js录制本地摄像头下载mp4和转file文件流

前端获取本地摄像头和麦克风并录制为mp4导出其实很简单,只是可能你不太了解相关的知识点,我已经在项目中实战过。

前端获取本地摄像头麦克风,并录制视频
export class VideoRecording { // 录视频mediaRecorder: MediaRecorder | null;stream: MediaStream | null;chunks: any[];endCallback: any[];constructor() {this.mediaRecorder = null; // 录音对象this.stream = null; // 轨道this.chunks = []; // 录制缓存this.endCallback = []; // 结束回调}create() { // 创建一个录制任务return new Promise((resolve, reject) => {this.resetState();navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((stream) => {this.stream = stream;const mime = MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? "video/webm\;codecs=h264" : "video/webm";this.mediaRecorder = new MediaRecorder(stream, { mimeType: mime });resolve({format: mime === "video/webm;codecs=h264" ? 'mp4': 'webm'});}).catch((err) => {reject(err);});});}start() { // 开始return new Promise((resolve, reject) => {this.judgeMediaRecorderIs().then((mediaRecorder: MediaRecorder) => {mediaRecorder.start();mediaRecorder.addEventListener('dataavailable', (e) => {this.chunks.push(e.data);this.endCallback.forEach((resolve) => {resolve();this.endCallback.shift();});});resolve('');}).catch((err) => {reject(err);});});}stop() { // 结束return new Promise((resolve, reject) => {this.judgeMediaRecorderIs().then((mediaRecorder: MediaRecorder) => {if (mediaRecorder.state === 'inactive') {return reject({code: 0, message: '已结束'});};mediaRecorder.stop();this.stream.getTracks().forEach((track) => { track.stop(); })this.endCallback.push(resolve);}).catch((err) => {reject(err);});});}download() { // 下载return new Promise((resolve, reject) => {this.handleChunksToBolb().then((blob: Blob) => {let url = URL.createObjectURL(blob);let a = document.createElement('a');a.href = url;a.download = MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? 'video.mp4' : 'video.webm';a.click();resolve(url);}).catch((err) => {reject(err);});});}viewRecording() { // 获取本地播放urlreturn new Promise((resolve, reject) => {this.handleChunksToBolb().then((blob: Blob) => {let url = URL.createObjectURL(blob);resolve(url);}).catch((err) => {reject(err);});});}toFile() { // 录音缓存转filereturn new Promise((resolve, reject) => {this.handleChunksToBolb().then((blob: Blob) => {let filename = MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? 'video.mp4' : 'video.webm';let fileType = filename.includes('.mp4') ? 'video/mp4' : 'video/webm';resolve(new File([blob], filename, { type: fileType }));}).catch((err) => {reject(err);});});}handleChunksToBolb() { // 录音缓存转bolbreturn new Promise((resolve, reject) => {this.judgeChunksIs().then((chunks: any) => {let blob = new Blob(chunks, { type: MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? 'video/mp4' : chunks[0].type })resolve(blob);}).catch((err) => {reject(err);});});}judgeChunksIs() { // 判断是否有录音缓存return new Promise((resolve, reject) => {let chunks = this.chunks;if (chunks.length === 0) {return reject({code: 0, message: '没有录制的缓冲'});};return resolve(chunks);});}judgeMediaRecorderIs() { // 判断是否创建录制任务return new Promise((resolve, reject) => {let mediaRecorder = this.mediaRecorder;if (!mediaRecorder) { return reject({code: 0, message: '请先创建一个录制对象'}); };resolve(mediaRecorder);});}setEndCallback(callback) { // 存录音结束回调this.endCallback.push(callback);}resetState() { // 重置状态this.chunks = [];this.mediaRecorder = null;this.stream = null;}
};
实用方法
let myVideoRecording = new VideoRecording();
@params res: {format: 'mp4',  type: String; value: 'mp4' | 'webm'; 说明:当前支持的录制格式;
}
myVideoRecording.create().then((res: {format: 'mp4'}) => {// 开始录制myVideoRecording.start();// 可选择自己注册一个结束回调, 也可以调用stop()结束成功后执行下载、播放url、转filelet endRecording = () => {// 下载到本地myVideoRecording.download();// 本地播放urlmyVideoRecording.viewRecording().then((srcObject) => {});// 转file可上传到后台服务器myVideoRecording.toFile().then((file) => {});};// 存结束录音回调函数myVideoRecording.setEndCallback(endRecording);// 手动结束录屏,then后才可以下载、获取本地播放url、转file对象myVideoRecording.stop().then(() => {// 下载到本地myVideoRecording.download();// 本地播放urlmyVideoRecording.viewRecording().then((srcObject) => {});// 转file可上传到后台服务器myVideoRecording.toFile().then((file) => {});});
});

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

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

