借助浏览器实现一个录屏插件?

说在前面

🎈不知道大家平时都是使用什么录屏软件呢?有没有想过只用JavaScript我们也可以快速实现一个录屏插件?

准备工作

开始写代码前我们需要先了解一下以下几点:

1、getDisplayMedia

navigator.mediaDevices.getDisplayMedia() 是一种基于Web的API,它允许网站在获得用户同意的情况下,捕获用户的屏幕或屏幕的特定部分作为媒体流。这个API是Media Capture and Streams API的一部分,通常用于实现屏幕共享功能,例如远程协作、视频会议或直播。

基本用法

getDisplayMedia() 方法返回一个Promise,该Promise解析为一个MediaStream对象,其中包含屏幕捕获的数据。使用此方法的基本步骤如下:

    1. 调用 getDisplayMedia() 并传入配置对象,指定所需的媒体类型和可选的约束条件。
    1. 处理Promise解析后的MediaStream对象,例如将其用作MediaRecorder的源或显示在<video>元素中。
if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
  const displayMediaOptions = {
    video: {
      cursor: "always" // 捕获鼠标指针
    },
    audio: false // 不捕获音频
  };

  navigator.mediaDevices.getDisplayMedia(displayMediaOptions)
    .then(stream => {
      // 屏幕捕获成功,'stream' 包含屏幕的媒体流
    })
    .catch(error => {
      // 捕获屏幕失败
      console.error("Error: ", error);
    });
}
重要特性
  • 用户授权:出于安全和隐私的考虑,浏览器要求用户明确授权才能进行屏幕捕获。
  • 异步操作getDisplayMedia() 是异步的,返回一个Promise对象。
  • 媒体类型:可以捕获视频和/或音频,具体取决于getDisplayMedia()调用中的配置选项。
  • 浏览器兼容性:不同的浏览器可能有不同的实现和支持程度,需要检查navigator.mediaDevices.getDisplayMedia是否存在。
安全和隐私
  • 屏幕捕获是一个敏感操作,因为它可能涉及到捕获用户的敏感信息。因此,浏览器会要求用户明确授权。
  • 网站在使用getDisplayMedia()时应该明确告知用户,并在获得用户同意后进行。
应用场景
  • 视频会议:用户可以共享他们的屏幕或应用程序窗口,以便在远程会议中展示内容。
  • 直播:游戏直播者可以共享他们的游戏画面。
  • 远程支持:技术支持人员可以请求访问用户的屏幕来帮助解决问题。

getDisplayMedia() 提供了一种强大的方式,允许Web应用以用户控制的方式捕获和使用屏幕内容。

2、快速开发一个插件

可以通过脚手架快速生成一个插件基本框架。

安装jyeontu脚手架
npm install jyeontu
使用脚手架快速创建新项目
jyeontu create

选择 Chrome 插件模板 即可

初始化
npm run init
打包
npm run build

插件开发

目标

  • 1、在浏览器中页面右键菜单加上开始录屏按钮

  • 2、点击开始录屏按钮后弹出新页面选择录取的屏幕

  • 3、结束录屏后输出视频文件

功能实现

1、浏览器右键菜单添加按钮
const id = "screenRecording"; //generateRandomString(8);
chrome.contextMenus.create({
  title: "开始录屏", //菜单的名称
  id: id, //一级菜单的id
  contexts: ["page"], // page表示页面右键就会有这个菜单,如果想要当选中文字时才会出现此右键菜单,用:selection
});

2、监听右键菜单点击事件

这里直接借用百度首页做个中间页面来触发录屏事件😀😀😀

chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId == id) {
    var createData = {
      url: "https://baidu.com?isStartMediaRecorder=1",
      // url: chrome.runtime.getURL("recorder.html"),
      type: "normal",
      top: 200,
      left: 300,
      width: 1300,
      height: 800,
    };
    // 创建(打开)一个新的浏览器窗口,可以提供大小、位置或默认 URL 等可选参数
    chrome.windows.create(createData);
  }
});
3、判断是否录屏弹窗

直接判断路径参数isStartMediaRecorder即可

