html5 标签不支持一键投屏,需依赖chrome cast sdk、服务端转流(hls/webrtc)或dlna代理实现;所有方案均受https、网络环境及电视解码能力严格限制。

html5 <video></video> 标签本身不支持“一键投屏”
浏览器里的 <video></video> 元素只是播放器容器,它没有内置协议去发现电视、建立会话、推送流——这和手机 App 里点一下“投屏”就跳转到电视完全不同。
真正能触发投屏的,只有三类情况:
- 用户手动点 Chrome 浏览器右上角的
Cast按钮(投的是整个标签页或桌面,不是单个<video></video>) - 网页主动调用 Google Cast SDK(需 https + 用户已装 Cast 扩展 + 电视连着 Chromecast 设备)
- 电视端运行了你写的接收页(比如一个打开 HLS 地址的 webview,或接入 WebRTC Signaling 的页面)
所以别指望给 <video></video> 加个 castable 属性就能投——它根本不存在。
想让网页视频“可控地”投到电视,必须绕过浏览器限制做服务端转流
原始 RTSP、GB28181、海康/大华私有协议……这些都不能被 <video></video> 直接播,更别说投。所有“HTML5 播 RTSP”的方案,本质都是服务端先把流转成浏览器能吃的格式。
立即学习“前端免费学习笔记(深入)”;
落地最稳的两条路:
- HLS 方案:用
ffmpeg拉 RTSP,输出.m3u8+.ts,前端用hls.js播;再让电视浏览器直接访问这个 HLS 地址(前提是电视浏览器支持 MSE) - WebRTC 方案:用
Mediasoup或Janus接入 RTSP 源,前端通过RTCPeerConnection拉流;电视端也跑一个相同信令逻辑的轻量页,实现“两端直连”
注意:ffplay -i rtsp://xxx 能播 ≠ 前端能播;本地转流成功 ≠ 部署后可用——NAT、防火墙、UDP 被限、关键帧间隔太长(>5s),都会让电视端卡住或黑屏。
Chrome Cast API 不是万能钥匙,HTTPS 和扩展缺一不可
就算你照文档引入了 https://www.gstatic.com/cv/js/cast_sender.js,只要网页是 http:// 开头,cast.framework.CastContext.getInstance() 就会静默失败,控制台连错误都不报。
还有几个硬性前提:
- 用户电脑/手机必须已安装并启用 Google Cast 扩展(桌面)或系统级 Cast 功能(android/ios)
- 电视必须插着 Chromecast 设备,或为原生支持 Cast 的 Android TV / Google TV
-
cast.framework.RemotePlayer只能播公网可访问的 URL,不能播localhost或内网地址(除非你配了反向代理)
常见现象:按钮点了没反应、SESSION_STATE_CHANGED 事件一直不触发、控制台显示 Failed to load Resource: net::ERR_CONNECTION_REFUSED——八成是协议或网络问题,不是代码写错了。
别依赖“自动发现 DLNA”,浏览器根本不让你直接发 UPnP 请求
想用 JavaScript 直接 fetch('http://192.168.1.100:8080/upnp/control/ContentDirectory') 扫电视?不行。跨域限制(CORS)会立刻拦住你,而浏览器不允许前端绕过。
可行做法只有一种:
- 写个后端代理(比如 Node.js 的
express+node-upnp),由它去局域网发现 DLNA 设备、解析 xml、构造 SOAP 请求 - 前端只跟自己的后端通信,后端再把指令透传给电视的
AVTransport服务
但要注意:DLNA 不保证实时性,SetAVTransportURI 后调 Play 可能延迟 2–5 秒;且多数智能电视的 DLNA 实现很基础,不支持 H.264 High Profile、不认 B-frames、要求关键帧严格对齐——这些编码细节,比写 JS 更容易让投屏失败。
最常被忽略的一点:你以为在投视频,其实是在投一个 URL 地址;电视能不能解、解得对不对、要不要转码,完全取决于电视自身的解码能力,而不是你的网页写了什么。