Skip to content
Advertisement

浏览器根本不支持 RTMP:所谓“RTMP 在线播放器”到底在播什么

关于我

我是 EZ 在线工具网 的站长,这个站上的播放器和转换工具都是我们自己写的。下面要拆的 FLV/RTMP 在线播放器 就是其中之一,所以这不是转述别人的科普,是我们的代码。

结论先甩出来

浏览器里没有 RTMP 这个东西。不是兼容性差,是压根没有。

不信,打开控制台把这几个名字挨个敲一遍:

js
typeof fetch             // 'function'  HTTP/1.1、2、3 都走这条
typeof XMLHttpRequest    // 'function'  老接口,还活着
typeof WebSocket         // 'function'  ws:// wss://
typeof RTCPeerConnection // 'function'  WebRTC
typeof RTMPConnection    // 'undefined' ← 就这个

RTMP 是跑在 TCP 1935 端口上的长连接协议。浏览器不给你裸 TCP 的能力,也没打算给。所以“网页直连 RTMP”这句话,从技术上就不成立。

RTMP 是谁的东西

Adobe 定的,更早是 Macromedia。规范到 2009 年才公开,整套东西是三个部件咬在一起的:TCP 长连接、握手加 chunk 分片、再加一个能解析它的运行时,也就是 Flash Player。

后半截已经没了。Flash 在 2020 年底停止支持,2021 年起主流浏览器把插件通道全拆了。RTMP 唯一的宿主就这么消失。

那浏览器为什么不自己实现一个?划不来。等于往浏览器里塞一套私有协议栈:握手、chunk 流、AMF 序列化,还要兼容各家魔改过的实现。推流本来就是服务端的事,播流又有更省事的出路。

浏览器只开了三个口子

管道能装什么一般延迟烦人的地方
HTTP 分段拉HLS(TS 或 fMP4 分片)、DASH6-30 秒,LL-HLS 能压到 2-5 秒分片和缓冲定死的下限,砍不下去
HTTP 长连接流HTTP-FLV、HTTP-TS1-3 秒服务端得一直吐,中间挂个代理就可能开始攒数据
WebSocket自己定义的二进制协议看你写没有播放器生态,拆包全靠自己
WebRTCRTP/RTCP over SRTP0.2-1 秒信令、NAT 穿透、运维成本

表格里没有 RTMP,一行都没有。你在网页上看过的所有直播,底下都是这四条里的一条。

flv.js 不播 RTMP,它只换壳

B 站开源的 flv.js 被叫了很多年“网页 RTMP 播放器”,我们站也把它放在 RTMP 播放器里用。这个名字的误会太大了。

<video> 能直接吃的数据只有两种容器:ISO BMFF(就是 fMP4)和 WebM。TS 不行,FLV 也不行。视频标签不管你想喂什么,它只认这两个。

flv.js 干的是中间那层活:走 HTTP 把 FLV 字节流拉下来,按 FLV 的 Tag 结构拆开,抠出 H.264 的 NALU 和 AAC 音频帧,现场重封成 fMP4,最后通过 MSE 的 appendBuffer() 丢给 <video>

这活儿叫 transmux,转封装。不解码也不编码,只是把盒子换了一个。所以它 CPU 占用低得离谱,画质一点不掉,延迟也小。代价是输入端只认 HTTP-FLV,它没有能力自己去连 1935。

同一套“只换壳不重编码”的路子,我们在 M3U8 转 MP4 的拆解 里也走过一遍,那次换的是另一层壳。

名字里带 RTMP 的,其实就三类

真转协议的。 用户填 RTMP,后端用 FFmpeg 拉流转成 HLS 或 HTTP-FLV 再吐出来。延迟和服务器账单都堆在服务端,商业方案基本都这么干,也只有这样才能真的接住一个 rtmp:// 地址。

只吃 HTTP-FLV、名字里塞 RTMP 骗搜索的。 我们站属于这类。它不连 RTMP,只是顺手把 rtmp:// 猜成对应的 http-flv 地址。那为什么还叫 RTMP?因为大家搜的就是这个词,我改个名字等于把自己藏起来。这点我坦白。

浏览器插件和桌面客户端。 这类是真在跑 RTMP,但要装东西,跟“在线”没关系。

下次看到“免安装、在线、直接播 RTMP”的宣传,就问一句:协议在哪儿转的?答不上来的,多半是第二类。

把我们自己的代码拖出来看

播放器拿到 rtmp:// 开头的地址,走的是这么三行:

js
const url = new URL(rtmpUrl.replace('rtmp://', 'https://'));
url.pathname += '.flv';
return url.href;

赌的是服务端在同一台机器的 80/443 上也开了 HTTP-FLV,路径规则就是把流名加个 .flv。腾讯云、阿里云的直播域名都吃这套,代码里塞的那个示例地址就是这么来的。

