Canvas录制视频

news2024/11/16 23:37:25

个人简介

👀个人主页: 前端杂货铺
🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js🍒Three.js🍖数据结构与算法体系教程

🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

文章目录

    • 前言
    • MediaRecorder
    • Canvas
    • 录制视频
    • 尚存问题

前言

大家好,这里是前端杂货铺。

今天我们要探讨一个新问题,如何在 Canvas 画布上录制视频并输出?

Canvas录屏

直入主题,基本技术路线:MediaRecorder录制媒体流 - Canvas绘制动画 - 导出录像视频

以上方式录制的视频还存在一些问题,我们在下文将逐步分析和解决…


MediaRecorder

MediaRecorder 是 MediaStream Recording API 提供的用来进行 媒体轻松录制的接口,他需要通过调用 MediaRecorder() 构造方法进行实例化

MediaStream 接口是一个 媒体内容的流。一个流包含几个轨道,比如视频和音频轨道

简单地说,MediaStream 是一个用于表示音频或视频流的接口,而 MediaRecorder 则是对指定的 MediaStream 进行录制的类。它们都是WebRTC(Web实时通信)的一部分,通常一起使用来实现音视频通话或录制功能

MediaRecorder() 构造函数会创建一对指定的 MediaStream 进行录制的 MediaRecorder 对象

var mediaRecorder = new MediaRecorder(stream[, options]);

参数说明:

stream: MediaStream 将要录制的流。它可以是来自于使用 navigator.mediaDevices.getUserMedia() 创建的流或者来自于 <audio>, <video> 以及 <canvas> DOM 元素

备注:navigator.mediaDevices.getUserMedia() 用于获取用户的媒体设备,如音频和视频的输入设备

options:一个字典对象,它可以包含下列属性:

  • mimeType: 为新构建的 MediaRecorder 指定录制容器的 MIME 类型。在应用中通过调用 MediaRecorder.isTypeSupported() 来检查浏览器是否支持此种 mimeType
  • audioBitsPerSecond: 指定音频的比特率
  • videoBitsPerSecond: 指定视频的比特率
  • bitsPerSecond: 指定音频和视频的比特率。此属性可以用来指定上面两个属性。如果上面两个属性只有其中之一和此属性被指定,则此属性可以用于设定另外一个属性。

备注: 如果视频/音频的比特率没有指定,视频默认采用的比特率是 2.5Mbps,但音频的默认比特率并不固定,音频的默认比特率根据采样率和轨道数自适应。

相关知识:

  • mimeType:控制文件类型,可以使用 MediaRecorder.isTypeSupported('video/webm')MediaRecorder.isTypeSupported('video/mp4') 查看浏览器支持的视频格式(目前谷歌支持 webm 而不支持 mp4)
  • 比特率:单位时间内传输或处理的比特数量(bit),它反映了数据传输的速度,比特率越高,传输速度越快

更多详细内容请参照官方文档:MediaRecorder官方文档 | MediaStream官方文档


Canvas

Canvas 是 HTML5 的新元素,它用于 图形的绘制,绘制图形需要通过脚本(通常是JavaScript)来完成。

下面我们来创建一个画布,并在画布上绘制文字:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #webm-canvas {
            width: 200px;
            height: 100px;
            border: 1px solid #d3d3d3;
        }
    </style>
</head>

<body>
    <canvas id="webm-canvas"></canvas>
</body>
<script>
    let canvas = document.getElementById("webm-canvas");
    // 创建context对象,该对象是内建的HTML5对象,拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法
    let context = canvas.getContext("2d");
    // 定义字体
    context.font="30px Arial";
    // 设置颜色
    context.fillStyle = "orange";
    // 在 canvas 上绘制实心的文本
    context.fillText("前端杂货铺", 10, 50);
</script>

</html>

在这里插入图片描述

更多详细内容请参照其他文档:HTML5-Canvas


录制视频

下面我们就使用 MediaRecorder 和 Canvas 及 DOM 操作,实现基本的 Canvas 视频录制

  • 运行代码后先点击开始录制,数秒过后点击下载录像,即可在浏览器下载录像
  • 在浏览器中打开录像,即可观看(可拖动进度条,可播放可暂停)

Canvas录制视频

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        canvas {
            box-shadow: 0 0 10px gray;
            display: block;
        }

        body {
            text-align: center;
        }

        button {
            margin-top: 20px;
        }
    </style>
</head>

