概述
这里记录一下如何让前端播放rtsp协议的视频流
项目中调用海康API,生成的视频流(hls、ws、rtmp等)通过PotPlayer播放器都无法播放,说明视频流有问题,唯独rtsp视频流可以播放。
但是浏览器本身是无法播放rtsp视频的,即使是使用videojs、flvjs等工具。
网上的方案都是通过后端基于ffmpeg工具进行转码。那么我的理解是后端Node起到的是中转作用:调用ffmpeg工具对传入的rtsp流进行转码再传给前端
这里记录整个过程与出现的问题解决
准备
需要三部分的准备:
- ffmpeg工具
- nodeJS转码
- 前端播放
ffmpeg安装与配置
- 下载ffmpeg https://ffmpeg.org/download.html
-
下载并解压完成后
我这里放在 D:\DevelopSoftware\ffmpeg
-
配置环境变量
我的电脑 => 属性 => 高级系统设置 => 环境变量 => Path => 添加
D:\DevelopSoftware\ffmpeg\bin
-
打开cmd输入
ffmpeg
或者ffmpeg -version
出现东西就说明OK了
如果
'ffmpeg' 不是内部或外部命令,也不是可运行的程序或批处理文件
, 重启cmd窗口, 还是不行的话网上搜一下吧
本节参考自 ffmpeg安装教程(windows版)
nodejs编写转码服务
先随便建个文件夹
npm i express express-ws fluent-ffmpeg websocket-stream
或者
yarn add express express-ws fluent-ffmpeg websocket-stream
新建 index.js
typescript
var express = require('express')
var expressWebSocket = require('express-ws')
var ffmpeg = require('fluent-ffmpeg')
var webSocketStream = require('websocket-stream/stream')
var WebSocket = require('websocket-stream')
var http = require('http')
ffmpeg.setFfmpegPath('ffmpeg')
// config
let rtspServerPort = 2156
function localServer() {
let app = express()
app.use(express.static(__dirname))
expressWebSocket(app, null, {
perMessageDeflate: true
})
// :id是动态参数, 前端调用时传递, 可以去掉
app.ws('/rtsp/:id/', rtspRequestHandle)
app.listen(rtspServerPort)
console.log('express listened on port : ' + rtspServerPort)
}
function rtspRequestHandle(ws, req) {
console.log('rtsp request handle')
const stream = webSocketStream(
ws,
{
binary: true,
browserBufferTimeout: 1000000
},
{
browserBufferTimeout: 1000000
}
)
let url = req.query.url
console.log('rtsp url:', url)
console.log('rtsp params:', req.params)
try {
ffmpeg(url)
.addInputOption('-rtsp_transport', 'tcp', '-buffer_size', '102400') // 这里可以添加一些 RTSP 优化的参数
.on('start', function () {
console.log(url, 'Stream started.')
})
.on('codecData', function () {
console.log(url, 'Stream codecData.')
// 摄像机在线处理
})
.on('error', function (err) {
console.log(url, 'An error occured: ', err.message)
})
.on('end', function () {
console.log(url, 'Stream end!')
// 摄像机断线的处理
})
.outputFormat('flv')
.videoCodec('copy')
.noAudio()
.pipe(stream)
} catch (error) {
console.log(error)
}
}
localServer()
运行
node index.js
前端调用转码服务
新建 demo.html
html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.bootcdn.net/ajax/libs/flv.js/1.6.2/flv.min.js"></script>
<!-- <script src="./js/flv.min.js"></script>-->
<style>
body,
center {
padding: 0;
margin: 0;
}
.v-container {
width: 640px;
height: 360px;
border: solid 1px red;
}
video {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="v-container">
<video id="player1" muted autoplay="autoplay" preload="auto" controls="controls"></video>
</div>
<script>
if (flvjs.isSupported()) {
var videoElement = document.getElementById('player1')
var flvPlayer = flvjs.createPlayer({
type: 'flv',
url: 'ws://localhost:2156/rtsp/111/?url=rtsp://xxx.xxx.xxx:554/openUrl/jmQgiJi'
})
flvPlayer.attachMediaElement(videoElement)
flvPlayer.load()
}
</script>
</body>
</html>
这两节源自 rtsp视频服务 基于node+ffmpeg 转换为 flv 视频服务
videojs + flvjs使用
yarn add video.js flv.js videojs-flvjs-es6
typescript
import videojs from 'video.js'
import flvjs from 'flv.js'
import 'video.js/dist/video-js.css'
import 'videojs-flvjs-es6'
let myPlayer
const initVideo = (videoUrl) => {
// videojs初始化
myPlayer = videojs(
document.querySelector('#videoBox'), // video元素, vue2或vue3推荐使用ref方式
{
// poster: '//vjs.zencdn.net/v/oceans.png',
autoplay: 'muted', //自动播放
controls: true, //用户可以与之交互的控件
loop: true, //视频一结束就重新开始
muted: true, //默认情况下将使所有音频静音
// aspectRatio: '16:9', //显示比率
techOrder: ['html5', 'flvjs'], // 兼容顺序
flvjs: {
mediaDataSource: {
cors: true,
withCredentials: false,
},
},
controlBar: {
remainingTimeDisplay: {
displayNegative: false,
},
},
playbackRates: [0.5, 1, 1.5, 2],
},
function onPlayerReady() {
this.on('play', function () {
console.log('视频开始播放')
})
this.on('pause', function () {
console.log('视频暂停播放')
})
this.on('error', function () {
console.log('加载错误')
isError.value = true
})
}
)
// 播放
myPlayer.reset()
myPlayer.src({
src: 'ws://localhost:2156/rtsp/?url=' + videoUrl,
type: 'video/x-flv',
})
// myPlayer.load('ws://localhost:2156/rtsp/1/?url=rtsp://xxxx:554/openUrl/rMYr6w0')
myPlayer.play()
}
html
<video ref="videoPlayer" id="videoBox" style="width:100%;height:100%;"></video>
总结
海康平台支持多种协议的视频流,如果流无法播放,可能是设备配置或者分辨率或者... 出了问题!!
这种事情当然是让后端去处理咯,是跟厂商联调还是怎么着,关我前端啥事儿!!!把精力用到更有意义的地方才是正解,例如像我一样水一篇文章, Nice!
当然,尽量直接使用海康平台API返回的流,转码始终是下策。
感谢各大佬的文章: