demo · v150
Worker Processor
Transfer the processor's .readable stream to a dedicated Worker for the heavy per-frame work, and read totalFrames / discardedFrames from the MediaStreamTrackProcessor on the main thread. A ReadableStream is transferable, so the frames cross to the worker — but a CanvasCaptureMediaStreamTrack is not, so the track object is never posted.
This demo uses a canvas-based synthetic
MediaStream (no camera permission required). The main thread builds the MediaStreamTrackProcessor and transfers its .readable stream to an inline Blob Worker that drains the frames. The counters are read from the processor on the main thread at 1 Hz. Slow down the worker consumer with the slider to induce frame drops.
Source (main thread)
Worker: idle
Consumer delay:
0 ms
Frame counter stats (posted from worker)
0
totalFrames
+0/s
0
discardedFrames
+0/s
0
fps (producer)
—
health
postMessage log (worker → main)
Architecture
Main thread
Canvas draw loop (30 fps)
canvas.captureStream(30)new MediaStreamTrackProcessor(track)Transfer
processor.readable to WorkerRead
totalFrames / discardedFrames @ 1 Hz⇄
Dedicated Worker
Receive transferred
ReadableStreamPull frames from
reader.read()Simulated per-frame work (configurable delay)
frame.close()Post drain progress to main
// main.js — keep the processor + counters on the main thread
const track = canvas.captureStream(30).getVideoTracks()[0];
const processor = new MediaStreamTrackProcessor({ track });
// A ReadableStream IS transferable; a CanvasCaptureMediaStreamTrack is NOT,
// so transfer the stream and never postMessage the track object.
const worker = new Worker(workerUrl);
worker.postMessage({ readable: processor.readable }, [processor.readable]);
setInterval(() => {
console.log(processor.totalFrames, processor.discardedFrames);
}, 1000);
// worker.js — heavy per-frame work drains the transferred stream
self.onmessage = ({ data }) => {
const reader = data.readable.getReader();
(async () => {
while (true) {
const { done, value: frame } = await reader.read();
if (done) break;
// ... per-frame work ...
frame.close();
}
})();
};
see also
- Pipeline Meter — live totalFrames / discardedFrames readout
- Pipeline Health Monitor — health chart and discard rate alert
- Counters API Explorer — feature-detect and probe the API
- ChromeStatus: MediaStreamTrackProcessor frame counters
- Insertable Streams of Media spec
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