相关文章

浏览器工作原理与实践--垃圾回收:垃圾数据是如何自动回收的

在上一篇文章中,我们提到了JavaScript中的数据是如何存储的,并通过例子分析了原始数据类型是存储在栈空间中的,引用类型的数据是存储在堆空间中的。通过这种分配方式,我们解决了数据的内存分配的问题。 不过有些数据被使用之后&am…

【PCB专题】案例:Allegro怎么1:1在纸上打印出PCB板

首先我们要知道为什么我们需要1:1打印出PCB板? 为什么需要1:1打印 一般我们要1:1打印出来这个功能是在新画的器件封装验证、首板结构配合检查、多个板卡互连验证等情况下使用: 在新画了一个器件封装时,如果我们手上有实物,那么通过1:1打印出来后可以与实物器件交叉对比…

Web框架开发-Django-Form组件归类

一、Form类 创建Form类时,注意涉及到【字段】和【插件】,字段用于对用户请求数据的验证,插件用于生成HTML; 1、Django内置字段如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 …

CVE-2023-38408漏洞修复 - 升级openssl和openssh

CVE-2023-38408 OpenSSH 代码问题漏洞修复 - 升级openssl和openssh ※ 重要说明: 1、升级后会导致无法用ssh远程登录,提示“Permission denied, please try again.” 2、解决方案请查看本章节【三、解决升级后无法用ssh远程登录】 目录 CVE-2023-38408 O…

使用Docker搭建NZBGet

NZBGet是一款高效的NZB下载客户端,它支持使用NZB文件来自动下载网络上的文件,特别是BT种子文件。NZBGet能够与多个索引器和下载管理器(如Sonarr、Radarr、SABnzbd等)集成,提供稳定、快速且易于管理的下载体验。 使用D…

代码随想录算法训练营第39天| 738.单调递增的数字、968.监控二叉树

738.单调递增的数字 题目链接&#xff1a;单调递增的数字 题目描述&#xff1a;当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递增 。 解…

WebScraper网页数据爬取可视化工具使用(无需编码)

前言 Web Scraper 是一个浏览器扩展&#xff0c;可以实现无需编码即可爬取网页上的数据。只需按照规则进行配置&#xff0c;即可实现一键爬取导出数据。 安装 进入Google应用商店安装此插件&#xff0c;安装步骤如下&#xff1a; 进入Google应用商店需要外网VPN才能访问&…

C#基础复习

【namespace】 命名空间 。net有众多类&#xff0c;全放一起&#xff0c;无法快速检索到需要的类。 所以用【点】来区分&#xff0c;注意【点】不是包含关系。 解决类重名问题时&#xff0c;要用完全限定名来区分。【完整命名空间路径】 配合引用&#xff1a; 【字段】 类内部…

Android 中 调试和减少内存错误

Android 中 调试和减少内存错误 ASan 概述 官网连接&#xff1a; https://developer.android.com/ndk/guides/asan?hlzh-cn ASan API 27开始HWASan&#xff08;替换AScan&#xff09; 从 NDK r21 和 Android 10&#xff08;API 级别 29&#xff09;开始适用于 64 位 Arm 设…

