如何按屏幕录制帧率捕获鼠标坐标并存储到数组
录屏帧与鼠标坐标一一匹配的解决方案
问题根源在于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));
关键细节说明
- 坐标同步:鼠标移动事件仅更新当前坐标,不管鼠标是否移动,每帧都会记录最后一次的坐标,确保无帧遗漏。
- 时间戳匹配:记录
video.currentTime,后端解码视频时可通过帧的时间戳与坐标数组中的时间戳对应,即使帧率有波动也能精准匹配。 - 参考系转换:示例中用
clientX/clientY(相对浏览器窗口),如果需要相对录屏区域的坐标,可结合录屏流的displaySurface信息或窗口偏移量进行转换。 - 实际帧率验证:可通过
mediaStream.getVideoTracks()[0].getSettings().frameRate获取实际录制帧率,用于验证坐标数量是否与帧数一致。
内容的提问来源于stack exchange,提问作者Joel Smith
相关产品推荐
相关产品推荐

