Generate video from Canvas

Confirmed for Version 75.0.3770.100 (Official Build) (64-Bit) on MacOS Version 77.0.3849.0 (Official Build) canary (64-Bit) on MacOS Version 77.0.3770.100 (Official Build) snap (64-bit) on Ubuntu 19.04 Disco Dingo

by keyboardsamurai

HTML

<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<div id="panel">

    <div id="recording_status" style="color: white; background-color: green; width: 150px;" class="panel-item">
        Not recording
    </div>

    <label for="toggle" class="panel-item">
        <input type="checkbox" checked onclick="toggleDrawImage();" id="toggle">
        <span>Use drawImage() = </span>
        <span id="imageState">undefined</span>
    </label>

    <div class="panel-item">
        <button onclick="renderVideo();">Render Video</button>
    </div>

    <div class="panel-item">
        <span id="panel-result-size"></span>
    </div>
</div>
<canvas id="drawing_canvas" width="1280" height="720"></canvas>
<script></script>
</body>
</html>

CSS

body {
  font-family: 'Arial', cursive;
}

#panel {
  display: inline-block;
  width: 100%;
  margin-bottom: 20px;
}

.panel-item {
  float: left;
  margin-left: 50px;
}

JavaScript

let drawImage = true;
    document.getElementById("imageState").innerText = drawImage;

    const image = new Image();
    image.src = 'https://66.media.tumblr.com/84d332cafeb1052c477c979281e5713b/tumblr_owe3l0tkCj1wxdq3zo1_1280.jpg';

    let allChunks, canvas, recorder;

    function animation() {
        const now = new Date();
        const ctx = document.getElementById('drawing_canvas').getContext('2d');

        ctx.clearRect(0, 0, 150, 150);

        ctx.strokeStyle = 'white';
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, 1280, 720);
        ctx.save();

        if (drawImage) {
            ctx.drawImage(image, 0, 0);  // !!! THIS LINE BREAKS THE STREAM !!!
        }

        ctx.translate(75, 75);
        ctx.scale(0.4, 0.4);
        ctx.rotate(-Math.PI / 2);
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'white';
        ctx.lineWidth = 8;
        ctx.lineCap = 'round';


        // Hour marks
        ctx.save();
        for (var i = 0; i < 12; i++) {
            ctx.beginPath();
            ctx.rotate(Math.PI / 6);
            ctx.moveTo(100, 0);
            ctx.lineTo(120, 0);
            ctx.stroke();
        }
        ctx.restore();

        // Minute marks
        ctx.save();
        ctx.lineWidth = 5;
        for (i = 0; i < 60; i++) {
            if (i % 5 != 0) {
                ctx.beginPath();
                ctx.moveTo(117, 0);
                ctx.lineTo(120, 0);
                ctx.stroke();
            }
            ctx.rotate(Math.PI / 30);
        }
        ctx.restore();

        const sec = now.getSeconds();
        const min = now.getMinutes();
        let hr = now.getHours();
        hr = hr >= 12 ? hr - 12 : hr;

        ctx.fillStyle = 'black';

        // write Hours
        ctx.save();
        ctx.rotate(hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) * sec);
        ctx.lineWidth = 14;
        ctx.beginPath();
        ctx.moveTo(-20, 0);
        ctx.lineTo(80, 0);
        ctx.stroke();
    ...