<body>
    <canvas id="webm-canvas" height=500 width=500 style="margin:auto;"></canvas>
    <button onclick="startRecording()">开始录制</button>
    <button onclick="stopAndblobDownload()">下载录像</button>
    <script>
        let canvas = document.getElementById("webm-canvas");
        let context = canvas.getContext('2d');
        window.requestAnimationFrame(draw);
        var x = 0;
        var speed = 1;
        var text = "前端杂货铺";
        var fontSize = 20;

        function draw() {
            // 清空画布(否则字体移动后颜色会遗留在画布上)
            context.clearRect(0, 0, canvas.width, canvas.height);
            // 设置字体
            context.font = fontSize + "px Arial"; //设置字体大小和类型  
            context.fillStyle = "orange"; //设置文本颜色  
            context.fillText(text, x, canvas.height / 2); //绘制文本  
            // x要移动
            x += speed;
            // 如果文本达到画布边缘,改变方向  
            if (x > canvas.width - 100 || x < 0) {
                speed = -speed;
            }
            window.requestAnimationFrame(draw);
        }

        let allChunks = [];
        // 实时视频捕获画布,参数为帧率
        const stream = canvas.captureStream(60); // 60 FPS 
        // 创建一个对指定的 stream 进行录制的 MediaRecorder 对象
        const recorder = new MediaRecorder(stream, {
            mimeType: 'video/webm;codecs=vp9' // 设置媒体类型
        });
        // 当数据有效时触发的事件,数据有效时可以把数据存储到缓存区里
        recorder.ondataavailable = e => {
            console.log("TCL: e", e)
            allChunks.push(
                e.data
            );
        }
        // 结束并下载到浏览器默认位置
        function stopAndblobDownload() {
            // 结束录像
            recorder.stop();
            // createElement() 方法通过指定名称创建一个元素
            const link = document.createElement('a');
            link.style.display = 'none';
            // 创建一个 Blob 对象,用于存储二进制数据
            const fullBlob = new Blob(allChunks);
            // 创建一个包含 Blob 数据的 URL
            const downloadUrl = window.URL.createObjectURL(fullBlob);
            // 获取或设置链接的 URL 属性
            link.href = downloadUrl;
            // 点击链接时,浏览器下载文件
            link.download = `前端杂货铺${Math.random().toFixed(4)}.webm`;
            // 向节点的子节点列表的末尾添加新的子节点
            document.body.appendChild(link);
            // 模拟用户点击链接的操作
            link.click();
            // 删除 HTML 文档中的链接元素
            link.remove();
        }
        // 开始录像
        function startRecording() {
            recorder.start(10);
        }
    </script>
</body>

</html>

尚存问题

使用上面的方式对 Canvas录制视频 还存在一定的问题

1、录制的视频背景图片为黑色,没有保持画布本身的颜色

2、通过非浏览器打开视频,无法拖动进度条

在这里插入图片描述

3、MediaRecorder 原生支持 webm,不支持 avi、mp4、flv等格式

可以通过 link.download = "xxx.mp4", 但视频属性信息会丢失,也可能出现视频无法打开的问题

4、视频属性信息有丢失,无时长、数据速率和总比特率均为 0kbps,无帧速率

在这里插入图片描述

如果强行修改文件扩展名为 .mp4,则属性信息均无

以上问题还需进一步调研,请期待接下来解决方案的文章,如果屏幕前的小伙伴知道解决方案还请不吝赐教

好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!


参考资料:

  1. 百度 · 文心一言
  2. HTML5-Canvas
  3. MediaRecorder官方文档
  4. MediaStream官方文档
  5. 分享一个canvas录屏的方案【作者:KaiKai】

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1152155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI:41-基于基于深度学习的YOLO模型的玉米病害检测

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

idea使用MyBatisX插件

1.MyBatisX功能 (1).实现mapper和xml的跳转 (2).自动生成java文件&#xff0c;比如mapper、service、dao、pojo 2.安装MyBatisX插件 install后然后重启idea即可 3.使用MyBatieX实现mapper和xml跳转 &#xff08;1&#xff09;.点击mapper中的红色图标即可跳转到对应的xml方…

算法通过村第十八关-回溯|青铜笔记|什么叫回溯(初篇)

文章目录 前言从N叉树说起为什么有的问题暴力搜索也不行总结 前言 提示&#xff1a;我对你透露一个大密码&#xff0c;这是人类最古老的玩笑。往哪走&#xff0c;都是往前走。 --米兰昆德拉 回溯是非常重要的算法思想之一&#xff0c;主要解决一些暴力枚举也搞不定的问题&#…

第五章 I/O管理 五、输入/输出应用程序接口设备驱动程序接口

目录 一、应用程序接口 二、阻塞和非阻塞I/O 阻塞I/O: 非阻塞I/O: 三、设备驱动程序 一、应用程序接口 以前的统一接口不适用了&#xff0c;现在改为了几种不同的接口 二、阻塞和非阻塞I/O 阻塞I/O: 应用程序发出I/O系统调用&#xff0c;进程需转为阻塞态等待。 eg:字符…

40 深度学习(四):卷积神经网络|深度可分离卷积|colab和kaggle的基础使用

文章目录 卷积神经网络为什么要卷积卷积的具体流程池化tensorflow代码 深度可分离卷积原理介绍计算量对比代码参数计算例子 colab 和 kagglecolabkaggle如何在colab上使用kaggle的数据 卷积神经网络 卷积神经网络的基本结构 1&#xff1a; (卷积层(可选)池化层) * N全连接层 *…

保险公司【Hamilton Insurance】申请1亿美元纽交所IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于美国的保险公司Hamilton Insurance Group, Ltd&#xff08;简称&#xff1a;Hamilton Insurance&#xff09;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff…

力扣每日一题86:分隔链表

题目描述&#xff1a; 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,…

