
在web前端进行屏幕录制时,例如使用navigator.mediadevices.getdisplaymedia()(或旧版getuserdisplay)api捕获用户屏幕内容,一个常见的需求是同时记录用户的鼠标移动轨迹。开发者通常希望能够将每个视频帧与一个对应的鼠标位置关联起来,以便在后端进行视频编辑(例如,在视频上叠加自定义光标)或分析。
然而,直接将鼠标位置数据与视频的每一帧进行一对一的匹配存在技术障碍。WebRTC API本身并没有提供一个类似于onFrame的事件,允许开发者在每一帧被捕获时同步执行代码。此外,视频的实际帧率可能会因设备性能、浏览器实现或网络状况而异,导致录制视频的帧数与通过requestAnimationFrame等机制捕获到的鼠标事件数量不匹配。例如,尝试使用requestAnimationFrame来收集鼠标位置时,发现其收集到的数据点远少于最终视频的帧数,这表明简单的计数匹配是不可行的。
鉴于无法直接将鼠标位置与每个视频帧绑定,更稳健的方法是采用基于时间戳的同步策略。这种方法的核心思想是:我们只需要知道在视频录制过程中的某个特定时刻,鼠标位于屏幕上的哪个位置。这意味着鼠标数据和视频帧数据在时间上保持同步,而不是在帧数上保持同步。
requestAnimationFrame是浏览器提供的一个优化API,它会请求浏览器在下一次重绘之前执行指定的回调函数。这意味着requestAnimationFrame的回调与浏览器的渲染周期高度同步。即使视频录制帧率高于requestAnimationFrame的执行频率,由于某些视频帧可能只是前一帧的重复(例如,在低活动度时),requestAnimationFrame捕获的鼠标位置仍然能够准确反映用户在屏幕更新时的交互状态,避免了无效或冗余的数据。
以下是实现这一策略的具体步骤和相应的JavaScript代码示例。
在您启动MediaRecorder开始录制视频的同一时刻,记录一个起始时间戳。
let recordingStartTime = 0; // 存储录制开始时间
// ... 在您的 getUserDisplay 或 getDisplayMedia 成功获取流之后
// ... 当您准备好开始录制时
// 假设 stream 是通过 getUserDisplay/getDisplayMedia 获取的 MediaStream
const mediaRecorder = new MediaRecorder(stream, {
mimeType: 'video/webm',
videoBitsPerSecond: 3000000
});
mediaRecorder.onstart = () => {
recordingStartTime = Date.now(); // 记录录制开始的精确时间
startMouseTracking(); // 启动鼠标轨迹跟踪
console.log('录制开始,时间戳:', recordingStartTime);
};
// ... 其他 mediaRecorder 事件处理,如 ondataavailable, onstop 等
mediaRecorder.start(); // 启动录制创建一个全局变量来存储鼠标的最新位置,并通过window.addEventListener('mousemove')来更新它。然后,使用requestAnimationFrame循环来周期性地收集这些最新的鼠标位置,并附加相对时间戳。
let lastKnownMousePosition = {
mouseX: 0,
mouseY: 0,
mouseButtons: 0,
};
const mousePositions = []; // 存储所有捕获的鼠标位置数据
window.addEventListener('mousemove', (event) => {
lastKnownMousePosition = {
mouseX: event.clientX,
mouseY: event.clientY,
mouseButtons: event.buttons,
};
});
function startMouseTracking() {
const frameHandler = () => {
// 只有当 recordingStartTime 已经被设置时才记录鼠标位置
if (recordingStartTime > 0) {
const mousePosition = {
timestamp: Date.now() - recordingStartTime, // 相对录制开始的时间戳
...lastKnownMousePosition,
};
mousePositions.push(mousePosition);
// 可以在此处将 mousePosition 发送到服务器,或者累积到 mousePositions 数组中
console.log('捕获鼠标位置:', mousePosition);
requestAnimationFrame(frameHandler); // 继续调度下一次捕获
}
};
requestAnimationFrame(frameHandler); // 启动第一次捕获
}
// 当录制停止时,您可以将 mousePositions 数组发送到后端
mediaRecorder.onstop = () => {
console.log('录制停止。捕获的鼠标轨迹数据:', mousePositions);
// 在这里将 mousePositions 数组和录制的视频文件一起发送到后端
};在后端接收到视频文件和mousePositions数组后,您可以根据视频的播放时间来查找对应的鼠标位置。
示例(概念性):
// 假设后端接收到 videoFile 和 mousePositionsArray
function getMousePositionAtTime(currentTimeMs, mousePositionsArray) {
// 查找时间戳小于或等于 currentTimeMs 的最后一个鼠标位置
let foundPosition = null;
for (let i = 0; i < mousePositionsArray.length; i++) {
if (mousePositionsArray[i].timestamp <= currentTimeMs) {
foundPosition = mousePositionsArray[i];
} else {
// 因为数组是按时间排序的,一旦找到一个大于当前时间的,就可以停止
break;
}
}
return foundPosition;
}
// 在视频处理循环中,例如每处理一帧时
// let videoCurrentTimeMs = ... // 获取当前视频帧的播放时间
// let currentMousePos = getMousePositionAtTime(videoCurrentTimeMs, mousePositionsArray);
// if (currentMousePos) {
// // 在当前视频帧上绘制光标,位置为 currentMousePos.mouseX, currentMousePos.mouseY
// }通过采用基于时间戳的同步策略,您可以有效地解决WebRTC屏幕录制中鼠标轨迹与视频帧同步的难题,为后续的视频编辑和分析提供精确且可靠的数据支持。
以上就是WebRTC屏幕录制中鼠标轨迹与视频帧同步的最佳实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号