最近在用 Electron 开发一个客户端 需要集成监控摄像头
摄像头是海康的网络摄像头 通过 RTSP 协议获取到推流视频
通过在 node 主进程创建一个服务 通过 websocket 接受 rtsp 连接
在通过 ffmpeg 转码通过 stream 推到渲染进程
渲染进程通过 flv.js 播放视频
通过转码可以实现 web 页面播放 rtsp 的视频流
但是会有 5~6 秒的延迟 体验很不好
而且 客户端集成 ffmpeg 体积太大了
想了解下 关于 rtsp 转码的方法还有那些 在 node 端可以实现的
主进程创建的 web 服务
import * as express from 'express'
import * as expressWebSocket from 'express-ws'
import ffmpeg from 'fluent-ffmpeg'
import webSocketStream from 'websocket-stream/stream'
const path = require('path')
let ffmpegPath
if (process.env.NODE_ENV === 'development') {
ffmpegPath = path.join(__static, 'ffmpeg', 'bin', 'ffmpeg.exe')
} else {
ffmpegPath = path.join(process.cwd(), 'ffmpeg', 'bin', 'ffmpeg.exe')
}
ffmpeg.setFfmpegPath(ffmpegPath)
// 启动视频转码服务服务
function videoServer () {
let app = express()
app.use(express.static(__dirname))
expressWebSocket(app, null, {
perMessageDeflate: true
})
app.ws('/rtsp/', rtspRequestHandle)
app.listen(8888)
console.log('express listened')
}
// RTSP 转码方法
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)
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)
}
}
export default videoServer
渲染进程通过播放视频
<template>
<div class="video">
<video class="video-box" ref="player"></video>
</div>
</template>
<script>
import flvjs from 'flv.js'
export default {
name: 'videopage',
props: {
rtsp: String
},
data () {
return {
player: null
}
},
mounted () {
if (flvjs.isSupported()) {
let video = this.$refs.player
if (video) {
this.player = flvjs.createPlayer({
type: 'flv',
isLive: true,
url: 'ws://localhost:8888/rtsp/?url=' + this.rtsp
})
this.player.attachMediaElement(video)
try {
this.player.load()
this.player.play()
} catch (error) {
console.log(error)
}
}
}
},
methods: {
getCurrentFrame () {
let video = this.$refs.player
let scale = 1
let canvas = document.createElement('canvas')
canvas.width = video.videoWidth * scale
canvas.height = video.videoHeight * scale
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height)
return canvas.toDataURL('image/png')
}
},
beforeDestroy () {
this.player.destory()
}
}
</script>
<style lang="scss">
.video {
width: 100%;
height: 100%;
font-size: 0;
video {
width: 100%;
height: 100%;
}
}
</style>
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.