【问题标题】:Electron screen recording stuck at <10fps电子屏幕录制卡在 <10fps
【发布时间】:2022-01-07 13:13:07
【问题描述】:

目标:

我想运行一个记录特定窗口约 2 分钟视频的电子应用程序。窗口是图像,而不是文本,所以我想要高清和 >=60 帧每秒。我只需要它在窗口平台上工作。捕获音频会很好,但不是我的首要任务。

我的尝试:

我查看了一些在线示例并想出了如何:

  • 我使用electron的desktopCapturer.getSources()来查找我感兴趣的具体窗口源
  • 然后我使用navigator.mediaDevices.getUserMedia() 将该窗口源转换为MediaStream
  • 然后我使用MediaRecorderMediaStream 收集记录块
  • 我将块聚合到 Blob,转换为 ArrayBuffer,然后是 Buffer
  • 由于MediaRecorder 不支持.mp4,我使用基于ffmpeg 构建的npm 包将webm 缓冲区转换为mp4 缓冲区。
  • 我使用 node 的 fs 将 webm 和 mp4 缓冲区写入 2 个文件。

这工作正常。 mp4 文件存在一些元数据问题,导致某些视频播放器无法播放,而其他视频播放器可以播放;我不太关心这个。 webm 视频播放良好。

问题:

录制的帧速率非常低。文件属性没有提到每秒帧数或比特率,这些字段只是空白。但它似乎每秒 5 帧。如果可能的话,我想要至少 30 个或更多。

console.log mediaStream 的视频轨道的帧速率为 30。我将写入文件短路,只是将 mediaStream 流式传输到 &lt;video&gt; 元素,但我仍然得到低帧,所以 MediaRecorder ,并且写入文件不负责。

简单示例:

const {desktopCapturer} = require('electron');

let source, stream, track;

desktopCapturer.getSources({types: ['window']}).then(async sources => {
    // Get the stream
    source = sources.find(source => source.name === 'My Window');
    stream = await navigator.mediaDevices.getUserMedia({
        audio: false,
        video: {
            mandatory: {
                chromeMediaSource: "desktop",
                chromeMediaSourceId: source.id,
            },
        },
    });

    // Print some info about the stream
    track = stream.getVideoTracks()[0];
    let obj = {
        settings: track.getSettings(),
        constraints: track.getConstraints(),
        capabilities: track.getCapabilities(),
    };
    console.log(JSON.stringify(obj, null, 2));

    // Project to a <video> element
    let video = document.querySelector('video');
    if (!video) {
        video = document.createElement('video');
        document.body.appendChild(video);
    }
    video.srcObject = stream;
    video.onloadedmetadata = () => video.play();
});

Track 控制台日志:

{
  "settings": {
    "aspectRatio": 1.7777777777777777,
    "deviceId": "window:4982682:0",
    "frameRate": 30,
    "height": 1440,
    "resizeMode": "crop-and-scale",
    "width": 2560
  },
  "constraints": {
    "deviceId": {
      "exact": "window:4982682:0"
    }
  },
  "capabilities": {
    "aspectRatio": {
      "max": 2560,
      "min": 0.0006944444444444445
    },
    "deviceId": "window:4982682:0",
    "facingMode": [],
    "frameRate": {
      "max": 30,
      "min": 0
    },
    "height": {
      "max": 1440,
      "min": 1
    },
    "resizeMode": [
      "none",
      "crop-and-scale"
    ],
    "width": {
      "max": 2560,
      "min": 1
    }
  }
}

Chrome 浏览器示例:

我尝试在 chrome 浏览器中做同样的事情并遇到同样的问题。所以它似乎不是电子特定的。如果我选择与使用电子记录相同的窗口,则 chrome 具有相同的

    // Run this in the dev console

    stream = await navigator.mediaDevices.getDisplayMedia();
    
    let video = document.querySelector('video');
    if (!video) {
        video = document.createElement('video');
        document.body.appendChild(video);
    }
    video.srcObject = stream;
    video.onloadedmetadata = () => video.play();

[编辑] 部分修复:

禁用窗口的“后台录制”设置后,我看到流的 fps 有了很大的提高。不过,它仍然不如内置窗口的 xbox-game-bar 录制(我正在尝试替换)那么流畅。

【问题讨论】:

    标签: javascript electron getusermedia mediastream mediadevices


    【解决方案1】:

    您对 .getUserMedia() 的调用提到了有关源设备的一些视频限制。要控制帧率,向约束对象添加

    frameRate: {min: 10, ideal: 60, max: 60 }
    

    也可以使用其他限制条件,例如大小。 See this.

    最好使用 min / Ideal / max 而不是仅仅说

     frameRate: 60
    

    如果你给出一个最小/理想/最大范围,即使捕捉无法保持更高的帧速率,你也会得到一些东西

    您在 MediaRecorder 构造函数中设置压缩视频数据流的带宽。你没有问这个。

    【讨论】:

    • 也许我误解了在线文档/解释,但我的理解是frameRate 约束对网络摄像头有效,但对屏幕截图无效。当我尝试使用它时,我得到"Unknown name of constraint detected" / "frameRate" 错误
    • 你是对的。这是一个相关的问题。 stackoverflow.com/questions/70142727/…
    • maxFrameRate,就像您链接的问题一样,确实会影响流 fps。但是当我将minFrameRate 设置为 60 或 120 时,它并没有什么不同。而且它明显比 widow 的 xbox-game-bar 录音更不稳定。
    猜你喜欢
    • 2018-07-14
    • 1970-01-01
    • 2021-06-14
    • 2012-07-02
    • 2020-03-24
    • 2020-11-21
    • 2017-03-19
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多