5

我想在 Node.JS 中生成一些图像,将它们编译成视频并将它们流式传输到 youtube。要生成图像,我正在使用 node-canvas 模块。这听起来很简单,但我想连续生成图像,并实时传输结果。我对这件事很陌生,在阅读了互联网上的大量资源后,我正在考虑做的是:

  1. 打开 ffmpeg spawn('ffmpeg', ...args),将输出设置为目标 rtmp 服务器
  2. 在画布中生成图像
  3. 将画布的内容转换为缓冲区,通过stdin写入ffmpeg进程
  4. 在 Youtube 上享受结果

但事情并没有那么简单,不是吗?我看到人们分享他们的代码,涉及在浏览器上运行的客户端 JS,但我希望它是一个 Node 应用程序,以便我可以从远程 VPS 运行它。有没有办法让我做到这一点,而无需在浏览器中使用 p5 之类的东西并捕获窗口以重新流式传输它?我的思维过程是否足够?现在我并不真正关心性能/资源的使用。提前致谢。

编辑:

我研究了一段时间,但我无法让它工作......这是我的代码:

const { spawn } = require('child_process');
const { createCanvas } = require('canvas');
const fs = require('fs');


const canvas = createCanvas(1920, 1080);
const ctx = canvas.getContext('2d');
const ffmpeg = spawn("ffmpeg",
    ["-re", "-f", "png_pipe", "-vcodec", "png", "-i", "pipe:0", "-vcodec", "h264", "-re", "-f", "flv", "rtmp://a.rtmp.youtube.com/live2/key-i-think"],
    { stdio: 'pipe' })

const randomColor = (depth) => Math.floor(Math.random() * depth)
const random = (min, max) => (Math.random() * (max - min)) + min;

let i = 0;
let drawSomething = function () {
    ctx.strokeStyle = `rgb(${randomColor(255)}, ${randomColor(255)}, ${randomColor(255)})`
    let x1 = random(0, canvas.width);
    let x2 = random(0, canvas.width);
    let y1 = random(0, canvas.height);
    let y2 = random(0, canvas.height);
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();

    let out = canvas.toBuffer();
    ffmpeg.stdin.write(out)
    i++;
    if (i >= 30) {
        ffmpeg.stdin.end();
        clearInterval(int)
    };
}

drawSomething();
let int = setInterval(drawSomething, 1000);

我没有收到任何错误,也没有从中获得任何视频数据。我已经设置了一个可以连接的 rtmp 服务器,然后使用 VLC 获取流,但我没有得到任何视频数据。难道我做错了什么?我环顾了一段时间,似乎找不到任何人尝试过这个,所以我真的不知道......

编辑 2:显然我走在正确的轨道上,但我的方法只是给了我 2 秒的“好”视频,然后它开始变得块状和混乱。我认为,很可能,我生成图像的方法太慢了。我将尝试使用一些 GPU 加速代码来生成图像,而不是使用画布,这意味着我将一直在做分形,因为我不知道如何用它做任何其他事情。此外,ffmpeg 中更大的缓冲区也可能有帮助

4

1 回答 1

2

你的方法很好。请记住,无论您要流式传输到什么,都希望源端跟上。如果你不能足够快地生成帧,那么各种各样的事情都会出错。(我认为这主要是由于 YouTube 试图丢弃太慢的源,并在收到帧后重新拾取,只是再次失败。)

在尝试流式传输到 RTMP 服务器之前,您可以先输出到文件进行测试。

于 2020-10-10T01:46:17.697 回答