微服务demo(三)nacosfeign

一、feign使用 1、集成方法 1.1、pom consumer添加依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.2.6.RELEASE</version></dependency&…

WEB APIS知识点案例总结

随机点名案例 业务分析: 点击开始按钮随机抽取数组中的一个数据,放到页面中点击结束按钮删除数组当前抽取的一个数据当抽取到最后一个数据的时候,两个按钮同时禁用(只剩最后一个数据不用抽了) 核心:利用定时器快速展示,停止定时器结束展示 <!DOCTYPE html> <html…

智慧公厕产品的特点、应用场景

随着城市化进程的加速和智能科技的不断发展&#xff0c;智慧公厕作为城市管理的重要组成部分&#xff0c;逐渐成为了现代城市的一道靓丽风景线。它的特点和应用场景备受人们关注和喜爱。 智慧公厕的特点有哪些呢&#xff1f;首先&#xff0c;它智能化的设备和感应技术为其特点…

华为昇腾认证考试内容有哪些

华为昇腾认证考试的内容主要包括理论知识和实践操作两部分。 在理论知识部分&#xff0c;考生需要掌握昇腾计算的基础知识&#xff0c;包括昇腾计算平台的架构、性能特点、应用场景等。此外&#xff0c;还需要深入理解昇腾AI框架、算子开发、模型优化等相关技术原理和应用方法…

《操作系统导论》第14章读书笔记:插叙:内存操作API

《操作系统导论》第14章读书笔记&#xff1a;插叙&#xff1a;内存操作API —— 杭州 2024-03-30 夜 文章目录 《操作系统导论》第14章读书笔记&#xff1a;插叙&#xff1a;内存操作API1.内存类型1.1.栈内存&#xff1a;它的申请和释放操作是编译器来隐式管理的&#xff0c;所…

Xcode删除原本的Git,再添加新的git

本文参考&#xff1a;Xcode怎么删除原本git,在重新设置新的git地址_ios xcode 删除原本git-CSDN博客 开发中会有一个问题。Xcode项目A 提交到Git服务器server1&#xff0c;此时项目A内部已经存在一个Git文件&#xff0c;与server1相关联。 此时你想将项目A提交到 另一个Git…

前端实现菜单搜索搜索(功能模版)

目录 前言正文 前言 总体界面如下所示&#xff1a; 正文 <template><div class"avue-searchs"click.self"handleEsc"><div class"avue-searchs__title">菜单搜索</div><div class"avue-searchs__content"…

PS从入门到精通视频各类教程整理全集,包含素材、作业等(4)复发

PS从入门到精通视频各类教程整理全集&#xff0c;包含素材、作业等 最新PS以及插件合集&#xff0c;可在我以往文章中找到 由于阿里云盘有分享次受限制和文件大小限制&#xff0c;今天先分享到这里&#xff0c;后续持续更新 PS人物数码照片处理技法视频教程 https://www.al…

Mybatis项目运行成功但是返回的数据是引用的地址

如图所示&#xff1a; 解决方法&#xff1a;是因为在实体类当中没有重写toString方法 成功输出&#xff1a;

企微获客助手到底有哪些价值?

获客助手作为企业微信官方提供的获客工具&#xff0c;在私域布局中确实展现了其强大的引流效率和便利性。这一工具通过简化传统引流过程中的复杂步骤&#xff0c;使得企业能够更高效地吸引和转化潜在客户。此外&#xff0c;获客助手还能实现不同渠道的无缝链接&#xff0c;进一…

脑机辅助推导算法

目录 一&#xff0c;背景 二&#xff0c;华容道中道 1&#xff0c;问题 2&#xff0c;告诉脑机如何编码一个正方形格子 3&#xff0c;让脑机汇总信息 4&#xff0c;观察图&#xff0c;得到启发式算法 5&#xff0c;根据启发式算法求出具体解 6&#xff0c;可视化 一&am…