使用bilibili開源的flvjs實作攝像頭rtsp視訊直播
實作攝像頭的直播功能其實有許多方案,像是安裝vlc插件、rtsp轉rtmp然後使用videojs通過flash播放rtmp,以及hls .m3u8等方式
然而現今的浏覽器對于vlc插件幾乎都不再支援了,flash在2020年也将被chrome停止支援,而.m3u8的方案用來做直播的話似乎延遲很高
經過一番查找,最終決定使用B站(bilibili)開源的flvjs作為解決方案,其原理是後端用ffmpeg将rtsp視訊流轉換為flv,然後通過websocket傳輸flv視訊流,然後前端通過websocket擷取到視訊流後,使用flvjs對視訊流再一次處理并進行播放,這是一套無插件無flash免費的視訊直播解決方案。
Demo github位址:https://github.com/LorinHan/flvjs_test
1.使用vlc等工具測試,確定rtsp流可連接配接
2.後端環境:node express
2.1 安裝第三方依賴
npm install express express-ws fluent-ffmpeg websocket-stream -S -D
2.2 編寫代碼 index.js
其中setFfmpegPath這裡是指明了ffmpeg的安裝路徑,如果沒有安裝,請看第4點
var express = require("express");
var expressWebSocket = require("express-ws");
var ffmpeg = require("fluent-ffmpeg");
ffmpeg.setFfmpegPath("D:/ffmpeg-20191031-7c872df-win64-static/ffmpeg-20191031-7c872df-win64-static/bin/ffmpeg");
var webSocketStream = require("websocket-stream/stream");
var WebSocket = require("websocket-stream");
var http = require("http");
function localServer() {
let app = express();
app.use(express.static(__dirname));
expressWebSocket(app, null, {
perMessageDeflate: true
});
app.ws("/rtsp/:id/", rtspRequestHandle)
app.listen(8888);
console.log("express listened")
}
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();
2.3 啟動後端,node index.js
3.前端環境,采用vue
3.1 vue的搭建就不贅述了,建構好一個vue項目之後,npm install flv.js -S -D
3.2 編寫代碼
video标簽中的muted屬性,是因為在視訊流加載好之後,autoplay屬性無法自動播放,加上這個屬性後就可以實作了
<template>
<div>
<video class="demo-video" ref="player" muted autoplay></video>
</div>
</template>
<script>
import flvjs from "flv.js";
export default {
data () {
return {
id: "1",
rtsp: "rtsp://admin:[email protected]:554/h264/ch1/main/av_stream",
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/${this.id}/?url=${this.rtsp}`
});
this.player.attachMediaElement(video);
try {
this.player.load();
this.player.play();
} catch (error) {
console.log(error);
};
}
// if (video) {
// this.player = flvjs.createPlayer({
// type: "flv",
// url: `/static/test.flv`
// });
// this.player.attachMediaElement(video);
// try {
// this.player.load();
// this.player.play();
// } catch (error) {
// console.log(error);
// };
// }
}
},
beforeDestroy () {
this.player.destory();
}
}
</script>
<style>
.demo-video {
max-width: 880px;
max-height: 660px;
}
</style>
4.到此為止,如果你有ffmpeg的環境,應該可以在前端看到畫面了,如果沒有ffmpeg的話請進行安裝
4.1 通路官網ffmpeg.zeranoe.com/builds/,根據作業系統自行選擇安裝
4.2 下載下傳好後進行解壓,在後端設定ffmpeg路徑的代碼中指向解壓路徑下的bin目錄下的ffmpeg
var ffmpeg = require("fluent-ffmpeg");
ffmpeg.setFfmpegPath("D:/ffmpeg-20191031-7c872df-win64-static/ffmpeg-20191031-7c872df-win64-static/bin/ffmpeg");