尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

大华摄像头WEB页面播放方案:RTSP转HTTP-FLV + flv.js实战

大华摄像头WEB页面播放方案:RTSP转HTTP-FLV + flv.js实战 做Web可视化大屏、物联网管理平台或者安防系统的同学大概率都被同一个问题卡过手里明明有一台大华摄像头管理页面能看、手机App也能看但自己写的WEB页面集成它的时候就是怎么都出不来视频。哪怕只是想把一路画面嵌入到自己的后台里也要折腾好几天。这类问题不是简单“写写前端代码”能解决的它牵扯到视频协议、编码格式、浏览器限制、流媒体服务好几个层面任何一个环节不对页面就是黑的。这篇文章就以“WEB页面播放大华摄像头视频解决方案”为线索从最底层的原理讲起再到方案选型最后给一套可以直接照抄的落地步骤和排错清单。适合正在做监控大屏、设备巡检平台、园区可视化管理系统的开发者参考也适合刚接手这类需求、对视频流一知半解的Java或前端工程师。我把实际项目中踩过的坑、验证过的方案、以及最终稳定运行下来的配置都写在里面你照着做大概率能少走我当初绕过的弯路。1. 项目概述与问题本质1.1 为什么WEB页面直接播不成大华摄像头视频在说方案之前先得搞清楚问题的根源。大华摄像头和市面上多数安防摄像头一样默认提供的是RTSPReal Time Streaming Protocol实时流传输协议视频流。RTSP协议本身很成熟在安防行业几乎是事实标准监控录像机、解码器、平台软件都靠它拉流。但问题是浏览器原生不支持RTSP。早些年大家用IE浏览器观看监控靠的是ActiveX控件也就是ActiveX插件。大华官方也提供过这类插件安装后页面就能直接播放。但ActiveX是Windows时代的老技术Chrome和Firefox早就把它禁了新版Edge也不再支持。现在的WEB页面要想播放视频流主流方式是使用HTML5的video标签配合HLSHTTP Live Streaming或者HTTP-FLV这类协议。而RTSP和这些协议完全不是一个世界的所以第一步必须想清楚你的视频流要怎么从RTSP“变”成浏览器能吃的格式。编码格式也是一个大坑。大华新款摄像头默认视频编码经常是H.265也叫HEVCH.265压缩率高、画质好、带宽占用小这是好事。但浏览器对H.265的支持一直很保守除Safari外Chrome和Firefox基本不带H.265硬解。就算你把RTSP转成HTTP-FLV如果在编码层面不处理H.265前端照样黑屏。所以真正要解决的其实是两件事一是用流媒体服务把RTSP协议转为浏览器能支持的HTTP协议二是确认视频编码是H.264或同时转码成H.264。把这两个核心点想明白了剩下的就是具体落地选择。2. 方案选型在“省事”和“好用”之间找平衡2.1 常见方案横向对比目前业界从RTSP到WEB播放主要有这么几条路我把优缺点列一下方案延迟表现浏览器兼容开发/部署成本适用场景大华官方浏览器插件极低仅限IE或老版本Edge需手动安装低但用户体验差已有老旧系统、内部少数人使用RTSP转RTMP flv.js播放1~3秒Chrome、Firefox、Edge均支持中等需流媒体服务与FFmpeg局域网监控大屏、通用WEB集成RTSP转HLSm3u85~10秒全平台iOS/Android都友好较低FFmpeg可一推解千愁对实时性要求不高、跨端播放WebRTC0.2~0.5秒Chrome、Firefox原生支持高需要支持WebRTC的流媒体网关指挥调度、高实时性场景GB28181上联到视频平台中低配合平台播放端兼容好中高适合大规模平台海量设备统一接入、国标场景这里先说一个最偷懒但最常见的误区很多人一上来就去找“大华摄像头插件下载”想靠官方插件把问题解决。如果你们的内网环境是用IE内核的浏览器且可以接受每台电脑装插件那这条路确实最快。但现在的新项目基本都基于Chrome内核2020年之后我再也没在正式项目里推荐过这个方案。插件安装本身就容易引发兼容问题摄像头固件一旦升级插件经常失效更麻烦的是来历不明的插件下载渠道还容易引入安全风险这一点我在后面安全加固部分会详细讲。2.2 我的选型结论与理由如果让我给一个通用建议自用或中小型项目选“RTSP转RTMP flv.js播放”这套组合最稳。原因有三个第一延迟可以控制在1~3秒无论是看监控画面还是操作云台体感都够用第二兼容性极好只要浏览器支持MSEMedia Source Extensionsflv.js就能跑现在主流浏览器几乎都支持第三这套方案依赖的组件都是开源免费的FFmpeg负责拉流转推Nginx负责承载流媒体转发前端一个flv.js搞定播放四舍五入等于零成本。有人说为什么不用HLSHLS的延迟太高了默认配置下从摄像头画面发生到浏览器显示往往要5秒以上做监控还好但如果项目里还要配合设备状态联动或者做语音对讲这个延迟会非常难受。HLS最大的优势是苹果生态好如果你需要手机网页直接看那么HLS可以作为辅助备用但主播放通道我还是推荐HTTP-FLV。WebRTC虽然延迟最低但部署很重。你需要一个支持RTSP拉流并转WebRTC的流媒体服务常见的有ZLMediaKit、SRS配置相对复杂还要解决信令服务器、ICE穿透等一系列问题。为了一个单页面的监控播放有点杀鸡用牛刀。项目做到平台化、要接几十上百路摄像头的时候再上ZLMediaKit这类重型服务不迟。3. 实操RTSP转RTMP flv.js播放方案落地3.1 环境准备与需要部署的服务这套方案涉及三个角色摄像头提供RTSP流。流媒体服务接收RTSP流转成RTMP/HTTP-FLV后对外分发。我用的是Nginx配上nginx-rtmp-module模块或者直接用支持该模块的Docker镜像。前端页面通过flv.js拉取HTTP-FLV流并播放。先说摄像头准备。大华摄像头需要提前打开RTSP服务一般在WEB管理页面的“网络设置-集成协议”里能看到RTSP开关确认开启。账号密码要有拉流要用。摄像头的IP务必固定不要用DHCP动态获取不然摄像头IP一变你的推流地址全废排查起来非常费劲。然后是流媒体服务器。我这里以Linux服务器为例假设你有一台内网服务器装好了Docker我们直接用开源镜像把Nginx和RTMP模块跑起来比手动编译Nginx省太多时间。Docker部署命令大概是这样的docker run -d --name nginx-rtmp \ -p 1935:1935 \ -p 8088:80 \ -v /path/to/nginx.conf:/etc/nginx/nginx.conf \ --restartalways \ alfg/nginx-rtmp端口说明1935给RTMP推流用8088给HTTP-FLV播放用。nginx.conf的关键配置在rtmp块和http块的location上我给出一份足够用的配置样例。rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; wait_key on; } } } http { server { listen 8088; location /live { flv_live on; add_header Access-Control-Allow-Origin *; } } }注意里面给HTTP-FLV接口加了跨域头。否则前端JavaScript去拉流的时候浏览器会因为跨域直接拦下播放器报错让人摸不着头脑。这个坑我吃过当时排查了很久才发现是CORS问题写在这里先帮你避掉。3.2 大华摄像头RTSP地址分析与推流命令大华摄像头的RTSP地址格式和我们常见的海康有点区别很多第一次接触的人会在这里卡住。大华RTSP的标准格式是rtsp://用户名:密码摄像头IP:554/cam/realmonitor?channel1subtype0注意几个关键点channel代表通道号从1开始。单目摄像头就是channel1如果是球机、多目摄像机第二个通道是channel2。subtype代表码流类型subtype0是主码流清晰度高、分辨率大subtype1是子码流分辨率低、带宽小。做多路预览时建议页面用子码流单路全屏细节查看时用主码流。实际地址示例rtsp://admin:yourpassword192.168.1.100:554/cam/realmonitor?channel1subtype0拿到地址后千万别急着写代码先在电脑上用VLC验证一下这个地址能不能出画面。我个人的习惯是所有摄像头接入都先用VLC拉一遍RTSPVLC能出画面说明摄像头侧没问题问题大概率在转流或前端VLC都出不来先去查网络、账号、端口而不是一头扎进代码里调。这个习惯帮我省了很多无用功。验证通过后用FFmpeg把RTSP流转推给Nginx的RTMP服务。推流命令如下ffmpeg -rtsp_transport tcp \ -i rtsp://admin:yourpassword192.168.1.100:554/cam/realmonitor?channel1subtype0 \ -c:v copy \ -c:a aac \ -f flv rtmp://127.0.0.1:1935/live/camera1这里参数逐个解释一下-rtsp_transport tcp强制RTSP走TCP传输。默认情况下FFmpeg可能用UDP但UDP在弱网环境或跨路由拉流时容易丢包花屏TCP稳定得多。如果摄像头在另一层网络里中间有TCP端口限制TCP还有机会过防火墙。-c:v copy表示视频编码不转码直接复制。前提是摄像头输出的是H.264编码这是最省CPU的模式一路1080P的流CPU占用率几乎可以忽略。-f flv把输出封装成FLV格式推给RTMP服务。rtmp://127.0.0.1:1935/live/camera1是推流地址其中camera1是流名称WEB端拉流时要和它保持一致。但这里有个大前提-c:v copy只有在你确认摄像头主码流是H.264时才成立。大华很多新款摄像头默认是H.265如果强用copy推流前面说过浏览器播放端会黑屏。遇到这种设备要么到摄像头WEB管理端手动把视频编码改成H.264要么推流时加转码参数ffmpeg -rtsp_transport tcp \ -i rtsp://admin:yourpassword192.168.1.100:554/cam/realmonitor?channel1subtype1 \ -c:v libx264 -preset veryfast -tune zerolatency \ -c:a aac \ -f flv rtmp://127.0.0.1:1935/live/camera1-preset veryfast用牺牲一点压缩率的代价换取更快的编码速度-tune zerolatency则是专门为流媒体直播场景设计的能显著降低编码引入的延迟。这里再次提醒如果是刚接触大华设备的朋友先检查编码再决定用copy还是转码别等到页面黑屏了才回头查。3.3 WEB前端播放页面实现流媒体服务跑起来了推流进程也稳定运行了最后一步是前端页面。前端用flv.js播放HTTP-FLV流核心代码其实很短。!DOCTYPE html html head meta charsetUTF-8 title大华摄像头WEB播放/title script srchttps://cdn.jsdelivr.net/npm/flv.js/dist/flv.min.js/script /head body video idvideoElement controls autoplay muted stylewidth: 720px; height: 480px;/video script if (flvjs.isSupported()) { var videoElement document.getElementById(videoElement); var flvPlayer flvjs.createPlayer({ type: flv, url: http://你的服务器IP:8088/live/camera1.flv, isLive: true }, { enableStashBuffer: false, lazyLoad: false }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play(); } /script /body /html有个细节要特别说明播放地址里为什么是camera1.flv而不是camera1nginx-rtmp模块的flv_live on开启后访问规则就是/live/流名称.flv。也就是说推流名称定义的是camera1播放地址就对应camera1.flv。对应关系别搞混。enableStashBuffer: false这个参数值得单独说一嘴。flv.js默认会在内存里缓存视频数据可能导致正在播放的画面比实时画面晚几秒。把stash buffer关掉后播放延迟会明显下降。实测下来在局域网环境下画面延迟基本能控制在1~2秒肉眼感知很轻微。如果摄像头带音频并且推流时用了-c:a aac转音频编码前端给video标签加muted属性往往比去掉更省心因为浏览器默认阻止带声音的视频自动播放这是产品的自动播放策略。你要允许用户听到声音就做一个点击触发播放的交互按钮而不是依赖autoplay。4. 真实环境中的坑与排查记录4.1 摄像头鉴权与客户端占用问题在实际项目中我最常遇到的第一类问题就是拉流鉴权失败。大华的RTSP地址里直接带账号密码是常规操作但很多系统管理员会给摄像头配一个“弱密码校验”或“非法登录锁定”策略连续输错几次密码后摄像头会临时锁定IP一段时间。页面里就很容易出现类似DSh Web authentication required; reopen the URL printed by DSh Web.这样的提示。遇到这个提示不要慌它的本质就是RTSP连接被拒绝原因基本是账号密码错误、或密码里带了特殊字符却没有做URL编码。比如密码里含有、#、:这类字符在RTSP地址里会被解析成账号密码分隔符或地址分隔符必须用URL编码替换。:换成%3A换成%40#换成%23。这个细节很容易被忽略但在对接大华摄像头时尤为常见。第二个大坑是多播会话超限。大华摄像头同一路RTSP流同时能被拉取的连接数是有限的默认情况下一路主码流只允许几个客户端同时访问。如果你们有多套系统都在拉同一路流比如监控平台拉一次、你自己写的FFmpeg又拉一次、运维同事做测试又拉一次摄像头会拒绝后续的新会话。遇到的现象就是最开始推流是好的跑上十分钟画面突然变黑VLC单独拉同一个地址没有任何反应重启摄像头后恢复过一会儿又不行。这类问题的解决思路不是去硬件上调大并发而是在流媒体层做“拉流复用”。让FFmpeg这一层成为唯一直接连接摄像头的客户端所有WEB端播放都从Nginx这里走而不要每个播放页面都直接去连摄像头。前面给的架构本质上也遵循了这个原则直连摄像头的是FFmpeg进程播放器连的是Nginx摄像头只面对一个客户端并发压力全部由Nginx消化。4.2 H.265编码导致的播放黑屏大华新款枪机、半球机如果供货日期比较新默认编码十有八九是H.265。你兴冲冲配好了Nginx和FFmpegVLC验证RTSP地址也能出画面前端页面却一直黑屏控制台里还不报错或者说有buffer但没有frames。这时候先去排查编码。在FFmpeg推流日志里你可以看到类似这样的信息Stream #0:0: Video: h264 (High)如果是h264说明这一路源流本身就是H.264可以放心用copy。如果看到的是hevc那就是H.265必须转码。前面给出了转码命令这里不再重复只补充一个参数细节-c:v libx264之前的输入参数一定要加-rtsp_transport tcp否则FFmpeg默认用UDP拉流在H.265转H.264这种高码率场景下UDP丢包会引发花屏或绿屏排查起来比黑屏更让人头疼。也有人问能不能用GPU加速转码减少CPU压力。可以-hwaccel cuda -c:v h264_nvenc在NVIDIA显卡上能大幅降低CPU占用。但牵扯到驱动和驱动版本兼容问题初期建议先用CPU转码跑通流程等确认稳定了再考虑优化。4.3 Web播放器报错与浏览器兼容问题前端播放还有一个容易被环境坑到的问题could not register service worker。这个报错通常出现在页面使用了HLS.js或flv.js且开启了一些高级特性时比如某些播放器会尝试注册Service Worker来拦截网络请求做缓存。浏览器对Service Worker有安全上下文要求如果用http://192.168.x.x这种局域网IP访问页面某些浏览器会限制Service Worker注册导致播放器初始化失败。处理的思路有两种一是放弃依赖Service Workerflv.js本身不依赖它如果你遇到的播放器是其他套壳组件换成原生flv.js即可二是如果必须用某些需要Service Worker的组件那就给页面配置HTTPS证书小程序或企业后台一般都有现成的证书资源内部系统也可以用自签名证书但要注意每台访问电脑都要信任该证书否则浏览器依然不认。另一个浏览器兼容问题是MSE支持性。flv.js依赖MSE播放FLV流理论上Chrome、Firefox、Edge都支持但部分国产浏览器或老旧内核浏览器可能不支持。前端代码里用flvjs.isSupported()做判断是最稳妥的如果不支持就回退到HLS播放或者直接提示用户更换Chrome内核浏览器。实际项目里我见过不少单位内部还在用老版Windows系统自带的老Edge这类环境几乎无解只能升级浏览器。4.4 播放延迟累增问题用FFmpeg拉流推流配合Nginx转发在长时间播放时会出现一个隐性Bug延迟会随时间慢慢累积。一开始播放延迟只有2秒挂了一个晚上第二天再看延迟可能涨到半分钟甚至更多。这是因为播放器的缓存机制和网络抖动不断把数据缓冲到本地但播放速度却跟不上数据到达的速度。缓解这个问题的办法有三层第一在flv.js初始化参数里关闭stash buffer上面已经写过第二在页面加一个“低延迟模式”开关切到该模式时重新创建播放器有意丢包把播放时间戳拉到直播边缘第三在FFmpeg推流命令中给输出增加-flvflags no_duration_filesize参数避免FLV封装时人为增加缓存阈值。我记得有一次客户现场反馈画面“卡卡的不实时”排查下来就是这个问题三层一起调整之后延迟稳定压在了1.5秒左右体感完全可接受。5. 扩展更稳的线上部署建议5.1 从单路演示到多路并发的改造思路如果你的项目只是临时看一两路画面以上这套架构完全够用。但要接入多路摄像头比如8路、16路就需要做一些改造。第一不要一个摄像头对应一个FFmpeg命令行进程挂在终端里用进程管理工具统一管理。Linux下推荐systemd给每个推流任务写一个unit文件设置Restartalways断线自动重拉也可以用Supervisor统一管理多个FFmpeg进程界面化管理更直观。Windows服务器就用计划任务或者NSSM把FFmpeg注册成服务。总之别手动开窗口挂关一次窗口推流就没了现场很尴尬。第二如果有更高并发的需求比如几十路摄像头的平台接入Nginx-rtmp就力不从心了。这时可以换成ZLMediaKit或SRS它们对RTSP、RTMP、HTTP-FLV、HLS、WebRTC都有完整支持API更丰富还能接入GB28181国标设备。迁移成本也不高前端播放的HTTP-FLV地址格式差距不大。第三多路推流时的带宽规划要提前想清楚。一路1080P主码流的码率通常在4~8Mbps转成H.264后码率可能更高。如果你在同一个内网里拉8路主码流瞬间就要占用几十兆带宽对交换机和服务器网卡都有压力。我的习惯是预览场景统一拉子码流分辨率以流畅为主单路解码成本低只在用户主动点开某一画面查看细节时才切换成主码流。这个策略在真实项目里能明显降低整套系统的资源占用。5.2 安全加固要点现在聊一下安全。之前热词里提到了“大华摄像头漏洞”其实不只是大华所有安防设备暴露在互联网上都存在被攻击的可能。除非有明确的远程访问需求否则摄像头管理端口和拉流端口不要直接暴露在公网应该放在内网通过堡垒机或应用网关访问。在日常运维中我会做几件基础的事一是修改摄像头的默认密码密码复杂度要够并且定期更换二是限制RTSP协议的访问来源IP如果流媒体服务器IP固定就在防火墙上只放行这个IP访问554端口三是摄像头固件有官方安全更新时先在测试环境验证再安排到生产环境升级四是谨慎下载各类“插件”这一类来路不明的安装包是安全风险的重灾区能不用就不用。回到WEB播放这个场景如果你们的平台需要给外部用户提供监控画面不要公开暴露Nginx的HTTP-FLV端口。更合理的做法是通过后端API做鉴权前端拿到临时有效的播放地址后再通过Nginx的secure_link模块或访问控制判断是否放行。这一步做完至少能挡住绝大多数未经授权的拉流请求。如果你们正在用Nginx部署多个Web项目也可以把视频播放服务统一收敛在同一个Nginx下做好location级别的转发和鉴权而不是每个项目各自开一个裸端口。5.3 与既有业务系统的集成建议最后再聊聊和业务系统怎么配合。这套播放方案本质上是把“视频能力”做成了一个可以嵌入任意页面的组件。我在实际项目中习惯用一个独立的CameraPlayer.vue组件如果是Vue技术栈把播放器封装起来接收摄像头ID、清晰度、自动播放这些参数内部去请求后端拿推流地址拿到地址后创建播放器实例组件销毁时同步释放播放器。这样的好处是页面里不管有多少个摄像头卡片每个卡片只需传入摄像头ID就能独立播放后端统一管理“哪些摄像头允许谁看”的权限关系。配电工艺图、设备巡检页面、安防一张图都能复用这一套能力不需要每个模块重新写一遍流媒体逻辑。前端代码在销毁播放器时记得调用flvPlayer.destroy()不释放资源的话页面频繁切换会造成内存持续上涨直到标签页崩溃。这个细节我在做多路预览时踩得很深后来对所有播放器实例做了统一回收内存曲线才稳定下来。6. 一些想分享的经验小结做WEB页面播放大华摄像头这件事本质上不是某一种技术的单一问题而是视频协议、编码、服务部署、前端播放器四个环节需要打通。我见过很多人卡在某一步就来回试实际上只要把链路梳理清楚它就是一个标准的“拉流—转流—播放”模型。我个人实际干活时的顺序是固定的先拿VLC验证摄像头RTSP地址再独立测试FFmpeg推流是否成功然后用ffprobe检查输出流的编码格式最后才写前端页面。每次新到项目现场我都坚持这个顺序排查效率非常高。如果地址VLC能弹画面FFmpeg能推出流但页面黑屏问题基本已经被压缩到前端播放器或编码层这两处了。另外架构上宁可在一开始多花一点时间把推流做成独立服务也不要图省事在业务代码里捆绑FFmpeg进程。这样后续无论接多少路摄像头业务层都不需要跟着改流媒体这一层也方便独立升级维护。这个决定后续会让你省下大把时间。
返回列表