aruntj / mjpeg-readable-stream

Code to read an Mjpeg stream using the Readable stream api.
MIT License
53 stars 13 forks source link

OUT of Memory #2

Closed Guigass closed 3 years ago

Guigass commented 3 years ago

Hello, i have a Worker fetching the mjpg from the server insted of creating a blob url im using createImageBitmap to send the image to the main thread, but after 30 minutes the browser runs out of memory.

Heres my code: Can you think for improvements? Thanks

/// <reference lib="webworker" />

var fps = 0;
var urlVideo = "";
var reader;
var timerFps;

addEventListener('message', ({ data }) => {
  switch (data.action) {
    case 'start':
      urlVideo = data.imgUrl;

      fetchMjpg();
      break;
    case 'pause':
      clearInterval(timerFps);
      reader.cancel();

      break;
    case 'stop':
      clearInterval(timerFps);
      reader.cancel();

      self.close();
      break;
  }
});

function fetchMjpg() {
  const SOI = new Uint8Array(2);
  SOI[0] = 0xFF;
  SOI[1] = 0xD8;

  fetch(urlVideo).then(response => {
    reader = response.body.getReader();

    let headers = '';
    let contentLength = -1;
    let imageBuffer = null;
    let bytesRead = 0;

    timerFps = setInterval(() => {
      self.postMessage({ type: 'fps', fps });
      fps = 0;
    }, 1000);

    const read = () => {
      const timeStart = new Date().getTime();

      reader.read().then(({ done, value }) => {

        if (done) {
          return;
        }

        try {
          for (let index = 0; index < value.length; index++) {
            // we've found start of the frame. Everything we've read till now is the header.
            if (value[index] === SOI[0] && value[index + 1] === SOI[1]) {
              // console.log('header found : ' + newHeader);
              contentLength = getLength(headers);
              // console.log("Content Length : " + newContentLength);
              imageBuffer = new Uint8Array(new ArrayBuffer(contentLength));
            }
            // we're still reading the header.
            if (contentLength <= 0) {
              headers += String.fromCharCode(value[index]);
            }
            // we're now reading the jpeg.
            else if (bytesRead < contentLength) {
              imageBuffer[bytesRead++] = value[index];
            }
            // we're done reading the jpeg. Time to render it.
            else {
              var blob = new Blob([imageBuffer]);

              //#region Calcula a taxa de bitrate

              const timeEnd = new Date().getTime();
              const kbps = Math.round(blob.size / ((timeEnd - timeStart) / 1000) / 1024);

              self.postMessage({ type: 'kbps', kbps });

              //#endregion

              createImageBitmap(blob).then(imageBitmap => {
                self.postMessage({ type: 'image', imageBitmap });
              });

              fps++;
              contentLength = 0;
              bytesRead = 0;
              headers = '';
            }
          }
        } catch (error) {}

        read();
      }).catch(error => {
        console.error(error);
      })
    }

    read();

  }).catch(error => {
    console.error(error);
  })

  const getLength = (headers) => {
    let contentLength = -1;
    headers.split('\n').forEach((header, _) => {
      const pair = header.split(':');
      if (pair[0] === 'Content-Length') {
        contentLength = pair[1];
      }
    })
    return contentLength;
  };
}
Guigass commented 3 years ago

I has executing this code after every window.onfocus thats wht i had a memory leak. Sorry