You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按屏幕录制帧率捕获鼠标坐标并存储到数组

录屏帧与鼠标坐标一一匹配的解决方案

问题根源在于requestAnimationFrame的执行频率依赖浏览器前台渲染节奏,当标签页处于后台、浏览器性能受限或系统资源不足时,它会被节流(甚至降到1帧/秒),而MediaRecorder是基于屏幕流的实际录制帧率工作,两者完全不同步,导致坐标数量远少于视频帧数。

下面是确保每帧对应一组鼠标坐标的实现方案:

核心思路

通过隐藏的<video>元素播放录屏流,再用<canvas>同步捕获每一帧,同时记录当前鼠标坐标——因为视频帧的渲染会触发浏览器重绘,requestAnimationFrame的执行时机能和视频帧完全对齐,保证每捕获一帧视频就记录一组坐标。

完整代码示例

let currentMousePos = { x: 0, y: 0 };
const mouseCoords = [];
let isRecording = false;

// 实时更新当前鼠标坐标
document.addEventListener('mousemove', (e) => {
  currentMousePos = {
    x: e.clientX,
    y: e.clientY
  };
});

const constraints = {
  audio: false,
  video: {
    width: { max: 1920 },
    height: { max: 1080 },
    frameRate: { min: 60, max: 90 }
  }
};

navigator.mediaDevices.getDisplayMedia(constraints)
  .then(stream => {
    const mediaStream = stream;
    const mediaRecorder = new MediaRecorder(mediaStream, {
      mimeType: 'video/webm',
      videoBitsPerSecond: 3000000
    });

    // 创建隐藏的video元素,用于同步播放录屏流
    const video = document.createElement('video');
    video.srcObject = mediaStream;
    video.playsInline = true;
    video.muted = true;
    video.play().catch(err => console.error('视频播放失败:', err));

    // 创建canvas用于捕获视频帧
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    
    // 监听视频尺寸变化,同步canvas尺寸
    video.addEventListener('loadedmetadata', () => {
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
    });

    // 开始录制时启动帧捕获
    mediaRecorder.onstart = () => {
      isRecording = true;
      captureFrame();
    };

    // 停止录制时结束捕获,准备发送数据
    mediaRecorder.onstop = () => {
      isRecording = false;
      // 此处可将mouseCoords数组与录制的视频Blob一同发送至后端
      console.log('录制完成,坐标数量:', mouseCoords.length);
      mediaStream.getTracks().forEach(track => track.stop());
    };

    // 帧捕获与坐标记录函数
    function captureFrame() {
      if (!isRecording) return;

      // 绘制当前视频帧到canvas,确保与录屏帧同步
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

      // 记录坐标与视频时间戳(后端可通过时间戳匹配帧)
      mouseCoords.push({
        x: currentMousePos.x,
        y: currentMousePos.y,
        timestamp: video.currentTime
      });

      // 继续捕获下一帧
      requestAnimationFrame(captureFrame);
    }

    // 示例:启动录制
    mediaRecorder.start();

    // 示例:5秒后停止录制(实际场景可按需触发)
    setTimeout(() => {
      mediaRecorder.stop();
    }, 5000);
  })
  .catch(err => console.error('获取屏幕流失败:', err));

关键细节说明

  1. 坐标同步:鼠标移动事件仅更新当前坐标,不管鼠标是否移动,每帧都会记录最后一次的坐标,确保无帧遗漏。
  2. 时间戳匹配:记录video.currentTime,后端解码视频时可通过帧的时间戳与坐标数组中的时间戳对应,即使帧率有波动也能精准匹配。
  3. 参考系转换:示例中用clientX/clientY(相对浏览器窗口),如果需要相对录屏区域的坐标,可结合录屏流的displaySurface信息或窗口偏移量进行转换。
  4. 实际帧率验证:可通过mediaStream.getVideoTracks()[0].getSettings().frameRate获取实际录制帧率,用于验证坐标数量是否与帧数一致。

内容的提问来源于stack exchange,提问作者Joel Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:00:14