Trying to encode frames from canvas crashes browser with STATUS_BREAKPOINT on latest Brave

Trying to encode frame or record canvas causes page crash with STATUS_BREAKPOINT


Description of the issue:
When trying to record with MediaRecorder on a canvas, or encode fra image with encoder, the page crashes

How can this issue be reproduced?

  1. Execute this script in console on any page:
( () => {
console.log("1 encoder");

const encoder = new VideoEncoder({
  output: (c) => console.log("chunk", c),
  error: (e) => console.log("encoder error", e),
});

console.log("2 configure");

encoder.configure({
  codec: "vp8",
  width: 640,
  height: 360,
  bitrate: 500000,
});

console.log("3 frame");

const frame = new VideoFrame(
  new Uint8Array(640 * 360 * 4),
  {
    format: "RGBA",
    codedWidth: 640,
    codedHeight: 360,
    timestamp: 0,   // REQUIRED in newer Chromium
  }
);

console.log("4 frame ok");

encoder.encode(frame);

console.log("5 encoded");

frame.close();

console.log("6 done");
})();
  1. Run this on any page - If you click 2 then 3, or 3 then 2, it crashes, even though neither does by itself:
(function() {
    const hud = document.createElement('div');
    hud.style.cssText = 'position:fixed;top:10px;left:10px;z-index:999999;background:#000;padding:20px;border:3px solid #ff0;color:#fff;';
    hud.innerHTML = ' <button id="btn2" style="display:block;margin-bottom:10px;">2. Test CPU-to-Memory Write (putImageData)</button> <button id="btn3" style="display:block;">3. Test Encoding Pipeline (MediaRecorder)</button>';
    document.body.appendChild(hud);
    const canvas = document.createElement('canvas');
    canvas.width = 1280; canvas.height = 720;
    const ctx = canvas.getContext('2d');
    // 2. ISOLATED WRITEBACK: Forces memory re-allocation
    document.getElementById('btn2').onclick = () => {
        const dummy = new Uint8ClampedArray(1280 * 720 * 4);
        setInterval(() => ctx.putImageData(new ImageData(dummy, 1280, 720), 0, 0), 100);
        console.log("Writeback stress active");
    };
    // 3. ISOLATED ENCODER: Forces the Media Pipeline
    document.getElementById('btn3').onclick = () => {
        const stream = canvas.captureStream(30);
        const rec = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=vp9' });
        rec.start();
        console.log("Encoder active");
    };
})();
  1. Another short one that reproduces it - 2 and 3 cause crash

(function() {
    const video = document.getElementById('leftVideo');
    const container = document.createElement('div');
    container.style.cssText = 'position:fixed;top:10px;left:10px;z-index:999999;background:#222;padding:20px;border:3px solid #f00;';

    container.innerHTML = `
        <button id="btn-safe">1. SAFE: Draw to Canvas</button>
        <button id="btn-safe-stream">2. SAFE: Direct Stream</button>
        <button id="btn-crash">3. CRASH: CanvasCaptureStream</button>
    `;
    document.body.appendChild(container);

    // 1. SAFE: Just rendering, no encoder
    document.getElementById('btn-safe').onclick = () => {
        const canvas = document.createElement('canvas');
        canvas.width = 1280; canvas.height = 720;
        const ctx = canvas.getContext('2d');
        function draw() {
            ctx.drawImage(video, 0, 0);
            requestAnimationFrame(draw);
        }
        draw();
        alert("If this works, Canvas Compositor is stable.");
    };

    // 2. SAFE: Stream from video directly, bypassing Canvas
    document.getElementById('btn-safe-stream').onclick = () => {
        const stream = video.captureStream();
        const rec = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=vp9' });
        rec.start();
        setTimeout(() => rec.stop(), 2000);
        alert("If this works, Media Pipeline is stable.");
    };

    // 3. CRASH: The bridge that causes the STATUS_BREAKPOINT
    document.getElementById('btn-crash').onclick = () => {
        const canvas = document.createElement('canvas');
        canvas.width = 1280; canvas.height = 720;

        const ctx = canvas.getContext('2d');

        // This loop combined with captureStream() forces the
        // compositor-to-encoder memory sync that triggers your crash
        function draw() {
            ctx.drawImage(video, 0, 0);
            requestAnimationFrame(draw);
        }
        draw();

        const stream = canvas.captureStream(30);
        const rec = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=vp9' });
        rec.start();
        console.log("CRASH EXPECTED NOW...");
    };
})();

Expected result: Page crashes with this errror:

Brave Version( check About Brave): Seems to be caused from something in chromium, which was fixed in 150:
150.0.7869.0 - works
Nightly v1.93.33 (Chromium 149.0.7827.59) - broken
Brave 1.91.168 (Official Build) (64-bit) Chromium: 149.0.7827.54 - broken (since a few days ago)
Brave 1.91.163 (Official Build) beta (64-bit) Chromium: 148.0.7778.179 - working

Additional Information: Does not happen on every machine

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.