微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

电子网络流媒体

如何解决电子网络流媒体

我正在尝试使用电子和 nodejs 服务器通过 networkig 流式传输我的桌面。 问题是,传输的字节没有显示为视频源。

我在底部提供了代码来重现。 请记住,这只是一些测试,tcp 服务器/客户端将被正确编码以用于生产。

node -v: v14.16.0 npm -v: 6.14.11

流媒体客户端 [index.html] (Electron):

<!DOCTYPE html>
<html>
<head>
    <Meta charset="UTF-8">
    <title>Hello World!</title>
    <Meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: rgb(33,33,33);">
    <video id="video" controls width="1280" height="720"></video>
    <script>require('./index.js')</script>
</body>
</html>

流媒体客户端 [index.js] (Electron):

const { desktopCapturer,ipcRenderer } = require("electron");

desktopCapturer.getSources({types: ["window","screen"]}).then(async sources => {
  for(const source of sources){
    if(source.name === "Screen 1"){
      try{
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: false,video: {
            mandatory: {
              chromeMediaSource: 'desktop',chromeMediaSourceId: source.id,minWidth: 1280,maxWidth: 1280,minHeight: 720,maxHeight: 720,maxFrameRate: 60
            }
          }
        });   
        handleStream(stream);
      } catch (e){
        handleError(e);
      }
      return;
    }
  }
})

function handleStream(stream){ 
  const recorder = new MediaRecorder(stream,{mimeType: 'video/webm; codecs=vp9'});
  recorder.ondataavailable = handleDataAvailable;
  const video = document.querySelector("#video");
  video.srcObject = stream;

  video.onloadedMetadata = (e) => {
    video.play();
    recorder.start(2000);
  }
}

function handleError(error){
  console.log(error);
}

const handleDataAvailable = (event) => {
  event.data.arrayBuffer().then(buffer => {
    ipcRenderer.send("video-data",buffer);
  })
}

流媒体客户端 [main.js] (Electron):

const { app,browserWindow,ipcMain } = require('electron')
const fs = require("fs");
const net = require("net");

const client = new net.socket();
let CLIENT_CONNECTED = false;

function createWindow () {
  const win = new browserWindow({
    width: 800,height: 600,webPreferences: {
      nodeIntegration: true,contextIsolation: false
    }
  })
  win.webContents.toggleDevTools();
  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()
  client.connect(10000,"127.0.0.1",() => {
    console.log("connected");
    CLIENT_CONNECTED = true;
  })
});

client.on("data",data => {
  console.log(data);
});

client.on("close",() => {
  console.log("client closed");
  CLIENT_CONNECTED = false;
});

client.on("error",error => {
  console.log(error);
  CLIENT_CONNECTED = false;
});

app.on('window-all-closed',() => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate',() => {
  if (browserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})

ipcMain.on('video-data',(event,arg) => {
  if(CLIENT_CONNECTED) client.write(new Buffer.from(arg).toString('base64'));
})

接收客户端 [index.js] (Electron):

const { ipcRenderer } = require("electron");
const video = document.getElementById("video");

const prefix = "data:video/webm;base64,";

ipcRenderer.on("video-data",arg) => {
  video.setAttribute("src",prefix + arg);
})

接收客户端 [index.html] (Electron):

<!DOCTYPE html>
<html>
<head>
    <Meta charset="UTF-8">
    <title>Hello World!</title>
    <Meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: rgb(33,33);">
    <video id="video" controls width="1280" height="720"></video>
    <script>require('./index.js')</script>
</body>
</html>

接收客户端 [main.js] (Electron):

const { app,ipcMain,ipcRenderer } = require('electron')
const fs = require("fs");
const net = require("net");
const { Readable } = require("stream");
var ipcstream = require('electron-ipc-stream')

const client = new net.socket();
let CLIENT_CONNECTED = false;

const webmReadable = new Readable();
webmReadable._read = () => { };

let win;
let ipcs;

function createWindow () {
  win = new browserWindow({
    width: 800,contextIsolation: false
    }
  });
  ipcs = new ipcstream('video-data',win)
  win.webContents.toggleDevTools();
  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()
  client.connect(10000,() => {
    console.log("connected");
    CLIENT_CONNECTED = true;
  })
  webmReadable.on("data",data => {
    win.webContents.send("video-data",Buffer.from(data).toString("base64"));
  })
});

client.on("data",data => {
  const buffer = Buffer.from(data);
  console.log(buffer.length);
  webmReadable.push(buffer);
});

client.on("close",() => {
  if (browserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})

节点js tcp服务器:

const net = require("net");
const server = net.createServer();
const process = require("process");

let sockets = [];
let buffers = [];

process.on("SIGINT",() => {
  console.log(buffers);
})

const handleConnect = (socket) => {
  sockets.push(socket);
  buffers.push({socket: socket,buffer: []})
  socket.on("data",data => handleData(socket,data));
  socket.on("error",error => handleError(socket,error));
  socket.on("close",() => handleClose(socket));
  socket.on("end",() => handleEnd(socket));
  socket.on("drain",() => handleDrain(socket));
  socket.on("lookup",() => handleLookup(socket));
  socket.on("timeout",() => handleTimeout(socket));
}

const handleData = (socket,data) => {
  broadcast(socket,data);
  // buffers.forEach(s => {
  //   if(s.socket == socket){
  //     // console.log("socket gefunden,daten werden gespeichert");
  //     // let buf = Buffer.from(data);
  //     // s.buffer.push(buf);
  //   }
  // })
}

const handleError = (socket,error) => {
  const index = sockets.indexOf(socket);
  sockets.splice(index,1);
  console.error(error);
}

const handleClose = (socket) => {
  const index = sockets.indexOf(socket);
  sockets.splice(index,1);
  console.log("client closed");
}

const handleEnd = (socket) => {
  console.log("client ended");
}

const handleDrain = (socket) => {
  
}

const handleLookup = (socket) => {
  console.log("client lookup");
}

const handleTimeout = (socket) => {
  const index = sockets.indexOf(socket);
  sockets.splice(index,1);
  console.log("client timeout");
}

const broadcast = (sender,data) => {
  sockets.forEach(socket => {
    if(socket !== sender) socket.write(data);
  })
}

server.on("connection",socket => handleConnect(socket));
server.listen(10000,"127.0.0.1");

非常感谢,希望你能帮助我。

附言我已经尝试过 ffmpeg,我无法获得正确的输出质量(并且流根本不起作用),所以我认为我会使用 Electron desktopCapturer,因为我无论如何都想构建一个电子应用程序。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。