这里有个坑必须说清楚:端口不会跟着改。 你填 rtmp://1.2.3.4:1935/live/demo,改写出来的是 https://1.2.3.4:1935/live/demo.flv。浏览器拿着 HTTPS 去敲 1935 端口,对面在那儿只会讲 RTMP,握手当场失败。更烦的是报错文案会让你以为是跨域,然后你花一晚上去查 CORS,最后发现是自己填错了地址。

两种正确填法:服务端确实在 443 上开了 HTTP-FLV,把端口去掉;不确定的话,直接填完整的 https://域名/live/xxx.flv,让它原样请求。

播不了的时候别猜。开 DevTools 的 Network 面板,看那条请求真实用的什么协议、什么端口、响应头写了什么。这一步能解决八成“播不了”。

参数为什么这么配

创建播放器时传的配置:

js
flvjs.createPlayer({
  type: 'flv', isLive: true, cors: true, withCredentials: false
}, {
  enableWorker: false,
  lazyLoad: true, lazyLoadMaxDuration: 3 * 60,
  liveBufferLatencyChasing: true,
  liveBufferLatencyMaxLatency: 2,
  liveBufferLatencyMinRemain: 1
})

liveBufferLatencyChasing: true 是低延迟那口气。播放器会盯着缓冲区里积压了多少,超过 liveBufferLatencyMaxLatency(设的 2 秒)就偷偷加速追帧,追到只剩 liveBufferLatencyMinRemain(1 秒)就收手。追太狠会卡,不追延迟就涨,延迟和流畅度就卡在这一对数字上。

lazyLoad 那两行是给点播型 FLV 兜的,lazyLoadMaxDuration: 180 意思是别一上来就把整个文件拉完,用户还没看到的位置没必要占带宽。

enableWorker: false 是我们踩出来的。转封装本身很轻,再开一个 worker 去搬数据,反而容易和主线程抢资源;页面上还有别的活在跑,直接放手在主线程更稳。

cors: truewithCredentials: false:允许跨域拉流,但不带 Cookie。这样服务端只要给个 Access-Control-Allow-Origin 就能播,不用去处理凭据模式下通配符不能用那堆麻烦。

面板上那个延迟读数不是我估的,是 flv.js 的 STATISTICS_INFO 事件报出来的 delay

延迟这数字,谁承诺谁心虚

上面表里的区间是典型值,不是协议保证值。同样一条流,换台服务器能差出三倍。真正说话算数的是这几个:

  • GOP 长度。2 秒一个关键帧,延迟就别想低于 2 秒。
  • 服务端缓冲策略。有的服务器为了抗抖动主动攒 3 秒再发,前端怎么追都追不回来。
  • 追帧阈值。就是上面那对 MaxLatencyMinRemain
  • 中间链路。CDN 或者反向代理有没有做二次缓冲,这条最容易被漏掉。

想拿到自己环境里的真实数字,办法很土:同一路流连播 5 分钟,每 10 秒记一次延迟读数,算平均值和最差值。别拿刚点开那一秒的数字当结论,那个数字永远很好看。

想自己搭一个能播的

三件事:

  1. OBS 推 rtmp://你的服务器/live/流名
  2. 服务端既收 RTMP,又吐 HTTP-FLV。nginx 得编译 nginx-http-flv-module,SRS 自带 http_remux
  3. 播放端填 http://你的服务器/live/流名.flv

卡人的永远是第 2 步。nginx 默认那套配置只收 RTMP,网页端一定播不了。从编译到跑通的全过程我们单独写过一篇——手把手搭建 Nginx-RTMP 流媒体服务器,重点就是那个“收流 + 输出”的双配置,只配一半必然白忙。

我们做不到的部分

  • iPhone 上基本别指望。iOS 的 Safari 长期没开 MSE,而 flv.js 整条链路都架在 MSE 上。iPhone 只能走原生 HLS 或者 WebRTC。iPadOS 有些版本反倒可以,所以别拿一台设备就下结论。
  • 跨域头是硬要求。flv.js 用 fetch 拉流,服务端得给 Access-Control-Allow-Origin。开了防盗链还要把来源域名加进白名单,不然控制台给你的那句报错会把你往坑里带。
  • 只认 FLV over HTTP。HEVC 封的 HTTP-FLV、或者别人自己拼的 MP4 流,它都吃不下。
  • 我们的工具不替你转协议。它就是纯浏览器端的播放器,服务端没开 HTTP-FLV,它也救不了你。这事在 隐私政策 里也写了:所有解析都在你自己的浏览器里跑,我们看不到你的流。

就这样

手上已经有 HTTP-FLV 或者 RTMP 原始地址的,直接丢进 FLV/RTMP 在线播放器,能出画面就说明服务端配对了。

播不出来、源站只有 HLS 的,换 M3U8 在线播放器,路更短。搞不清手里那个地址属于哪一类,先看 .m3u8 文件到底是什么,一分钟能判断出来。

至于浏览器直连 RTMP 这件事,等哪天它愿意把裸 TCP 的权限交出来再说。目前一点迹象都没有。


📌 相关文章

🚀 推荐阅读

Last updated:

Advertisement