陷阱,实时IO判断避坑!

这是题面&#xff1a; 然后我写了如下代码: #include<iostream> #include<map> #include<vector> #include<algorithm> using namespace std; #define int long long int const int maxLine50010; map<char,char> mymap; int arr[maxLine]{1,2…

数据结构Demo——简单计算器

简单计算器 一、项目介绍二、技术使用三、具体代码实现1.前端部分2.后端部分 一、项目介绍 本项目实现了一个通过网页访问的简单计算器&#xff0c;它可以对带括号的加减乘除表达式进行计算并将计算结果返回给用户&#xff0c;并且可以对用户输入的表达式进行合法性判断&#…

SV-10A-4G IP网络报警非可视终端 (4G版)

SV-10A-4G IP网络报警非可视终端 &#xff08;4G版&#xff09; https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.621e3d0dpv5knb&ftt&id745728046948 产品简介&#xff1a; 通过局域网/广域网网组网的网络报警系统&#xff0c;改变传统局域网组网…

【MySql】10- 实践篇(八)

文章目录 1. 用动态的观点看加锁1.1 不等号条件里的等值查询1.2 等值查询的过程1.3 怎么看死锁&#xff1f;1.4 怎么看锁等待&#xff1f;1.5 update 的例子 2. 误删数据后怎么办?2.1 删除行2.2 误删库/表2.3 延迟复制备库2.4 预防误删库 / 表的方法2.4.1 账号分离2.4.2 制定操…

人工智能(8):Numpy的使用

1 Numpy介绍 Numpy&#xff08;Numerical Python&#xff09;是一个开源的Python科学计算库&#xff0c;用于快速处理任意维度的数组。 Numpy支持常见的数组和矩阵操作。对于同样的数值计算任务&#xff0c;使用Numpy比直接使用Python要简洁的多。 Numpy使用ndarray对象来处理…

NSGA-II 遗传多目标算法(python示例)

一、前言 最近在准备毕业论文&#xff0c;研究了一下主流的多目标算法&#xff0c;对于NSGA-II&#xff0c;网上大部分代码是全部是面向过程来实现的&#xff0c;本人更喜欢采用面向对象的方式&#xff0c;故采用python面向对象实现了一个示例&#xff0c;实现了对于二元多目标…

1400*C. Element Extermination(贪心规律)

Problem - 1375C - Codeforces 解析&#xff1a; 可以发现&#xff0c;最左端的数字&#xff0c;无论删除自己还是下一个&#xff0c;这个位置的值都不会变小。 同理&#xff0c;最右端位置的值都不会变大。 所以当最后剩余两个数字的时候&#xff0c;只有左端小于右端数字&…

STM32—PWM开发SG90舵机

目录 PWM介绍 PWM输出模式&#xff1a; ​编辑PWM占空比&#xff1a; PWM周期与频率公式&#xff1a;​编辑 SG90舵机介绍 1. 什么是舵机 2. 怎么控制舵机 SG90舵机介绍实战 1. 在 SYS 选项里&#xff0c;将 Debug 设为 Serial Wire​编辑 2. 将 RCC 里的 HSE 设置为 …

Vue的快速入门

Vue的快速入门 下载并安装vue.js Vue是一个基于JavaScript实现的框架, 要使用它就需要从[Vue官网]((https://cn.vuejs.org/)下载 vue.js 文件 第一步&#xff1a;打开Vue2官网&#xff0c;点击下图所示的“起步” 第二步&#xff1a;继续点击下图所示的“安装” 第三步&…

二叉树的遍历+二叉树的基本操作

文章目录 二叉树的操作一、 二叉树的存储1.二叉树的存储结构 二、 二叉树的基本操作1.前置创建一棵二叉树&#xff1a;1. 定义结点 2.简单的创建二叉树 2.二叉数的遍历1.前序遍历2.中序遍历3.后序遍历4.层序遍历 3.二叉树的操作1.获取树中节点的个数2.获取叶子节点的个数3.获取…

PHP的Excel导出与导入

下载地址&#xff08;注意php版本大于7.3可能会报错&#xff09; GitHub - PHPOffice/PHPExcel: ARCHIVED 解压 1、导出 Excel $data[[name>a,age>11],[name>b,age>22],[name>d,age>33], ]; $fileds["name">"名称","age"…

在Java和PostgreSQL枚举之间进行转换的通用方法

枚举类型&#xff08;enum&#xff09;是一种方便的数据类型&#xff0c;允许我们指定一个常量列表&#xff0c;对象字段或数据库列可以设置为该列表中的值。 枚举的美妙之处在于我们可以通过提供人类可读格式的枚举常量来确保数据完整性。因此&#xff0c;Java和PostgreSQL原…

MySQL 8.2 支持读写分离!

我们一直在等待的 MySQL 读/写分离功能 现在终于可以使用了&#xff01; 在规模上&#xff0c;我们在副本之间分配读取&#xff0c;但这必须在应用程序中以某种方式进行管理&#xff1a;指向在某个地方写入并在其他地方读取。 在 MySQL 8.2 中&#xff0c;MySQL Router 现在能…