MSTP/MSTG FrameDropper (working)

by jib1

HTML

<button id="button">Start</button><br>
<video id="video1" width="320" height="180" autoplay controls></video><br>
<div id="fps1">FPS 0.00</div>
<video id="video2" width="320" height="180" autoplay controls></video><br>
<div id="fps2">FPS 0.00</div>

JavaScript

// Showing a high-fps self-view while "sending" (encode/decode) low-fps video
button.onclick = async () => {
  try {
    const video = {width: 1280, height: 720};
    const stream = await navigator.mediaDevices.getUserMedia({video});
    const [track] = stream.getTracks();
    const {readable} = new MediaStreamTrackProcessor({track});

    const track2 = new MediaStreamTrackGenerator({kind: 'video'});
    const writableSelfView = track2.writable;
    video1.srcObject = new MediaStream([track2]);

    const track3 = new MediaStreamTrackGenerator({kind: 'video'});
    const writableRemoteView = track3.writable;
    video2.srcObject = new MediaStream([track3]);

    const b = new Blob([`(${work.toString()})()`], {type: "text/javascript"});
    const worker = new Worker(URL.createObjectURL(b));
    worker.postMessage({readable, writableSelfView, writableRemoteView},
                       [readable, writableSelfView, writableRemoteView]);

    const frames = v => v.mozPaintedFrames || v.webkitDecodedFrameCount;
    const wait = ms => new Promise(r => setTimeout(r, ms));
    const updateFps = (element, video, state) => {
      const last = state.counter;
      state.counter = frames(video);
      element.innerHTML = `FPS ${(state.counter - last).toFixed(2)}`;
    }

    const frames1 = {counter: frames(video1)};
    const frames2 = {counter: frames(video2)};
    while (true) {
      await wait(1000);
      updateFps(fps1, video1, frames1);
      updateFps(fps2, video2, frames2);
    }
  } catch (e) {
    console.log(e);
  }
};

function work() {
  let decoder;

  onmessage = async ({data: {readable, writableSelfView, writableRemoteView}}) => {
    try {
      readable = readable.pipeThrough(new TransformStream({transform: crop}));

      const [r1, r2] = teeSynchronizedCloned(readable);
      await Promise.all([
        r1.pipeTo(writableSelfView),
        r2.pipeThrough(new FrameDropper())
          .pipeThrough(new EncodeVideoStream({
            codec: "vp8",
     ...