localStorage.setItem("isMediaRecorderEnd", false);
const url = new URL(location.href);
const isStartMediaRecorder = url.searchParams.get("isStartMediaRecorder");
if (isStartMediaRecorder) {
  document.body.style.display = "flex";
  document.body.innerHTML = `<div
    style="
      font-size: large;
      margin: auto;
      font-weight: bold;
      text-align: center;
    "
  >
    录制中
  </div>`;
  startMediaRecorder();
}
4、开始录屏
function startRecorder(stream) {
  var mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9")
    ? "video/webm; codecs=vp9"
    : "video/webm";
  var mediaRecorder = new MediaRecorder(stream, { mimeType: mime }); // 录制

  var chunks = [];
  mediaRecorder.addEventListener("dataavailable", function (e) {
    chunks.push(e.data);
  });

  // 监听用户取消屏幕共享
  stream.getTracks().forEach((track) => {
    track.addEventListener("ended", function (e) {
      console.log("轨道结束: ", e);
      // 用户取消屏幕共享,执行清理操作
      mediaRecorder.stop(); // 停止录制
    });
  });

  mediaRecorder.start(); // 手动启动录制
}
function startMediaRecorder() {
  navigator.mediaDevices
    .getDisplayMedia({
      video: true,
    })
    .then((stream) => {
      startRecorder(stream);
    })
    .catch((err) => {
      console.warn(err);
      localStorage.setItem("isMediaRecorderEnd", true);
    });
}
5、录屏结束

监听录屏结束事件,并使用a标签将录制视频下载到本地。

function getFormattedCurrentTime() {
  const now = new Date(); // 获取当前时间
  const year = now.getFullYear(); // 年份
  const month = (now.getMonth() + 1).toString().padStart(2, "0"); // 月份,加1因为月份是从0开始的
  const day = now.getDate().toString().padStart(2, "0"); // 日期
  const hours = now.getHours().toString().padStart(2, "0"); // 小时
  const minutes = now.getMinutes().toString().padStart(2, "0"); // 分钟
  const seconds = now.getSeconds().toString().padStart(2, "0"); // 秒
  return `${year}${month}${day}${hours}${minutes}${seconds}`;
}

mediaRecorder.addEventListener("stop", function () {
  var blob = new Blob(chunks, { type: "video/webm" }); // 确保Blob的MIME类型正确
  var url = URL.createObjectURL(blob);
  var a = document.createElement("a");
  a.href = url;
  a.download = getFormattedCurrentTime() + "-video.webm";
  a.click();
  setTimeout(() => {
    localStorage.setItem("isMediaRecorderEnd", true);
  }, 200);
});

插件使用

下载

下载地址:https://gitee.com/zheng_yongtao/chrome-plug-in/blob/master/screenRecording/screenRecording.zip

安装

下载解压后导入chrome:chrome://extensions/

选择解压后的文件夹即可

源码

🔎源码地址:https://gitee.com/zheng_yongtao/chrome-plug-in/tree/master/screenRecording

⭐⭐⭐欢迎star⭐⭐⭐

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

  • 68
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用JavaCv实现功能,需要使用FFmpeg进行视频编码,以下是一个简单的实现示例: 首先,需要引入JavaCv和FFmpeg的库文件,例如: ```xml <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>ffmpeg</artifactId> <version>4.4</version> </dependency> ``` 然后,创建一个FFmpegFrameRecorder对象,设置视频编码器、视频格式、视频帧率等参数: ```java FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("output.mp4", width, height); recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); recorder.setFormat("mp4"); recorder.setFrameRate(fps); recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); recorder.start(); ``` 接着,使用Java.awt.Robot类进行幕捕获,获取幕上的图像: ```java Robot robot = new Robot(); Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); BufferedImage image = robot.createScreenCapture(screenRect); ``` 将图像转换为JavaCv的Frame对象,写入到视频文件中: ```java Frame frame = converter.convert(image); recorder.record(frame); ``` 最后,当完成时,需要停止制并释放资源: ```java recorder.stop(); recorder.release(); ``` 完整的代码示例如下: ```java import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.javacv.FFmpegFrameRecorder; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter; import java.awt.*; import java.awt.image.BufferedImage; public class ScreenRecorder { public static void main(String[] args) throws Exception { int width = 1920; int height = 1080; int fps = 30; FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("output.mp4", width, height); recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); recorder.setFormat("mp4"); recorder.setFrameRate(fps); recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); recorder.start(); Java2DFrameConverter converter = new Java2DFrameConverter(); Robot robot = new Robot(); Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); long startTime = System.currentTimeMillis(); while (System.currentTimeMillis() - startTime < 60 * 1000) { BufferedImage image = robot.createScreenCapture(screenRect); Frame frame = converter.convert(image); recorder.record(frame); } recorder.stop(); recorder.release(); } } ``` 注意,由于幕需要操作系统的权限,所以需要以管理员身份运行程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JYeontu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值