jsmpeg + ffmpeg播放多个RTSP监控视频流

319 阅读2分钟

上一篇文章介绍了# 监控视频流媒体播放-jsmpeg+ffmpeg[监控视频流媒体播放-jsmpeg+ffmpeg监控视频流有两种类型,包含H264、H265。 尝试过的方法: webRT - 掘金]这种方法支持H264、H265的播放,但只能播放单路流,node服务使用的websocket-relay.js会将收到的ffmpeg转码的流广播给所有与node服务建立链接的客户端,这样播放多路流会出现串流现象。因此需要对websocket-relay.js进行改造。

  1. 将websocket-relay.js改造如下
// Use the websocket-relay to serve a raw MPEG-TS over WebSockets. You can use
// ffmpeg to feed the relay. ffmpeg -> websocket-relay -> browser
// Example:
// node websocket-relay yoursecret 8081 8082
// ffmpeg -i <some input> -f mpegts http://localhost:8081/yoursecret

var fs = require("fs"),
  http = require("http"),
  WebSocket = require("ws");

if (process.argv.length < 3) {
  console.log(
    "Usage: \n" +
      "node websocket-relay.js <secret> [<stream-port> <websocket-port>]"
  );
  process.exit();
}

var STREAM_SECRET = process.argv[2],
  STREAM_PORT = process.argv[3] || 8081,
  WEBSOCKET_PORT = process.argv[4] || 8082,
  RECORD_STREAM = false;

var clients = [];
// Websocket Server
var socketServer = new WebSocket.Server({
  port: WEBSOCKET_PORT,
  perMessageDeflate: false,
});
socketServer.connectionCount = 0;
socketServer.on("connection", function (socket, upgradeReq) {
  socketServer.connectionCount++;
  socket.reqUrl = upgradeReq.url
  clients.push(socket);
  console.log(
    "New WebSocket Connection: ",
    (upgradeReq || socket.upgradeReq).socket.remoteAddress,
    (upgradeReq || socket.upgradeReq).headers["user-agent"],
    "(" + socketServer.connectionCount + " total)"
  );
  socket.on("close", function (code, message) {
    socketServer.connectionCount--;
    console.log(
      "Disconnected WebSocket (" + socketServer.connectionCount + " total)"
    );
  });
});

socketServer.broadcast = function (data, ffmpeg_url) {
  if (clients) {
    clients.forEach(client=>{
      if (client.readyState === WebSocket.OPEN &&  ffmpeg_url.includes(client.reqUrl)) {
        client.send(data);
      }
    });
  }
};

// HTTP Server to accept incomming MPEG-TS Stream from ffmpeg
var streamServer = http.createServer(function (request, response) {
  var params = request.url.substr(1).split("/");

  if (params[0] !== STREAM_SECRET) {
    console.log(
      "Failed Stream Connection: " +
        request.socket.remoteAddress +
        ":" +
        request.socket.remotePort +
        " - wrong secret."
    );
    response.end();
  }

  response.connection.setTimeout(0);
  console.log(
    "Stream Connected: " +
      request.socket.remoteAddress +
      ":" +
      request.socket.remotePort
  );
  request.on("data", function (data) {
    socketServer.broadcast(data, request.url);
    if (request.socket.recording) {
      request.socket.recording.write(data);
    }
  });
  request.on("end", function () {
    console.log("close");
    if (request.socket.recording) {
      request.socket.recording.close();
    }
  });

  // Record the stream to a local file?
  if (RECORD_STREAM) {
    var path = "recordings/" + Date.now() + ".ts";
    request.socket.recording = fs.createWriteStream(path);
  }
});
// Keep the socket open for streaming
streamServer.headersTimeout = 0;
streamServer.listen(STREAM_PORT);

console.log(
  "Listening for incomming MPEG-TS Stream on http://127.0.0.1:" +
    STREAM_PORT +
    "/<secret>"
);
console.log(
  "Awaiting WebSocket connections on ws://127.0.0.1:" + WEBSOCKET_PORT + "/"
);
  1. 使用ffmpeg转码多路流时,需要打开多个cmd窗口,每个流输出的url进行区分

比如对第一个rtsp流rtsp://user:password@ip

ffmpeg -i rtsp://user:password@ip -q 0 -f mpegts -codec:v mpeg1video -s 800x600 http://127.0.0.1:8081/supersecret/live1

对第二个rtsp流rtsp://user:password@ip

ffmpeg -i rtsp://user:password@ip -q 0 -f mpegts -codec:v mpeg1video -s 800x600 http://127.0.0.1:8081/supersecret/live2

  1. web页面使用jsmpeg进行转码时需要使用对应的url解码
<template>
  <div class="right_one_box">
    <div class="title"><span></span>蘑菇房视频监控</div>
    <div class="box_con">
      <div class="con">
        <canvas id="video-canvas1" style="height: 500px; wight: 700px"></canvas>
        <canvas id="video-canvas2" style="height: 500px; wight: 700px"></canvas>
      </div>
    </div>
  </div>
</template>
<script> 
export default {
  name: 'Home',
  data () {
    return {
      path1: 'ws://127.0.0.1:8082/live1',   //你拉取视频源地址
      canvas1: null,
      path2: 'ws://127.0.0.1:8082/live2',   //你拉取视频源地址
      canvas2: null,
    }
  },
  mounted () {
    this.canvas1 = document.getElementById('video-canvas1')
    var player1 = new JSMpeg.Player(this.path1, { canvas: this.canvas1 })
    this.canvas2 = document.getElementById('video-canvas2')
    var player2 = new JSMpeg.Player(this.path2, { canvas: this.canvas2 })
  },
  methods: {
  
  }
}
</script>