前言 项目上又遇到了播放rtsp、rtmp等原生流的需求,因为现在的浏览器早已抛弃flash,所以无法直接播放rtsp、rtmp这种格式的直播流,之前在某个项目上处理过,用的是后台调用ffmpeg转流,最终经过nginx处理转为m3u8格式让前端来播放,虽然最终能播放,但是实际延迟很大,开多了,服务器资源、带宽占用都非常大,不是一个好的解决方案,所以下面来说说另一个种可行的方案
原理
RTSP 流 -> WebSocket / WebRTC
WebSocket / WebRTC -> WebVideo
方案I - 基于 ffmpeg 的 Node 后端推流方案 + 基于 jspmeg / flvjs 的前端视频展示 后端部分:基于 ffmpeg 的 node 推流方案 这种方案应该是网上能搜索到的文章中最主流的方案,其中 Nodejs 部分可选择的包就有很多种:
上面几个包最后都能实现我们所要的效果,但是唯一都有一个前提条件:必须在系统里安装 FFMPEG ,因为 RTSP 流转 WebSocket 就是通过底层调用 FFMPEG 来实现的。因为这些包都是经过封装后的,所以使用起来非常的简单,我这里就以第一个 node-rtsp-stream 为例,来说一下如可启动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 js复制代码const Stream = require ('node-rtsp-stream' ); new Stream ({ name : 'socket' , streamUrl : 'rtsp://localhost:554/test' , wsPort : 9999 , ffmpegOptions : { '-stats' : '' , '-r' : 20 , '-s' : '1280 720' } });
你没有看错,就是这么简单,你只需要把你要接入的 RTSP 流地址填写进去即可,然后在前端你需要展示的就是转换过后的 WebSocket 地址,前端如何显示,在下方,耐心观看。
关于本地可测试的 RTSP 推流的创建过程,可以参考本文最后章节 其他 - 创建本地 RTSP 推流 。
前端部分 上面后端的部分真的可谓是非常简单,那么我们前端也不能落后,其实都是站在巨人的肩膀上前行,前面也提到了,我们的 video
大法在这种场景不好用了,因此我们就得考虑别的方案,调研一圈发现了两个比较成熟且验证过后比较靠谱的方案,笔者一一给大家介绍使用姿势。
jsmpeg.js 或 jsmpeg-player
这两个包是一样的,只不过如果你是原生 HTML 你就用 jsmpeg.js
,如果你用的 React/Vue 这种框架,你就用 jsmpeg-player
,因为现在大部分前端都是使用框架进行开发,所以笔者直接用 jsmpeg-player
进行演示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import React , { useEffect } from "react" ;import JSMpeg from "@cycjimmy/jsmpeg-player" ;export default function JsmpegPlayer ( ) { useEffect (() => { new JSMpeg .VideoElement ('#video' , 'ws://localhost:9999' ); }, []); return ( <div > <h1 > Jsmpeg Player</h1 > <div > <video id ="video" width ="640" height ="480" > </video > </div > </div > ); }
FLV 相关代码也是类似的,直接贴代码了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import React , { useEffect, useRef } from 'react' ;import flvjs from 'flv.js' ;export default function FlvPlayer ( ) { const flvRef = useRef (null ); useEffect (() => { const videoElement = document .getElementById ('videoElement' ); if (flvjs.isSupported ()) { const flvPlayer = flvjs.createPlayer ({ type : 'flv' , isLive : true , url : 'ws://localhost:9998' , }); flvPlayer.attachMediaElement (videoElement); flvPlayer.load (); flvRef.current = flvPlayer; } }, []); return ( <div > <h1 > Flv.js Player</h1 > <div style ={{ width: '100 %', display: 'flex ', justifyContent: 'center ', alignItems: 'center ' }}> <video id ="videoElement" controls > </video > <button onClick ={() => {flvRef?.current?.play()}}>Play</button > </div > </div > ); }
方案II - 基于 WebRTC 的推流方案(推荐) 基于 WebRTC 实现 RTSP 流的推送,需要优先下载 webrtc-streamer ,官方提供了各种系统各种版本的安装包,大家下载安装即可。
WebRTC Streamer 是用于 V4L2 捕获设备、RTSP源 和屏幕捕获的 WebRTC 流媒体。**关于这个东西底层原理,其实大家不需要了解,笔者也不知道。我们只需要知道它能捕获 RTSP 流在前端使用播放出来就可以了。
前端部分 前端代码看起来比较复杂,但是实际上都是复制粘贴,因为核心代码片段 WebRTC Streamer 官方已经给我们提供了足够多的基础组件,笔者在这里就以其中一个为例展示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 html复制代码<html > <head > <script type ="module" src ="./js/webrtc-streamer-element.js" > </script > <style > h2 { margin : 0 auto; text-align : center; } </style > </head > <body > <h2 id ="message" > </h2 > <webrtc-streamer id ="stream" options ="rtptransport=tcp&timeout=60&width=0&height=0&bitrate=0&rotation=0" style ="display:none" > </webrtc-streamer > <p id ="hint" > 默认从url连接上获取 video || audio 参数进行播放,本示例如果没有会选择本地 RTSP 推流</p > <p style ="color: red" > 【注意】:WebRTC 播放 RTSP 流需要前置启动 webrtc-streamer 客户端,否则推流无法播放</p > <script > let messageElement = document .getElementById ("message" ); customElements.whenDefined ('webrtc-streamer' ).then (() => { let streamElement = document .getElementById ("stream" ); var params = new URLSearchParams (location.search ); if (params.has ("options" )) { streamElement.setAttribute ('options' , params.get ("options" )); } let url = { video :params.get ("video" ) || 'rtsp://localhost:554/test' , }; streamElement.setAttribute ('url' , JSON .stringify (url)); streamElement.style .display = "block" }).catch ( (e ) => { messageElement.innerText = "webrtc-streamer webcomponent fails to initialize error:" + e }) </script > </body > </html >
更详细的代码已经存放到仓库,大家可以 clone 下来运行一下,需要注意的就是要想能看到正常播放视频,要满足两个条件:
必须启动 WebRTC Streamer
必须有一个可用的 RTSP 推流(关于本地可测试的 RTSP 推流的创建过程,可以参考本文最后章节 其他 - 创建本地 RTSP 推流 。)
结语 推荐使用方案2,因为我两种方案都测试过,方案1延迟较大,局域网内延迟大概在5秒左右,首次播放较慢!
方案2实测播放速度很快,首次播放无需等待,基本可以说无延迟!