node.js - 使用 puppeteer + ffmpeg 从网站录制视频
问题描述
我正在尝试使用类似于puppeteer-recorder的方式从网站录制视频,但我想自己停止录制,然后将其保存到文件(在我停止之后)。为此,我编写了简单的 Web 服务:
var express = require('express');
var app = express();
const { spawn } = require('child_process');
const puppeteer = require('puppeteer');
var record = true;
app.get('/startRecord', function (req, res)
{
const frun_record = async () => {
console.log("Start recording");
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://worldfoodclock.com/', { waitUntil: 'networkidle2' });
var ffmpegPath = 'ffmpeg';
var fps = 60;
var outFile = 'E:\\Code\\video-record\\output.webm';
const args = ffmpegArgs(fps);
args.push(outFile);
const ffmpeg = spawn(ffmpegPath, args);
const closed = new Promise((resolve, reject) => {
ffmpeg.on('error', reject);
ffmpeg.on('close', resolve);
});
console.log("Entering loop");
while (record) {
let screenshot = await page.screenshot({ omitBackground: true });
await write(ffmpeg.stdin, screenshot);
}
ffmpeg.stdin.end();
console.log("Recording stopped");
await closed;
};
frun_record();
res.end( "starting recording" );
})
app.get('/stopRecord', function (req, res) {
record = false;
res.end( "stopped" );
})
const ffmpegArgs = fps => [
'-y',
'-f',
'image2pipe',
'-r',
`${+fps}`,
'-i',
'-',
'-c:v',
'libvpx',
'-auto-alt-ref',
'0',
'-pix_fmt',
'yuva420p',
'-metadata:s:v:0',
'alpha_mode="1"'
];
const write = (stream, buffer) =>
new Promise((resolve, reject) => {
stream.write(buffer, error => {
if (error) reject(error);
else resolve();
});
});
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
但它总是只录制 1 秒的视频,看起来就像流刚刚被覆盖。我尝试将屏幕截图保存在磁盘上,这是超过 1 秒的视频。所以主要的问题是如何把所有的截图放到流中,然后保存到磁盘上?我想知道的另一件事是从网页截屏的频率是多少?
解决方案
可以这样做:
let recordVideo = (setup) => {
return new Promise(async (resolve, reject) => {
let frames = [];
let session;
let start = async () => {
session = await page.target().createCDPSession();
await session.send('Page.startScreencast');
session.on('Page.screencastFrame', event => {
event.data; // Base64 encoded frame
frames.push(event.data);
});
}
let stop = async () => {
await session.send('Page.stopScreencast');
resolve(frames);
}
await setup(start, stop);
});
}
let setup = (start, stop) => {
start();
/** statements */
stop();
}
let frames = await recordVideo(setup);
在“session.on”函数中,每次该函数触发一个新帧时,都会检索所有帧。您必须用您的逻辑替换“/** statements */”。
推荐阅读
- python - 为什么我的新机器人出现 Discord SSL 验证错误?
- ocaml - 如何构建 OASIS 包
- apache-spark - 无法在 Databricks 上运行 spark.eventLog.enabled true 和 spark.eventLog.dir
- swift - 没有“'Range 类型的表达式模式”,无法使函数工作
'不能匹配'Int'类型的值" - c++ - 为什么向量不在代码块中运行?
- bash - 当我回显或尝试创建命令时,bash shell 脚本将最后一项放在首位
- rust - 如何使用 TcpStream 拆分为 2 个异步线程?
- magento - Magento 会话立即到期
- xml - XSLT 3.0 将节点组合成单个父节点
- python - 从文本文件的数据中取平均值