0

0

js怎么实现屏幕录制

小老鼠

小老鼠

发布时间:2025-08-20 08:48:02

|

618人浏览过

|

来源于php中文网

原创

屏幕录制可通过mediarecorder和getdisplaymedia api实现;2. 麦克风权限应先请求屏幕共享,再单独请求音频以避免多次弹窗;3. 优化文件大小可降低分辨率、帧率,选择vp9编码或限制时长;4. 添加水印可用canvas api绘制并捕获流,或录制后用ffmpeg.js处理;5. 错误处理需捕获用户拒绝、api不支持及录制中断等异常并给出提示。完整实现需结合安全策略与用户体验,最终方案在浏览器限制下可行但功能有限。

js怎么实现屏幕录制

屏幕录制在 JavaScript 中实现起来,直接使用原生 API 是比较困难的,因为浏览器出于安全考虑,限制了直接访问底层硬件设备的能力。不过,我们可以借助

MediaRecorder
API 和
getDisplayMedia
API 来实现一个简易的屏幕录制功能。核心思路是:先获取屏幕共享的 MediaStream,然后使用 MediaRecorder 将 MediaStream 中的数据录制下来,最后将录制的数据保存为文件。

js怎么实现屏幕录制

解决方案

以下是一个简单的 JavaScript 屏幕录制示例:

