3

I'm trying to make a simple live webcam streaming (1 streamer to many clients) and I've run into a problem with showing the video on the client-side.

My basic system is that the webcam is recorded into 1000ms chunks using MediaRecorder, which is sent to the server using the WebSocket, which then broadcasts that recording all the other users, and those ArrayBuffers are converted and played consecutively on the user webpage. This is my code:

//recieve video chunks from server
socket.on('video-stream', (stream) => {
  console.log(stream);
  createVideo(URL.createObjectURL(new Blob(stream)), 1);
});

//record video in chunks, send over websocket
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((stream) => {
  setInterval(function () {
    record(stream, 1000).then((recording) => {
      socket.emit('video-stream', {
        stream: recording,
        room: window.location.pathname.split('/')[0] || '/',
        cam: 1,
      });
    });
  }, 1000);
});

var record = (stream, ms) => {
  var rec = new MediaRecorder(stream),
    data = [];
  rec.ondataavailable = (e) => data.push(e.data);
  rec.start();
  var stopped = new Promise(
    (y, n) => ((rec.onstop = y), (rec.onerror = (e) => n(e.error || e.name)))
  );
  return Promise.all([stopped, wait(ms).then(() => rec.stop())]).then(() => data);
};

var wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

function createVideo(stream, cam) {
  var video = document.getElementById('cam-' + cam + '-embed');
  video.src = stream;
  //video.addEventListener('click', () => {
  //  if (video.volume != 0) video.volume = 0;
  //  else video.volume = 1;
  //});
}

The problem is that this requires changing the src of the video element on the page every 1000ms which makes the video blink constantly and not be smooth. I need some way to merge the incoming video buffers on the clientside instead of constantly changing the video element. I've been trying to figure out how to do this with no luck. Can someone please help me merge the incoming data into 1 video?

I've also tried: -RTC - doesn't work because way to much bandwidth required on the streaming user. -Encoding and connecting the videos on the server side, and then piping it to a response as a readablestream. This also didn't work.

Chenlenkiy
  • 31
  • 1

1 Answers1

3

You need mediasource and sourcebuffer. Something like this:

var video = document.querySelector("#video");
video.src = URL.createObjectURL(mediaSource)

socket.on('onChunk', (d) => {          
  if(mediaSource.readyState == 'open') {
    sourceBuffer.appendBuffer(d);
  }
})
var mediaSource = new MediaSource();
var sourceBuffer = null;
mediaSource.addEventListener("sourceopen", function()
{
  sourceBuffer = mediaSource.addSourceBuffer("video/webm;codecs=vp8,opus");
});

More info: HTML5 Video: Streaming Video with Blob URLs

Jonathan
  • 31
  • 3
  • This certainly helped, but now my video freezes after the first chunk. The next chunks are still getting received by the client, and it seems like they are being successfully added to the sourceBuffer, but I still don't understand why it only plays the first clip then freezes. Any help? – Chenlenkiy May 24 '20 at 04:48