我使用navigator.webkitGetUserMedia
每秒捕获一次窗口的屏幕截图,方法是将返回的stream
分配给<video>
并将其复制到<canvas>
并且将缓冲区保存到文件。
我的应用程序中的CPU使用率一直很高,我已将其精确定位到此区域。
// Initialize the video, canvas, and ctx
var localStream,
_video = document.querySelector('#video'),
_canvas = document.querySelector('#canvas'),
_ctx = _canvas.getContext('2d'),
sourceName = 'my-window-id';
// Load the stream from navigator.webkitGetUserMedia
navigator.webkitGetUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: sourceName,
minWidth: 1920,
maxWidth: 1920,
minHeight: 1080,
maxHeight: 1080
}
}
}, gotStream, getUserMediaError);
function gotStream(stream) {
// Use the stream in our <video>
_video.src = window.URL.createObjectURL(stream);
// Reference the stream locally
localStream = stream;
}
function captureState() {
var buffer,
dataURL;
// Draw <video> to <canvas> and convert to buffer (image data)
_ctx.drawImage(_video, 0, 0);
dataURL = _canvas.toDataURL('image/png');
buffer = new Buffer(dataURL.split(",")[1], 'base64');
// Create an image from the data
fs.writeFileSync('screenshot.png', buffer);
}
// Capture state every second
setInterval(function() {
captureState();
}, 1000);
此代码我没有运行,它是我的代码中的简化版本,使StackOverflow可读。
_video.pause()
和_video.play()
。似乎没有改变CPU使用率。_video.stop()
。这意味着我必须再次获取流,这会导致CPU使用率的飙升比保持打开状态更差。我现在最好的方法是通过添加:
来更改帧速率 optional: [
{ minFrameRate: 1 },
{ frameRate: 1 }
]
极低的帧速率会很好。但是,在这种情况下,我还无法确定frameRate
设置是否有效。 The docs没有列出,我没有更新的mediaDevices.getUserMedia
。
是否可以为navigator.webkitGetUserMedia
设置极低的帧速率(或根本不设置)?
有没有人能够以任何其他方式减少流的CPU使用率?
实现相同目标的任何替代方法(间隔状态捕获)也会有所帮助。
谢谢!
旁注
这是在使用DesktopCapturer的Windows上的Electron应用中获取chromeMediaSourceId
。
CPU使用率更新
stream
:6%CPU使用率captureState
:5%CPU使用率总电流:11%
目前正在根据Csaba Toth的建议努力减少#2。我应该可以通过更改画布的捕获方式来减少captureState
。完成后会更新。
对于#1,如果我无法捕获视频流,我将不得不通过优化#2来尝试将总CPU使用率限制在6%以上。
答案 0 :(得分:1)
这里有一些不必要的base64编码和操作,你抓住数据很奇怪:
dataURL = _canvas.toDataURL('image/png');
buffer = new Buffer(dataURL.split(",")[1], 'base64');
请查看QR解码器如何访问图像:https://github.com/bulldogearthday/booths/blob/master/scripts/qrdecoder.js#L1991
var canvas_qr = document.getElementById("qr-canvas");
var context = canvas_qr.getContext('2d');
qrcode.width = canvas_qr.width;
qrcode.height = canvas_qr.height;
qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height);
(软件的另一面早先对画布做了drawImage
)。现在的任务是找到一种方法,它不会不必要地将PNG数据转换为base64,然后对其进行解码。我看到建议使用这种URI编码,因为它的行数较少。但是性能明智的是不必要的编码/解码阶段。 1920x1080的PNG很大,不适用于base64内嵌。由于您无论如何都在nodejs中,请尝试使用https://github.com/niegowski/node-pngjs或类似的库来保存图像数据。
在空间和时间之间总是需要权衡,所以如果时间真的很重要,压缩率较低,你可以获得更高的性能:https://github.com/wheany/js-png-encoder
这里有一个权衡,因为base64 URI编码示例利用了浏览器的本机(C ++,快速)png编码,但随后进行了不必要的base64编码+解码。 node-pngjs将在JS land中执行PNG编码,可能不像浏览器的内部编码那样高效。最好的方法是找到一种方法来利用浏览器的编码,而无需使用base64。
早期建议
根据您展示的内容,我认为您的主要问题是您在_ctx.drawImage(_video, 0, 0);
中执行了gotStream
和其他操作。
以下是我的Progressive Web App,它也执行QR码扫描:https://github.com/bulldogearthday/booths/blob/master/scripts/app.js
请注意,在“gotStream
”(我的情况下是匿名的https://github.com/bulldogearthday/booths/blob/master/scripts/app.js#L67)中,我只将流连接到画布。
我的情况比较容易,因为我不必强制执行大小(我希望你不要硬连接那些屏幕尺寸的像素数),但我也会定期执行处理(QR码扫描尝试,每500ms)。我最初使用计时器,但是经过一些迭代/滴答后停止工作,所以从技术上讲,我发出一次超时,每次点击我重新发出一个新的。请参阅初始超时https://github.com/bulldogearthday/booths/blob/master/scripts/app.js#L209和定期重新发布:https://github.com/bulldogearthday/booths/blob/master/scripts/app.js#L231
正如你所看到的那样,我所做的“重举”只在app.scanQRCode
中,每秒只发生两次。在那里我处理画布的内容:
https://github.com/bulldogearthday/booths/blob/master/scripts/app.js#L218
我建议你以这种方式重构你的代码。因此,设置计时器每秒钟滴答或重新发出超时。然后在该部分进行捕获+保存。希望这会减轻CPU负载,尽管每秒编码1920x1080 PNG
可能会对CPU造成压力(将PNG
编码)。
(如果您想要获取单个图像,那将非常有用。如果您最终想要最终获得视频,那么我会尝试按照您的建议继续执行1s FPS视频并捕获视频流直接而不是单个图像。但对于CPU负载我的建议应该有助于恕我直言。)
在自述文件(https://github.com/bulldogearthday/booths)中,您可以看到我为getUserMedia
查看的主要来源之一:https://github.com/samdutton/simpl/blob/gh-pages/getusermedia/sources/js/main.js
我不会发出.play()
或.pause()
或其他任何内容。事实上,我的代码会等到它收到播放开始的信号(默认情况下至少自动启动):document.getElementById('qrVideo').addEventListener('playing', app.saveVideoSize, false);
https://github.com/bulldogearthday/booths/blob/master/scripts/app.js#L67我的意图是不打扰自然过程如果可能的话。在我的情况下,我以这种温和的方式检测视频大小。看看DesktopCapturer,他们也不会在自述文件https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md中的gotStream
中执行任何额外操作,如图所示,理想情况下,您只需将视频流与画布相连接即可。