js怎么实现屏幕录制
async function startRecording() {
  try {
    const stream = await navigator.mediaDevices.getDisplayMedia({
      video: { mediaSource: "screen" },
      audio: true, // 可选,如果需要录制音频
    });

    const recorder = new MediaRecorder(stream);
    let data = [];

    recorder.ondataavailable = (event) => data.push(event.data);
    recorder.onstop = () => {
      const blob = new Blob(data, { type: "video/webm" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.style.display = "none";
      a.href = url;
      a.download = "screen-recording.webm";
      document.body.appendChild(a);
      a.click();
      window.URL.revokeObjectURL(url); // 释放 URL 对象
      stream.getTracks().forEach(track => track.stop()); // 停止所有轨道
    };

    recorder.start();
    return recorder;

  } catch (err) {
    console.error("Error accessing screen:", err);
    // 处理用户拒绝共享屏幕的情况
  }
}

async function stopRecording(recorder) {
  recorder.stop();
}

// 使用示例
let recorderInstance = null;

document.getElementById("startBtn").addEventListener("click", async () => {
  recorderInstance = await startRecording();
});

document.getElementById("stopBtn").addEventListener("click", () => {
  if (recorderInstance) {
    stopRecording(recorderInstance);
  }
});

这个代码片段首先定义了

startRecording
函数,它使用
navigator.mediaDevices.getDisplayMedia
获取屏幕共享的 MediaStream。然后,创建一个
MediaRecorder
对象,并设置
ondataavailable
onstop
事件处理程序。
ondataavailable
事件处理程序将录制的数据添加到
data
数组中,
onstop
事件处理程序将
data
数组中的数据合并为一个 Blob 对象,并创建一个下载链接,以便用户可以下载录制的文件。

stopRecording
函数简单地调用
recorder.stop()
来停止录制。

js怎么实现屏幕录制

最后,代码片段添加了两个按钮的事件监听器,分别用于启动和停止录制。

屏幕录制时如何处理麦克风权限请求?

当同时需要录制屏幕和麦克风音频时,需要在

getDisplayMedia
中同时请求视频和音频权限。但是,用户可能会先授权屏幕共享,然后才授权麦克风。在这种情况下,浏览器可能会弹出多个权限请求窗口,这可能会让用户感到困惑。

一种更好的做法是,先请求屏幕共享权限,然后在屏幕共享启动后,再请求麦克风权限。这样可以避免弹出多个权限请求窗口。

async function startRecordingWithAudio() {
    try {
        const stream = await navigator.mediaDevices.getDisplayMedia({
            video: { mediaSource: "screen" },
            audio: false // 先不请求音频
        });

        // 检查是否需要同时录制麦克风
        const shouldRecordAudio = confirm("是否同时录制麦克风?");

        let audioStream = null;
        if (shouldRecordAudio) {
            try {
                audioStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
                // 将麦克风音轨添加到屏幕共享流中
                audioStream.getTracks().forEach(track => stream.addTrack(track));
            } catch (audioErr) {
                console.error("Error accessing microphone:", audioErr);
                alert("无法访问麦克风,将只录制屏幕。");
                // 如果用户拒绝麦克风权限,可以继续只录制屏幕
            }
        }

        const recorder = new MediaRecorder(stream);
        let data = [];

        recorder.ondataavailable = (event) => data.push(event.data);
        recorder.onstop = () => {
            const blob = new Blob(data, { type: "video/webm" });
            const url = URL.createObjectURL(blob);
            const a = document.createElement("a");
            a.style.display = "none";
            a.href = url;
            a.download = "screen-recording.webm";
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            stream.getTracks().forEach(track => track.stop());
            if(audioStream){
              audioStream.getTracks().forEach(track => track.stop());
            }
        };

        recorder.start();
        return recorder;

    } catch (err) {
        console.error("Error accessing screen:", err);
    }
}

如何优化屏幕录制的文件大小?

录制的文件大小通常取决于多个因素,包括分辨率、帧率、编码格式和录制时长。

Quinvio AI
Quinvio AI

AI辅助下快速创建视频,虚拟代言人

下载
  • 降低分辨率: 降低录制的分辨率可以显著减小文件大小。可以在
    getDisplayMedia
    video
    选项中设置
    width
    height
    属性来降低分辨率。
  • 降低帧率: 降低帧率也可以减小文件大小,但可能会导致录制的视频看起来不流畅。可以在创建
    MediaRecorder
    对象时,通过设置
    mimeType
    选项来指定帧率。例如:
    new MediaRecorder(stream, { mimeType: 'video/webm; codecs=vp9', videoBitsPerSecond : 1000000 })
    ,可以尝试调整
    videoBitsPerSecond
    的值。
  • 选择合适的编码格式: 不同的编码格式具有不同的压缩率。VP9 是一种高效的视频编码格式,可以提供比 VP8 或 H.264 更好的压缩率。
  • 限制录制时长: 避免录制不必要的长时间视频。

屏幕录制过程中如何添加水印?

直接在 JavaScript 中实现复杂的水印功能比较困难,因为

MediaRecorder
API 本身并不提供直接添加水印的接口。不过,可以通过一些间接的方法来实现水印效果。

一种方法是使用 Canvas API 将水印绘制到屏幕共享的 MediaStream 中。首先,创建一个 Canvas 元素,并将水印绘制到 Canvas 上。然后,使用

captureStream
方法从 Canvas 中获取 MediaStream,并将该 MediaStream 作为
MediaRecorder
的输入。

这种方法的缺点是,水印是静态的,不能动态改变。此外,由于水印是直接绘制到屏幕上的,因此可能会影响屏幕的显示效果。

另一种方法是在录制完成后,使用视频编辑库(例如 FFmpeg.js)将水印添加到录制的文件中。这种方法的优点是,水印可以动态改变,并且不会影响屏幕的显示效果。但是,这种方法需要在客户端运行视频编辑库,这可能会增加客户端的负担。

以下是使用 Canvas API 添加水印的示例代码:

async function startRecordingWithWatermark() {
    try {
        const stream = await navigator.mediaDevices.getDisplayMedia({
            video: { mediaSource: "screen" },
            audio: true
        });

        // 创建 Canvas 元素
        const canvas = document.createElement('canvas');
        canvas.width = stream.getVideoTracks()[0].getSettings().width;
        canvas.height = stream.getVideoTracks()[0].getSettings().height;
        const ctx = canvas.getContext('2d');

        // 获取屏幕共享的视频轨道
        const videoTrack = stream.getVideoTracks()[0];

        // 创建一个 Video 元素,用于绘制屏幕共享的内容到 Canvas 上
        const video = document.createElement('video');
        video.srcObject = stream;
        video.muted = true; // 必须设置 muted 为 true,否则会报错
        await video.play(); // 必须 play,否则无法绘制

        // 定时绘制 Canvas
        function drawCanvas() {
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            // 添加水印
            ctx.font = '30px Arial';
            ctx.fillStyle = 'red';
            ctx.fillText('Watermark', 50, 50);

            requestAnimationFrame(drawCanvas);
        }

        drawCanvas();

        // 从 Canvas 中获取 MediaStream
        const canvasStream = canvas.captureStream();

        // 将屏幕共享的音频轨道添加到 Canvas Stream 中
        const audioTracks = stream.getAudioTracks();
        audioTracks.forEach(track => canvasStream.addTrack(track));

        const recorder = new MediaRecorder(canvasStream);
        let data = [];

        recorder.ondataavailable = (event) => data.push(event.data);
        recorder.onstop = () => {
            const blob = new Blob(data, { type: "video/webm" });
            const url = URL.createObjectURL(blob);
            const a = document.createElement("a");
            a.style.display = "none";
            a.href = url;
            a.download = "screen-recording.webm";
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            stream.getTracks().forEach(track => track.stop());
            canvasStream.getTracks().forEach(track => track.stop()); // 停止 canvasStream 的所有轨道
        };

        recorder.start();
        return recorder;

    } catch (err) {
        console.error("Error accessing screen:", err);
    }
}

这个示例代码首先创建了一个 Canvas 元素,并将屏幕共享的内容绘制到 Canvas 上。然后,在 Canvas 上添加水印。最后,从 Canvas 中获取 MediaStream,并将其作为

MediaRecorder
的输入。

需要注意的是,使用 Canvas API 添加水印可能会影响性能,特别是当水印比较复杂时。

如何处理屏幕录制过程中的错误?

在屏幕录制过程中,可能会发生各种错误,例如用户拒绝共享屏幕、浏览器不支持

getDisplayMedia
API、录制过程中断等等。为了提高应用程序的健壮性,需要对这些错误进行处理。

  • 处理用户拒绝共享屏幕的错误: 当用户拒绝共享屏幕时,
    getDisplayMedia
    API 会抛出一个
    DOMException
    异常。可以在
    try...catch
    块中捕获该异常,并向用户显示一条友好的错误消息。
  • 处理浏览器不支持
    getDisplayMedia
    API 的错误:
    某些旧版本的浏览器可能不支持
    getDisplayMedia
    API。可以在代码中检查
    navigator.mediaDevices.getDisplayMedia
    是否存在,如果不存在,则向用户显示一条错误消息。
  • 处理录制过程中断的错误: 录制过程中可能会因为各种原因而中断,例如网络连接中断、浏览器崩溃等等。可以在
    MediaRecorder
    对象的
    onerror
    事件处理程序中处理这些错误。
async function startRecordingWithErrorHandling() {
    try {
        const stream = await navigator.mediaDevices.getDisplayMedia({
            video: { mediaSource: "screen" },
            audio: true
        });

        const recorder = new MediaRecorder(stream);
        let data = [];

        recorder.ondataavailable = (event) => data.push(event.data);
        recorder.onstop = () => {
            const blob = new Blob(data, { type: "video/webm" });
            const url = URL.createObjectURL(blob);
            const a = document.createElement("a");
            a.style.display = "none";
            a.href = url;
            a.download = "screen-recording.webm";
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            stream.getTracks().forEach(track => track.stop());
        };

        recorder.onerror = (event) => {
            console.error("MediaRecorder error:", event.error);
            alert("录制过程中发生错误:" + event.error.name);
            // 可以根据 event.error.name 进行更详细的错误处理
        };

        recorder.start();
        return recorder;

    } catch (err) {
        console.error("Error accessing screen:", err);
        if (err.name === 'NotAllowedError') {
            alert("用户拒绝了屏幕共享请求。");
        } else if (err.name === 'NotFoundError') {
            alert("找不到可用的屏幕共享源。");
        } else {
            alert("发生未知错误:" + err.message);
        }
    }
}

总的来说,JavaScript 实现屏幕录制功能依赖于浏览器提供的 API,并且受到安全限制。虽然可以实现基本功能,但在高级功能(例如水印、实时编辑)方面存在一定的局限性。

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

557

2023.06.20

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

374

2023.07.04

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

754

2023.07.04

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

478

2023.09.01

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

454

2023.09.04

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

1031

2023.09.04

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

658

2023.09.12

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

553

2023.09.20

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.7万人学习

麻省理工大佬Python课程
麻省理工大佬Python课程

共34课时 | 5.2万人学习

【李炎恢】ThinkPHP8.x 后端框架课程
【李炎恢】ThinkPHP8.x 后端框架课程

共50课时 | 4.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号