如何在Next.js/React中使用Video.js播放RTSP直播流
核心前提
所有现代桌面/移动端浏览器都已原生移除RTSP协议支持,你直接把RTSP地址填入Video.js的sources配置永远无法正常播放。网上能搜到的大部分过时方案,要么依赖早已被淘汰的Flash插件,要么依赖已经被浏览器安全策略封禁的第三方NPAPI插件,在2024年之后的Chrome、Edge、Firefox版本里完全不可用。
最新可落地实现方案(适配Next.js全版本)
实现逻辑分两步,缺一不可:
1. 前置转码处理
RTSP流不能直接被前端拉取解析,必须先在服务端完成转码,转成浏览器原生支持的流格式,目前生产环境最常用的两种选型:
- HLS(m3u8)格式:延迟2-5秒,兼容性拉满,支持所有主流浏览器,是通用场景首选
- WebRTC格式:延迟低于500毫秒,适合互动直播、监控这类低延迟需求场景
转码完成后你会拿到http/https协议开头的可直接在浏览器访问的流地址,再传给前端播放器即可。
2. 修正你的Stream组件代码
你贴的原有代码存在三个会直接导致功能异常的问题:
- 没有处理Next.js的SSR逻辑,Video.js是纯浏览器端依赖,直接在服务端渲染阶段执行会报window不存在的错误
- useEffect没有传入依赖数组,每次组件重渲染都会重复初始化播放器实例,造成内存泄漏
- 没有在组件卸载时销毁播放器实例,会导致控制台持续报错、播放器DOM残留
修正后的可直接运行的代码如下:
// Next.js 13+ App Router 必须保留下面这行客户端组件标记,Pages Router可删掉 'use client'; import { useRef, useEffect } from "react"; import videojs from "video.js"; // 记得提前安装依赖:npm i video.js @videojs/http-streaming import "video.js/dist/video-js.css"; export default function Stream() { const videoRef = useRef(null); const playerRef = useRef(null); useEffect(() => { // 非浏览器环境、视频DOM未挂载、播放器已初始化时直接跳过 if (typeof window === "undefined" || !videoRef.current || playerRef.current) return; // 初始化播放器,注意这里要填转码后的流地址,不能填原始RTSP地址 playerRef.current = videojs(videoRef.current, { autoplay: true, muted: true, // 现代浏览器自动播放策略要求默认静音,否则会被拦截 controls: true, preload: "auto", sources: [ { src: "https://你的转码服务输出的HLS地址.m3u8", type: "application/x-mpegURL" // HLS流固定type,用WebRTC时替换为对应type即可 } ] }); // 组件卸载时彻底销毁播放器实例,避免内存泄漏 return () => { if (playerRef.current) { playerRef.current.dispose(); playerRef.current = null; } }; }, []); // 空依赖数组,保证初始化逻辑只执行一次 return ( <div data-vjs-player> <video ref={videoRef} className="video-js vjs-big-play-centered" /> </div> ); }
使用注意事项
- 组件直接按你原来的方式引入使用即可,不需要额外做动态导入
- 如果使用WebRTC低延迟流,额外安装Video.js对应的WebRTC播放插件即可,初始化逻辑和HLS完全一致,仅需替换src和type参数
- 如果转码服务和前端站点不同源,需要在转码服务端配置CORS跨域规则,否则会出现拉流失败的问题
- 不要尝试搜索任何“前端直接播放RTSP”的方案,这类方案目前全部无法在生产环境使用
注意:如果本地测试时出现播放异常,优先检查转码服务是否正常输出可访问的流地址、跨域配置是否正确、播放器type参数是否和流格式匹配。
内容的提问来源于stack exchange,提问作者YSLdev
相关产品推荐
相关产品推荐

