首页 / 资讯中心 / 文章详情

网页嵌入flowplayer播放RTMP流:Red5推流与低延迟直播实践

网页嵌入flowplayer播放RTMP流:Red5推流与低延迟直播实践 ★ FEATURED ARTICLE
简介在网页中内嵌流媒体播放器flowplayer是一套成熟的轻量方案适合需要播放FLV、MP4等格式视频的Web开发人员尤其是使用Red5作为流媒体服务器的场景。整套资源压缩后仅201KB共8个文件其中3个SWF分别对应播放器核心、RTMP插件与控制条1个JavaScript脚本负责初始化播放器和传入视频源1个HTML示例页面展示最基本的嵌入方式1个CSS样式文件用于调整播放器外观另外2个说明文档补充了Red5地址配置和使用注意事项。已有654人学习或下载。通过该资源能够快速理解flowplayer 3.2.13的嵌入流程、RTMP参数配置和播放器样式调整方法拿到示例后稍作修改即可集成到自有项目中由于包内同时提供了HTML、JS、CSS和播放器组件开发人员可以对照完成前端页面搭建无需再分别搜索分散资料节省从零阅读官方文档和反复验证的时间整体方案已在Red5环境中测试通过。1. 网页里跑通RTMP流web嵌入flowplayer这件事到底难在哪事情得从我维护过的某个内部培训系统说起甲方要求网页端打开就能看摄像头直播延迟不能超过两秒HLS试了几次切片缓冲加播放器累计卡到五秒起步当场被否决。最后选型落到 web嵌入flowplayer流媒体播放器配合Red5收流分发。这套方案听起来老却是局域网直播、老监控平台、课件点播场景里最能在浏览器里直接出画面的路子。它解决的核心问题是HTML5 video不认RTMP本质是Flash 的 NetStream 替你把 RTMP 协议翻译成画面渲染。适合正在维护老系统、不想上全套RTC、只想在页面里把RTMP流稳定放出来的开发者。2. RTMP链路的分工Red5在左、flowplayer在右、Flash在中间2.1 为什么RTMP能压住延迟先看协议再谈选型RTMP 的低延迟来自它的传输方式。它是一条 TCP 长连接客户端先 connect 到服务器再 play 一个流名之后服务器把 FLV 格式的数据分块持续推过来。播放端拿到带时间戳的视频 tag 后可以直接解码渲染不需要像 HLS 那样等上几秒的 TS 切片对齐。延迟通常能控制在 1 到 3 秒这正好卡在监控、内部直播课、视频对讲这类场景的需求线上。HLS 慢是因为它把视频切成一个个小文件播放器得先下载 m3u8 索引再按片段拉流分片长度普遍在 3 到 10 秒网络一抖累计延迟就直接到十几秒。做点播和公网泛直播没问题做双向对讲就不行。对比项RTMPHLS端到端延迟1 到 3 秒5 到 15 秒首屏时间快connect play 即出画面慢要等第一个切片下载完播放端要求Flash 插件或支持 RTMP 的播放器HTML5 video 原生或 hls.js部署复杂度需要流媒体服务端只要能切分片静态服务就行适用场景低延迟直播、监控、内部系统点播、泛直播、移动端兼容所以你会发现这套方案在 2024 年依然能被翻出来用不是因为它新而是它确实解决了低延迟播放这个具体问题。代价是播放器要挂在 Flash 上而 Flash 在现代浏览器里默认被禁。后面我会专门讲怎么绕过这个坑。2.2 Red5端准备把推上来的流先收下Red5 是服务端负责接收编码器推上来的 RTMP 流再分发给所有请求播放的客户端。它跑在 Java 环境里解压后进目录直接启动cd /opt/red5 ./red5.sh启动后观察日志看到类似“RTMP server started”的信息说明 1935 端口已经起来了。默认 RTMP 端口是 1935HTTP 管理端口是 5080。防火墙要放行sudo ufw allow 1935/tcp然后用 ffmpeg 推一路测试流。我用一个本地视频文件模拟摄像头信号ffmpeg -re -i camera.mp4 \ -c:v libx264 -preset veryfast -tune zerolatency -g 30 \ -c:a aac -b:a 96k \ -f flv rtmp://127.0.0.1:1935/live/stream1参数说明-re按真实时间读取输入文件模拟实时推流-tune zerolatency让 x264 以最低延迟为目标编码不引入额外缓冲-g 30控制关键帧间隔为 30 帧也就是 1 秒一个关键帧这对播放器秒开很重要。-f flv是把编码后的数据打包成 FLV 通过 RTMP 推出去。验证服务端没问题用 ffplay 直接拉流看ffplay -fflags nobuffer -flags low_delay rtmp://127.0.0.1:1935/live/stream1-fflags nobuffer和-flags low_delay是播放端低延迟的常见组合能真实反映服务端的延迟状况。如果这一步能出画面问题就全在播放器侧了。Red5 的默认应用目录是webapps/live推流地址里最后一段stream1叫 stream name是你自己取的流名和应用名live无关。connect 阶段连的是rtmp://ip:1935/liveplay 阶段播放的是stream1。这两个概念后面嵌入 flowplayer 时非常关键。2.3 flowplayer的嵌入结构一个容器、两层配置、三件套flowplayer 的工作方式是在页面里放一个带尺寸的 div 容器然后调用flowplayer(player, swf路径, 配置对象)把播放器 SWF 嵌进这个容器。配置对象里最核心的是 clip 和 plugins 两段clip 描述播什么plugins 里告诉播放器用哪个协议插件去拉流。flowplayer(player, /static/flowplayer/flowplayer.swf, { clip: { url: stream1, autoPlay: true, live: true, provider: rtmp }, plugins: { rtmp: { url: /static/flowplayer/flowplayer.rtmp.swf, netConnectionUrl: rtmp://192.168.10.20:1935/live } } });这里的写法是新手最容易抄错的clip.url只填 stream name不带协议不带 ipnetConnectionUrl才填服务器连接地址。原因在于 RTMP 播放分两步——先 NetConnection.connect 到rtmp://ip:1935/live建立会话再 NetStream.play 播放stream1。如果你把完整地址rtmp://ip:1935/live/stream1填到clip.url同时又在netConnectionUrl里填了服务器地址Flash 会把地址重复拼接轻则多一次无效连接重则直接失败。flowplayer 本身经历过多次版本迭代不同版本的 API 细节有差异这一点几乎是所有接手老项目的人都会踩的坑。我一般会把 swf 文件固定放在一个静态目录里用相对路径引用不写死版本号升级时只换文件不改配置这样页面代码能跨版本存活。3. 一套能直接抄的嵌入代码单路直播、多路切换与误用对照3.1 最小嵌入页面15行代码放一个RTMP直播流下面是一个可以直接放到静态服务器里跑的完整页面。前提是你的 Red5 已经按上一章的方式推了一路stream1流并且页面和 SWF 文件在同一个域下。!doctype html html head meta charsetutf-8 titleflowplayer rtmp直播demo/title script src/static/flowplayer/flowplayer.min.js/script link relstylesheet href/static/flowplayer/skin/minimalist.css /head body div idplayer stylewidth:640px;height:360px;/div script flowplayer(player, /static/flowplayer/flowplayer.swf, { clip: { url: stream1, autoPlay: true, live: true, provider: rtmp }, plugins: { rtmp: { url: /static/flowplayer/flowplayer.rtmp.swf, netConnectionUrl: rtmp://192.168.10.20:1935/live } } }); /script /body /html几个关键点说清楚容器div#player必须有明确的宽高flowplayer 初始化时会把这个 div 变成 SWF 的宿主没有尺寸的容器会导致播放器黑屏。flowplayer.min.js负责解析配置并创建播放器实例。flowplayer.rtmp.swf是 RTMP 插件它负责建立 NetConnection 和 NetStream没有这个插件RTMP 流是放不出来的。clip.autoPlay决定页面加载后是否立即拉流live: true告诉播放器这是一路直播流不要启用点播的 seek 和进度条逻辑。3.2 多路画面切换用playlist管理四路监控如果把单路的 URL 改成playlist数组就能用同一容器管理多路流。我在一个模拟监控项目里放过四路摄像头代码是这样组织的flowplayer(player, /static/flowplayer/flowplayer.swf, { playlist: [ { url: cam1, netConnectionUrl: rtmp://192.168.10.20:1935/live }, { url: cam2, netConnectionUrl: rtmp://192.168.10.20:1935/live }, { url: cam3, netConnectionUrl: rtmp://192.168.10.20:1935/live }, { url: cam4, netConnectionUrl: rtmp://192.168.10.20:1935/live } ], clip: { autoPlay: true, live: true, provider: rtmp }, plugins: { rtmp: { url: /static/flowplayer/flowplayer.rtmp.swf } }, listType: playlist });切换流时调用播放器实例的方法var api flowplayer(player); function switchCamera(index) { api.play(index); } api.bind(load, function(e, api, video) { console.log(当前流 video.url); });注意 playlist 模式下每一路 clip 都可以单独带netConnectionUrl这保证了切换到不同服务器时不会串地址。api.play(index)按数组下标切换下标从 0 开始绑定load事件可以在换台时更新页面上的摄像头名称。直播流不要开启循环播放直播不存在“播完”的概念循环会让播放器在流结束时走一遍 finish 逻辑反而容易卡住。3.3 黑屏误用对照三种最常写错的用法我在排查别人代码时发现 RTMP 播放黑屏绝大多数不是环境问题而是配置写错。最常见的三种第一种是把完整地址填进clip.url同时netConnectionUrl也配了同样的地址。现象是控制台能看到连接发起但随后立刻断开或者一直停在“正在连接”状态。原因是 Flash 会对地址做二次拼接。解决方法是二选一要么clip.url只写 stream name要么直接把完整地址写进clip.url并删除netConnectionUrl。推荐前者。第二种是拿 HLS 地址喂给 RTMP 插件。比如某开发者把xxx.m3u8填进了 clip.urlprovider 还是 rtmp。现象是黑屏且基本没有报错因为 Flash 尝试用 RTMP 协议去解析一个 HTTP 地址协议握手直接失败。解决方法是把 provider 改成支持 HLS 的插件或者走 HTML5 video。第三种是把 HTTP 播放地址当 RTMP 地址比如填http://ip/live/stream1.flv。现象是播放器一直转圈偶发报 NetStream.connect 失败。判断方法很简单看地址前缀只有rtmp://、rtmpt://、rtmps://这个协议族才能交给 RTMP 插件。这些误用的共性在于都是没把 flowplayer 的 NetConnection 和 NetStream 两层结构理清楚就动手写配置。宁可先用单路流验证通了再上多路。4. 缓冲参数与前端配合把直播画面从“能放”调到“不卡”4.1 bufferLength与bufferLimit直播卡顿的临界点怎么找播放器能出画面之后下一个问题就是卡不卡。RTMP 直播的卡顿通常不是编码问题而是缓冲策略不对。播放器的缓冲设太大延迟会慢慢累积设太小网络一抖动就频繁断流缓冲。参数默认值作用直播场景建议clip.bufferLength1 秒播放器预缓冲的视频时间直播 0.3 到 0.6 秒点播 2 到 4 秒clip.livefalse是否按直播流处理truertmp.netConnectionUrl无服务器连接地址写rtmp://ip:1935/livereconnect.retries无断流后重试次数5 到 10 次reconnect.interval无重试间隔毫秒数3000 到 5000bufferLength 调大的效果是画面停止时的缓冲时长变长能抗住短时网络抖动但代价是延迟增加。直播场景里我一般从 0.5 秒起调观察 10 分钟内的画面停顿次数和延迟增长幅度。如果频繁缓冲先别急着加缓冲回头查推流端的-g参数——关键帧间隔太长会让播放端在丢包后等很久才能恢复画面。-g 30是最常用的值对应 1 秒一个关键帧。还有个容易忽略的点bufferLength是播放器侧缓冲服务端 Red5 也有自己的缓冲队列。两端缓冲叠加才是真实延迟。调参时要在客户端开一个时钟对比画面和实际时间确定延迟可接受范围后再定参数。4.2 断流重连reconnect插件和它的退避策略直播流断掉再恢复播放器不会被自动拉起来这是 Reconnect 插件存在的意义。配置如下flowplayer(player, /static/flowplayer/flowplayer.swf, { clip: { url: stream1, live: true, autoPlay: true, provider: rtmp }, plugins: { rtmp: { url: /static/flowplayer/flowplayer.rtmp.swf, netConnectionUrl: rtmp://192.168.10.20:1935/live }, reconnect: { url: /static/flowplayer/flowplayer.reconnect.js, retries: 5, interval: 3000, transition: 800 } } });retries是最大重连次数interval是两次重连之间的间隔毫秒数transition是重连过程中的过渡动画时长。注意重连对直播流的语义不是“回到刚才的位置继续播”而是重新执行 connect 和 play。所以直播重连后画面会短暂卡一下这是正常的。这个参数不能开太大。某次生产事故里把 retries 配了 99推流端断了一个钟头客户端就在那反复重连把 Red5 的连接线程全占满了连正常的播放请求都被拖死。重连次数够覆盖一次短暂的网络切换就行剩下的事交给上层监控去处理。4.3 让页面知道播放器的状态事件与状态上报播放器本身是个黑匣子但 flowplayer 会把生命周期事件暴露给页面。不同版本的绑定写法略有差异我按常见版本的bind写法来逻辑是通用的var api flowplayer(player); api.bind(load, function(e, api, video) { setStatus(拉流成功 video.url); }); api.bind(pause, function() { setStatus(暂停); }); api.bind(finish, function() { setStatus(流结束); }); api.bind(error, function(e, api, err) { setStatus(播放错误 err.code err.message); });load事件在流真正开始加载时触发pause是用户手动暂停或缓冲中断时触发finish对直播流来说一般不会触发error携带错误码和信息是最有用的排错入口。我习惯把状态同步到页面上的状态灯同时每 30 秒向后台发一次心跳内容包含当前播放地址和最后一张画面的时间戳。这样运维不用打开浏览器就能知道哪台客户端断了流。前端状态上报是低成本的事但能省掉大量在群里问“你们那边画面卡不卡”的时间。5. 避坑清单flowplayer生产环境常见的六个坑5.1 浏览器默认禁Flash播放器直接黑屏现象页面加载完播放器区域是空的或者白底控制台提示 Flash 插件被禁用有些环境连提示都没有只看到 div 里嵌了个空白对象。原因Chrome、Edge 从 2020 年起默认阻止 Flash 内容运行企业内网如果没有做策略放行SWF 就是一团空白。解决如果是内网系统在浏览器策略里把页面域名加入 Flash 运行白名单如果用户环境不可控就按第 6 章的方案自动降级 HLS。最忌讳的是在页面里放“请点击允许运行 Flash”的提示用户根本找不到在哪里点。5.2 页面是HTTPS、流是HTTP插件被混合内容拦截现象页面用 HTTPS 打开播放器加载不了 SWF控制台报 Mixed Content 错误说页面是 HTTPS 的还请求了不安全的插件。原因浏览器不允许安全页面里加载明文 HTTP 资源SWF 和 RTMP 地址都会被拦。解决内网系统最简单就是把页面也改成 HTTP如果页面必须 HTTPS那 SWF 必须从 HTTPS 域名加载RTMP 地址要用rtmps://走 SSL。很多老项目的坑在于页面上了 HTTPSSWF 还留在 HTTP 静态目录里这种混合配置在 IE 里能跑在 Chrome 里直接废。5.3 RTMP端口通了流却出不来跨域策略文件漏配现象端口连通性测试没问题ffplay 拉流也正常但 flowplayer 播放器一直报 SecurityError 或者 NetStream.Connect.Failed。原因Flash 的 NetConnection 做跨域安全检查时会尝试从目标服务器的 HTTP 端口获取crossdomain.xml。Red5 默认虽然会生成一个但如果你改了应用目录或者部署方式文件经常不在正确位置。解决在 Red5 的 HTTP 根目录下放一个策略文件内容如下?xml version1.0? cross-domain-policy allow-access-from domain* / /cross-domain-policy把文件放到 Red5 HTTP 服务根目录对应 5080 端口的 ROOT 目录然后用 curl 验证curl http://192.168.10.20:5080/crossdomain.xml能看到 XML 内容才算生效。生产环境如果安全要求高可以把domain从*收紧成播放页面的域名但别收太狠不然排查跨域问题时会以为是网络问题。5.4 公网映射的玄学NAT回环让内网用户连不上现象播放地址填的是公网域名rtmp://pub.example:1935/live公网用户能放内网用户反而连不上一直转圈。原因多数路由器的 NAT 不支持回环内网设备访问公网 IP 时流量到不了内网服务器。解决前端页面加载时判断访问来源内网访问就自动替换成内网地址if (location.hostname.indexOf(internal.example) -1) { streamBase rtmp://10.0.0.5:1935/live; } else { streamBase rtmp://pub.example:1935/live; }这个坑我第一次遇到时排查了整整一下午抓包都抓不出问题最后发现是路由器的回环问题。记住一句话内网用户用内网地址公网用户用公网地址别让播放器自己猜。5.5 流在半夜断掉播放器停在倔强不重连现象推流端凌晨出了故障恢复之后画面一直没有回来播放器停在最后一片静止画面第二天上班才发现。原因默认配置下直播流断开后播放器不会自动重建连接它以为只是网络间歇性抖动。解决按照 4.2 节配置 reconnect 插件同时再加一道保险——页面在外层做心跳检测连续几次发现播放器状态异常就整页 reload。生产系统别把宝全押在播放器上重连是播放器的职责恢复是上层页面的职责两层都要有。5.6 本地能放上线不能放swf路径与域名白名单现象本地打开的 HTML 文件能出画面部署到服务器上就黑屏单独访问 SWF 文件路径倒是 404。原因最常见的是 swf 用了绝对根路径/static/flowplayer/flowplayer.swf但服务器上根本没这个目录或者部署时把 SWF 文件漏传了。解决上线前先直接访问一遍三个资源播放页、SWF 文件、RTMP 插件文件确认都能返回 200。再看页面引用的是相对路径还是绝对路径统一用一个固定的静态资源目录不要散落到应用目录的不同层级。这一条看起来很低级但多数“本地能放线上不能放”都是这原因。6. Flash退役的降级路线自动切HLS 上线前强制检查单6.1 用一段代码判断当前浏览器还能不能跑Flash初始化之前先探测 Flash 是否可用不可用就切换播放策略function detectFlash() { if (window.ActiveXObject) { try { new ActiveXObject(ShockwaveFlash.ShockwaveFlash); return true; } catch (e) { return false; } } if (navigator.mimeTypes navigator.mimeTypes[application/x-shockwave-flash]) { return true; } return false; }6.2 同一个容器降级到HLSNginx切片与hls.js接管服务端在 Nginx 的 RTMP 模块里把同一路流切成 HLS配置里把分片压到 2 秒rtmp { server { listen 1935; application live { live on; hls on; hls_path /data/hls; hls_fragment 2s; hls_playlist_length 6s; } } }前端拿到 hls.js 后用同一个 video 容器接管if (Hls.isSupported()) { var video document.getElementById(player); var hls new Hls({ liveSyncDurationCount: 3, liveMaxLatencyDuration: 5 }); hls.loadSource(http://192.168.10.20:8080/hls/stream1.m3u8); hls.attachMedia(video); }6.3 上线前十分钟的检查单检查项动作期望RTMP 端口nc -vz 192.168.10.20 1935返回 openRed5 服务查看 Java 进程和日志无报错应用已加载跨域策略curl http://ip:5080/crossdomain.xml返回 XML 内容Flash 可用性目标浏览器访问播放页能出画面公网映射使用公网域名访问不黑屏、不断流断流恢复手动 kill ffmpeg 再重启播放器自动重连降级 HLS禁用 Flash 的浏览器访问自动切到 HLS 并出画面从那以后我每次上线这类流媒体项目都会强制把这张单子走一遍五分钟的事能少接到一半的半夜报障电话。Flash 终归是要退役的但老系统的替换不是一天能做完的先把降级路线打通再逐步迁移比一刀切来得稳。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站