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. 用于特定领域,不需要支持多任…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
