vue3实现录音与录像上传功能
录音
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import useInject from '@/utils/useInject';const props: any = defineProps<{params?: any;
}>();const recObj: any = reactive({blob: null,
});const { $global, $fn } = useInject();const recBtnDom: any = ref(null);
const playerDom: any = ref(null);onMounted(() => {// microphone 麦克风权限// camera 相机权限// geolocation 地理位置信息// notifications 网站显示桌面通知权限// navigator.mediaDevices.getUserMedia({ audio: true }).then() 麦克风权限// navigator.mediaDevices.getUserMedia({ video: true }).then() 摄像头权限// navigator.geolocation.getCurrentPosition(callback) 地理位置权限// Notification.requestPermission().then() 通知权限navigator.permissions.query({ name: 'microphone' }).then((res) => {if (res.state === 'granted') {// $global.tipsfn({ type: 'ok', con: '已授权录音' });}else{}});if (navigator.mediaDevices?.getUserMedia) {let chunks: any = [];const constraints = { audio: true };navigator.mediaDevices.getUserMedia(constraints).then((stream) => {console.log('授权成功!');const mediaRecorder = new MediaRecorder(stream);$fn.As.stopTouch(recBtnDom.value);recBtnDom.value.onpointerdown = () => {if (mediaRecorder.state === 'recording') {mediaRecorder.stop();recBtnDom.value.textContent = 'record';$global.tipsfn({ type: 'ok', con: '录音结束!' });} else {mediaRecorder.start();$global.tipsfn({ type: 'ok', con: '录音中...' });recBtnDom.value.textContent = 'stop';}console.log('录音器状态:', mediaRecorder.state);};mediaRecorder.ondataavailable = (e: any) => {chunks.push(e.data);};mediaRecorder.onstop = (e: any) => {recObj.blob = new Blob(chunks, {type: 'audio/ogg; codecs=opus',});console.log(666.10001, '录音文件blob', chunks, recObj.blob);chunks = [];var audioURL = window.URL.createObjectURL(recObj.blob);playerDom.value.src = audioURL;};},() => {$global.tipsfn({ type: 'err', con: '授权失败!' });});} else {$global.tipsfn({ type: 'err', con: '浏览器不支持 getUserMedia' });}
});
function uprec() {if (recObj.blob) {var reader = new FileReader();reader.readAsDataURL(recObj.blob);reader.onload = function () {$fn.useApiFiles().request({data: {dir: 'chat/chat',uid: $fn.As.Uuid('CR'),ext: '.ogg',data: reader.result,},}).then((res: any) => {console.log(666.789, res);props?.params?.fn(res);}).catch((err: any) => {$global.tipsfn({ type: 'err', con: err });});};}
}
</script><template><div class="as-ogg-area"><div class="as-ogg-show-area"><audio ref="playerDom" controls></audio></div><div class="as-btn-area"><button ref="recBtnDom">record</button><button @click="uprec">提交</button></div></div>
</template><style scoped>
.as-ogg-area {width: 100%;height: 100%;display: flex;flex-direction: column;
}
.as-ogg-show-area {flex-grow: 1;width: 100%;height: 100%;overflow: hidden;
}
.as-ogg-show-area > audio {width: 100%;height: 100%;
}
.as-btn-area {text-align: center;height: auto;
}
.as-btn-area > button {user-select: none;padding: 5px 12px;margin: 15px 5px 0 5px;
}
</style>
录像
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import useInject from '@/utils/useInject';const props: any = defineProps<{params?: any;
}>();const { $global, $fn } = useInject();const webmObj: any = reactive({stat: 0,blob: null,dataChunks: [],newRecorder: null,
});const startBtn: any = ref(null);
const stopBtn: any = ref(null);
const downBtn: any = ref(null);
const preVideo: any = ref(null);
const recVideo: any = ref(null);onMounted(() => {navigator.permissions.query({ name: 'camera' }).then((res) => {if (res.state === 'denied') {// $global.tipsfn({ type: 'err', con: '已拒绝授权录像' });}});// 开始录制function startRecording(stream: any, lengthInMS: any = null) {webmObj.newRecorder = new MediaRecorder(stream);webmObj.newRecorder.ondataavailable = (event: any) => {let data = event.data;webmObj.dataChunks.push(data);};webmObj.newRecorder.start(1000);console.log(webmObj.newRecorder.state + ' start to recording .....');}stopBtn.value.addEventListener('pointerdown', () => {webmObj.stat = 0;// close the recordingrecVideo.value.srcObject.getTracks().forEach((track: any) => track.stop());webmObj.newRecorder.stop();// Play recorded videowebmObj.blob = new Blob(webmObj.dataChunks, { type: 'video/webm' });console.log(666.30003,'视频数据Blob',webmObj.dataChunks,webmObj.blob);preVideo.value.src = URL.createObjectURL(webmObj.blob);// Save download video, click the download button, you can download itdownBtn.value.href = preVideo.value.src;downBtn.value.download = 'RecordedVideo.webm';});startBtn.value.addEventListener('pointerdown', () => {webmObj.stat = 1;// get the streamnavigator.mediaDevices.getUserMedia({audio: true,video: true,}).then((stream) => {// set the stream to left videorecVideo.value.srcObject = stream;// set the stream to <a> for downloaddownBtn.value.href = stream;// captureStream: which is streaming a real-time capture of the content being rendered in the media element.// A MediaStream object which can be used as a source for audio or video data by other mediarecVideo.value.captureStream =recVideo.value.captureStream ||recVideo.value.mozCaptureStream;startRecording(recVideo.value.captureStream());}).catch((err) => {console.log('recording error: ', err);});});
});
function upvideo() {if (webmObj.blob) {var reader = new FileReader();reader.readAsDataURL(webmObj.blob);reader.onload = function () {$fn.useApiFiles().request({data: {dir: 'chat/chat',uid: $fn.As.Uuid('CV'),ext: '.webm',data: reader.result,},}).then((res: any) => {console.log(666.789, res);props?.params?.fn(res);}).catch((err: any) => {$global.tipsfn({ type: 'err', con: err });});};}
}
</script><template><div class="as-webm-area"><div class="as-webm-show-area"><video v-show="!webmObj.stat" ref="preVideo" controls></video><video v-show="webmObj.stat" ref="recVideo" autoplay muted></video></div><div class="as-btn-area"><button ref="startBtn">开始录制</button><button ref="stopBtn">停止录制</button><button ref="downBtn">下载</button><button @click="upvideo">提交保存</button></div></div>
</template><style scoped>
.as-webm-area {width: 100%;height: 100%;display: flex;flex-direction: column;
}
.as-webm-show-area {flex-grow: 1;width: 100%;height: 100%;overflow: hidden;
}
.as-webm-show-area > video {width: 100%;height: 100%;
}
.as-btn-area {text-align: center;height: auto;
}
.as-btn-area > button {user-select: none;padding: 5px 12px;margin: 15px 5px 0 5px;
}
</style>
相关文章:
vue3实现录音与录像上传功能
录音 <script setup lang"ts"> import { onMounted, reactive, ref } from vue; import useInject from /utils/useInject;const props: any defineProps<{params?: any; }>();const recObj: any reactive({blob: null, });const { $global, $fn } …...
PHP小方法
一、随机生成姓名 二、随机获取身份证 三、随机获取手机号 四、随机获取省 五、通过身份证获取生日和性别 六、通过身份证获取年龄 七、获取访问IP 八、获取访问URL地址 九、陆续增加 //一、随机生成姓名 function generateName(){$arrXing getXingList();$numbXing …...
gulimall-search P125 springboot整合elasticsearch版本冲突
一、问题 spring-boot.version 2.2.4.RELEASE,在gulimall-search pom.xml中添加elasticsearch.version 7.4.2后,发现出现如下问题:elasticsearch版本是springboot引入的6.8.6,没有变为7.4.2。 二、原因 在gulimall-search 的pom文件中&#…...
如何在Coze中实现Bot对工作流的精准调用(如何提高Coze工作流调用的准确性和成功率)
文章目录 📖 介绍 📖🏡 演示环境 🏡📒 工作流(workflow)📒📝 创建设计工作流📝 添加工作流📝 调用工作流⚓️ 相关链接 ⚓️📖 介绍 📖 在使用Coze平台创建智能Bot时,您可能会遇到一个常见问题:即便添加了正确的工作流,Bot却没有按照预期调用它们。…...
毫米波雷达阵列天线设计综合1(MATLAB仿真)
1 天线设计目标 毫米波雷达探测目标的距离、速度和角度,其中距离和角度和天线设计相关性较强。天线增益越高,则根据雷达方程可知探测距离越远;天线波束越窄,则角度分辨率越高;天线副瓣/旁瓣越低,则干扰越少…...
Freemarker
Freemarker简介 Freemarker是一个用Java语言编写的模板引擎,用于基于模板和数据生成文本输出。它可以用于生成HTML网页、XML文档、电子邮件、配置文件等任何格式的文本。Freemarker将业务逻辑与表示逻辑分离,使得开发人员可以专注于功能实现,…...
基于Zero-shot实现LLM信息抽取
基于Zero-shot方式实现LLM信息抽取 在当今这个信息爆炸的时代,从海量的文本数据中高效地抽取关键信息显得尤为重要。随着自然语言处理(NLP)技术的不断进步,信息抽取任务也迎来了新的突破。近年来,基于Zero-shot&#x…...
【python】tkinter GUI编程经典用法,Label标签组件应用实战详解
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
国产操作系统上给麒麟虚拟机安装virtualbox增强工具 _ 统信 _ 麒麟 _ 中科方德
原文链接:国产操作系统上给麒麟虚拟机安装virtualbox增强工具 | 统信 | 麒麟 | 中科方德 Hello,大家好啊!昨天给大家带来了一篇在国产操作系统上给VirtualBox中的Win7虚拟机安装增强工具的文章,今天我们将继续深入,介绍…...
(delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第3节(特定类约束)
14.3.2 特定类约束 如果您的泛型类需要使用某个特定子集的类(特定层次结构),则可能需要根据给定基类指定约束。 例如,如果您声明: typeTCompClass<T: TComponent> class 则此泛型类的实例仅适用于组…...
【postgresql初级使用】视图上的触发器instead of,替代计划的rewrite,实现不一样的审计日志
instead of 触发器 专栏内容: postgresql使用入门基础手写数据库toadb并发编程 个人主页:我的主页 管理社区:开源数据库 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 文章目录 inst…...
window.setInterval(func,interval)定时器
window.setInterval()是JavaScript中的方法,用于在指定的时间间隔重复执行某个函数或代码块。它接受两个参数,第一个参数是要执行的函数或代码块,第二个参数是时间间隔(以毫秒为单位)。 以下是使用window.setInterval…...
Einstein Summation 爱因斯坦求和 torch.einsum
Einstein Summation 爱因斯坦求和 torch.einsum flyfish 理解爱因斯坦求和的基本概念和语法,这对初学者来说可能有一定难度。对于不熟悉该表示法的用户来说,可能不如直接的矩阵乘法表达式易于理解。 整个思路是 向量的点积 -》矩阵乘法-》einsum 向…...
TCP攻击是怎么实现的,如何防御?
TCP(Transmission Control Protocol)是互联网协议族中的重要组成部分,用于在不可靠的网络上提供可靠的数据传输服务。然而,TCP协议的一些特性也使其成为攻击者的目标,尤其是DDoS(Distributed Denial of Ser…...
Chrome DevTools开发者调试工具
Chrome DevTools 是一个功能强大的网页开发工具,集成在谷歌浏览器中,帮助开发者调试和优化网页应用。以下是详细的功能说明和使用技巧: 1. 打开 DevTools 快捷键:按下 F12 或 CtrlShiftI(Windows/Linux)或…...
产品创新管理:从模仿到引领,中国企业的创新之路
一、引言 在全球化竞争日益激烈的今天,科技创新已成为推动国家经济增长和社会进步的关键动力。中国自改革开放四十年来,在科技创新领域取得了举世瞩目的成就,从跟踪模仿到自主研发,再到自主创新、开放创新和协同创新并举…...
Android 日志实时输出
开发中如果只是单纯的应用开发,Android studio基本上可以满足,但是如果应用和系统联调那就得用logcat实时输出了,我这里都是总结的实用经验,没那么多花里胡哨 Android 日志实时输出 1、输出 android log //分步,进入s…...
JavaEE初阶---多线程编程(一.线程与进程)
目录 🤣一.线程与进程的概念与联系: 进程的基本概念: 线程的基本概念: 进程和线程的区别与联系: 🙃代码执行实列: 1.通过继承Thread父类来实现多线程 2.通过实现Runnable接口来实现多线程…...
react+vite创建
要在本地初始化一个结合了React和Vite的项目,你可以遵循以下步骤: 1、安装Node.js: 确保你的机器上已安装了Node.js。如果未安装,请前往Node.js官网下载并安装。 2、使用终端或命令提示符: 打开你的终端(…...
软考 系统架构设计师系列知识点之杂项集萃(29)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(28) 第46题 以下描述中,( )不是嵌入式操作系统的特点。 A. 面向应用,可以进行裁剪和移植 B. 用于特定领域,不需要支持多任…...
[Qt开发]当我们在开发兼容高分辨率和高缩放比、高DPI屏幕的软件时,我们在谈论什么。
前言 最近在开发有关高分辨率屏幕的软件,还是做了不少尝试的,当然我们也去网上查了不少资料,但是网上的资料也很零碎,说不明白,这样的话我就做个简单的总结,希望看到这的你可以一次解决你有关不同分辨率下…...
uniapp视频组件层级太高,解决方法使用subNvue原生子体窗口
目录 前言 先看一下uniapp官网的原话: subNvue的一些参数介绍 subNvues使用方法: 绑定id 显示 subNvue 弹出层 subNvue.show() 参数信息 subNvue.hide() 参数信息 在使用subNvue 原生子体窗口 遇到的一些问题 前言 nvue 兼容性 以及使用方式 控…...
java项目使用jsch下载ftp文件
pom <dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version> </dependency>demo1:main方法直接下载 package com.example.controller;import com.jcraft.jsch.*; im…...
指针(初阶1)
一.指针是什么 通俗的讲,指针就是地址,其存在的意义就像宾馆房间的序号一样是为了更好的管理空间。 如下图: 如上图所示,指针就是指向内存中的一块空间,也就相当于地址 二.一个指针的大小是多少 之前我们学习过&#x…...
MySQL实体类框架
实现mysql数据库的增删改查功能 import com.mchange.v2.collection.MapEntry; import lombok.Data; import org.junit.jupiter.api.Test;import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.*; import java.sql.*; …...
数据结构之初始泛型
找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:数据结构(Java版) 目录 深入了解包装类 包装类的由来 装箱与拆箱 面试题 泛型 泛型的语法与使用…...
【网络编程开发】7.TCP可靠传输的原理
7.TCP可靠传输的原理 TCP实现可靠传输的原理主要基于序列号和确认应答、超时重传、滑动窗口、连接管理机制以及拥塞控制等多重机制。 TCP(Transmission Control Protocol),即传输控制协议,是网络通信中的一种重要协议࿰…...
视觉SLAM十四讲:从理论到实践(Chapter8:视觉里程计2)
前言 学习笔记,仅供学习,不做商用,如有侵权,联系我删除即可 一、目标 1.理解光流法跟踪特征点的原理。 2.理解直接法是如何估计相机位姿的。 3.实现多层直接法的计算。 特征点法存在缺陷: 二、光流(Optical Flow) …...
C语言过度C++语法补充(面向对象之前语法)
目录 1. C相较于C语言新增的语法 0. C 中的输入输出 1. 命名空间 1. 我们如何定义一个命名空间? 2. 如何使用一个命名空间 3. 命名空间中可以定义什么? 4. 在 相同或者不同 的文件中如果出现 同名的命名空间 会如何? 5. 总结~~撒花~~…...
类和对象(二)(C++)
初始化列表 class Date{public:Date(int year, int month, int day){_year year;_month month;_day day;}private:int _year;int _month;int _day;}; 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化…...
门户网站设计思路/个人优秀网页设计
5G的核心应用是物联网、车联网、大数据的采集等应用领域,其中手机3D摄像头、激光雷达、无人驾驶传感器等器件,实际应用中往往是工作在窄脉冲大电流的工作条件下。例如,手机3D 摄像头的核心器件是VCSEL的半导体激光器阵列,在一个很…...
南昌做购物网站的公司/下载百度极速版免费安装
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录10/24 915. 分割数组10/25 934. 最短的桥10/26 862. 和至少为 K 的最短子数组10/27 1822. 数组元素积的符号10/28 907. 子数组的最小值之和10/29 1773. 统计匹配检索规则的物…...
网站日记在哪里看/百度网址怎么输入?
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼现在入手一个项目,大概是JSP传来一个JSON串,然后H5页面再用ajax调用jsp,这边我想先用jsp写一些死的数据,但是不知道怎么写,网上搜了很多都不行。大概是这样的:…...
建站网站/北京网站外包
a.如果备份的数据库可以访问,那么执行执行生产转化脚本:select set newname for datafile || file# || to ||replace( name,/old/data/path,/new/data/path ) || ; from v$datafile;b.如果备份的数据库不可以访问,可以trace控制文件内容&a…...
主题之家wordpress/百度点击器找名风
前几天有朋友问到歌词滚动应该怎么做,针对歌词滚动这个功能做了一个简单的案例,仅供参考,大家如果有更好的做法记得call我们一下!按照惯例,我们先看一下这个效果是怎样的点这里预览:https://o0piel.axshare…...
国外网站设计网站/网站推广平台搭建
最近着迷上了 Python用Python给小宝做的数学算数口算练习程序(2015年1月添加四则运算)!给小宝做的口算游戏:#用Python给小宝做的数学算数口算练习程序(2015年1月添加四则运算)!#给小宝做的口算游戏:import stringimport randominput11nums10num0righ1t0 …...