Animation rendering using Nodejs on backend server

2020-07-27 05:47发布

I have simple animation created using create js and ffmpegserver.js.

ffmpegserver.js.

This is a simple node server and library that sends canvas frames to the server and uses FFmpeg to compress the video. It can be used standalone or with CCapture.js.

Here is repo: video rendering demo.

on folder public, I have demos eg test3.html and test3.js

Test3.html

<!DOCTYPE html>
<html>
<head>
    <title>TweenJS: Simple Tween Demo</title>
<style>

canvas {
          border: 1px solid #08bf31;
          justify-content: center;
          display: flex;
          align-items: center;
          margin: 0px auto;
          margin-bottom: 40px;
      }

      a {
        width: 150px;
        height: 45px;
        background: red;
        text-align: center;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 300px;
        color: white;
      }
      #container{
        flex-direction: column;
        justify-content: center;
        display: flex;
        align-items: center;
        margin: 0px auto;
      }
    #progress{
        margin: 30px;
    }
    #preview{
        margin: 40px;
        width: 150px;
        height: 45px;
        background: deepskyblue;
        color: white;
        border: none;
        border-radius: 300px;
    }


</style>

</head>
<body onload="init();">

<div>

<div id="container">
        <h1>Simple Tween Demo</h1>
    <canvas id="testCanvas" width="500" height="400"></canvas>
    <div id="progress"></div>
</div>
</div>
<script src="http://localhost:8081/ffmpegserver/CCapture.js"></script>
<script src="http://localhost:8081/ffmpegserver/ffmpegserver.js"></script>
<script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.js"></script>
<script src="test3.js"></script>
</body>
</html>

Test3.js

/* eslint-disable eol-last */
/* eslint-disable no-undef */
/* eslint-disable quotes */
var canvas, stage;
    function init() {
        var framesPerSecond = 60;
        var numFrames = framesPerSecond * 5; // a 5 second 60fps video
        var frameNum = 0;

        var progressElem = document.getElementById("progress");
        var progressNode = document.createTextNode("");
        progressElem.appendChild(progressNode);

        function onProgress(progress) {
          progressNode.nodeValue = (progress * 100).toFixed(1) + "%";
        }

        function showVideoLink(url, size) {
          size = size ? (" [size: " + (size / 1024 / 1024).toFixed(1) + "meg]") : " [unknown size]";
          var a = document.createElement("a");
          a.href = url;
          var filename = url;
          var slashNdx = filename.lastIndexOf("/");
          if (slashNdx >= 0) {
            filename = filename.substr(slashNdx + 1);
          }
          a.download = filename;
          a.appendChild(document.createTextNode("Download"));
          var container = document.getElementById("container").insertBefore(a, progressElem);

        }

        var capturer = new CCapture( {
          format: 'ffmpegserver',
          //workersPath: "3rdparty/",
          //format: 'gif',
          //verbose: true,
          framerate: framesPerSecond,
          onProgress: onProgress,
          //extension: ".mp4",
          //codec: "libx264",
        } );
        capturer.start();


        canvas = document.getElementById("testCanvas");
        stage = new createjs.Stage(canvas);
        var ball = new createjs.Shape();
        ball.graphics.setStrokeStyle(5, 'round', 'round');
        // eslint-disable-next-line quotes
        ball.graphics.beginStroke('#000000');
        ball.graphics.beginFill("#FF0000").drawCircle(0, 0, 50);
        ball.graphics.setStrokeStyle(1, 'round', 'round');
        ball.graphics.beginStroke('#000000');
        ball.graphics.moveTo(0, 0);
        ball.graphics.lineTo(0, 50);
        ball.graphics.endStroke();
        ball.x = 200;
        ball.y = -50;
        createjs.Tween.get(ball, {loop: -1})
            .to({x: ball.x, y: canvas.height - 55, rotation: -360}, 1500, createjs.Ease.bounceOut)
            .wait(1000)
            .to({x: canvas.width - 55, rotation: 360}, 2500, createjs.Ease.bounceOut)
            .wait(1000)
            .to({scaleX: 2, scaleY: 2}, 2500, createjs.Ease.quadOut)
            .wait(1000)
        stage.addChild(ball);
        createjs.Ticker.addEventListener("tick", stage);


        function render() {
            requestAnimationFrame(render);
            capturer.capture( canvas );

            ++frameNum;
            if (frameNum < numFrames) {
            progressNode.nodeValue = "rendered frame# " + frameNum + " of " + numFrames;
            } else if (frameNum === numFrames) {
            capturer.stop();
            capturer.save(showVideoLink);
            }
        }

        render();
}

Everything works fine, you can test it yourself if you want by cloning the repo.

Right now animation rendering happens in client side, I would like this animation rendering to happen in the backend side

What do I need to change to make this animation rendering in backend server side using Nodejs? any help or suggestions will be appreciated.

1条回答
Root(大扎)
2楼-- · 2020-07-27 06:48

Since you do all your animations in the canvas, you can use node-canvas to do the same in Node.js. (You have to double check that create.js also work in Node.js, though. If not, find another library or write those routines yourself).

Spawn ffmpeg into it's own process accepting input through a pipe (ffmpeg -i - -f rawvideo -pix_fmt rgba etc. The pipe will probably be different according to which server environment you use). After each frame is drawn, extract the image array using canvas.getContext('2d').getImageData(0, 0, width, height).data and pipe the result to to ffmpeg.

查看更多
登录 后发表回答