我使用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设置是否有效。医生们没有列出它,我也没有新的mediaDevices.getUserMedia可用。
是否可以为navigator.webkitGetUserMedia设置极低的帧速率(或任何帧速率)
是否有人能够以任何其他方式减少流的CPU使用量?
实现相同目标的任何替代方法(间隔上的状态捕获)也会有帮助。
谢谢!
边注
这是在Windows上的一个电子应用程序中,使用DesktopCapturer获取chromeMediaSourceId。
关于CPU使用的更新
stream的成本: 6%的CPU使用率captureState:5%的CPU使用率总电流: 11%
目前正在根据Csaba Toth迄今为止的建议减少#2。我应该能够通过改变画布捕获的方式来减少captureState。会在做完后更新。
对于#1,如果我无法避免捕获视频流,我将不得不尝试通过优化#2将总的CPU使用率限制在略高于6%。
发布于 2016-07-11 03:09:17
这里有一些不必要的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编码,因为它的行数较少。但就性能而言,必须的编码/解码阶段是不可取的。1920x1080PNGs很大,不适合base64内嵌。由于您是在nodejs中,所以尝试使用https://github.com/niegowski/node-pngjs或类似的库来保存图像数据。
在空间和时间之间总是有一种权衡,所以如果时间真的与较低的压缩有关,那么您可以拥有更高的性能:https://github.com/wheany/js-png-encoder
这里有一个折衷方案,因为base64 URI编码示例利用了浏览器的本机(C++,快速) png编码,然后执行不必要的base64 encodeing+decoding。节点pngjs将在JS域执行PNG编码,这可能不像浏览器的内部编码那样具有性能。最好是找到一种方法来利用浏览器的编码,而不需要base64。
较早的建议
根据您显示的内容,我认为您的主要问题是在gotStream中执行gotStream和其他操作。
这里是我的一个渐进Web,它也执行QR代码扫描:https://github.com/bulldogearthday/booths/blob/master/scripts/app.js注意到,在"gotStream“(在我的例子中是https://github.com/bulldogearthday/booths/blob/master/scripts/app.js#L67)中,我只将流连接到画布上。
我的情况更简单,因为我不需要强制执行大小(我希望您不要硬连接那些屏幕大小像素数),但我也定期执行处理(QR代码扫描尝试,每500毫秒)。我最初使用的是计时器,但在迭代/滴答之后就停止了工作,所以从技术上讲,我只发出一个超时,每次碰到它,我就重新发出一个新的超时。参见初始超时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
我建议你用这种方式重组你的代码。所以设置一个计时器,每秒钟滴答一次,或者像我一样重新发布超时。然后执行该部分中的capture+save。希望这将减轻CPU负载,尽管每秒编码一次1920x1080 PNG可能会给CPU带来压力(会有PNG编码)。
(这是有益的,如果你想要个人图像。如果你想最终得到一个视频,那么我会尝试按照你的建议执行1SFPS视频,直接捕获视频流而不是单个图像。但是对于CPU负载,我的建议应该有助于IMHO。)
在自述文件(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中执行任何额外的操作,理想情况下,您只需将视频流与画布连接起来。
https://stackoverflow.com/questions/38243490
复制相似问题