当前位置: 首页 > news >正文

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后&#xff0c;发现出现如下问题&#xff1a;elasticsearch版本是springboot引入的6.8.6&#xff0c;没有变为7.4.2。 二、原因 在gulimall-search 的pom文件中&#…...

如何在Coze中实现Bot对工作流的精准调用(如何提高Coze工作流调用的准确性和成功率)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 工作流(workflow)📒📝 创建设计工作流📝 添加工作流📝 调用工作流⚓️ 相关链接 ⚓️📖 介绍 📖 在使用Coze平台创建智能Bot时,您可能会遇到一个常见问题:即便添加了正确的工作流,Bot却没有按照预期调用它们。…...

毫米波雷达阵列天线设计综合1(MATLAB仿真)

1 天线设计目标 毫米波雷达探测目标的距离、速度和角度&#xff0c;其中距离和角度和天线设计相关性较强。天线增益越高&#xff0c;则根据雷达方程可知探测距离越远&#xff1b;天线波束越窄&#xff0c;则角度分辨率越高&#xff1b;天线副瓣/旁瓣越低&#xff0c;则干扰越少…...

Freemarker

Freemarker简介 Freemarker是一个用Java语言编写的模板引擎&#xff0c;用于基于模板和数据生成文本输出。它可以用于生成HTML网页、XML文档、电子邮件、配置文件等任何格式的文本。Freemarker将业务逻辑与表示逻辑分离&#xff0c;使得开发人员可以专注于功能实现&#xff0c…...

基于Zero-shot实现LLM信息抽取

基于Zero-shot方式实现LLM信息抽取 在当今这个信息爆炸的时代&#xff0c;从海量的文本数据中高效地抽取关键信息显得尤为重要。随着自然语言处理&#xff08;NLP&#xff09;技术的不断进步&#xff0c;信息抽取任务也迎来了新的突破。近年来&#xff0c;基于Zero-shot&#x…...

【python】tkinter GUI编程经典用法,Label标签组件应用实战详解

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…...

国产操作系统上给麒麟虚拟机安装virtualbox增强工具 _ 统信 _ 麒麟 _ 中科方德

原文链接&#xff1a;国产操作系统上给麒麟虚拟机安装virtualbox增强工具 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;昨天给大家带来了一篇在国产操作系统上给VirtualBox中的Win7虚拟机安装增强工具的文章&#xff0c;今天我们将继续深入&#xff0c;介绍…...

(delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第3节(特定类约束)

14.3.2 特定类约束 ​ 如果您的泛型类需要使用某个特定子集的类&#xff08;特定层次结构&#xff09;&#xff0c;则可能需要根据给定基类指定约束。 ​ 例如&#xff0c;如果您声明&#xff1a; typeTCompClass<T: TComponent> class​ 则此泛型类的实例仅适用于组…...

【postgresql初级使用】视图上的触发器instead of,替代计划的rewrite,实现不一样的审计日志

instead of 触发器 ​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 文章目录 inst…...

window.setInterval(func,interval)定时器

window.setInterval()是JavaScript中的方法&#xff0c;用于在指定的时间间隔重复执行某个函数或代码块。它接受两个参数&#xff0c;第一个参数是要执行的函数或代码块&#xff0c;第二个参数是时间间隔&#xff08;以毫秒为单位&#xff09;。 以下是使用window.setInterval…...

Einstein Summation 爱因斯坦求和 torch.einsum

Einstein Summation 爱因斯坦求和 torch.einsum flyfish 理解爱因斯坦求和的基本概念和语法&#xff0c;这对初学者来说可能有一定难度。对于不熟悉该表示法的用户来说&#xff0c;可能不如直接的矩阵乘法表达式易于理解。 整个思路是 向量的点积 -》矩阵乘法-》einsum 向…...

TCP攻击是怎么实现的,如何防御?

TCP&#xff08;Transmission Control Protocol&#xff09;是互联网协议族中的重要组成部分&#xff0c;用于在不可靠的网络上提供可靠的数据传输服务。然而&#xff0c;TCP协议的一些特性也使其成为攻击者的目标&#xff0c;尤其是DDoS&#xff08;Distributed Denial of Ser…...

Chrome DevTools开发者调试工具

Chrome DevTools 是一个功能强大的网页开发工具&#xff0c;集成在谷歌浏览器中&#xff0c;帮助开发者调试和优化网页应用。以下是详细的功能说明和使用技巧&#xff1a; 1. 打开 DevTools 快捷键&#xff1a;按下 F12 或 CtrlShiftI&#xff08;Windows/Linux&#xff09;或…...

产品创新管理:从模仿到引领,中国企业的创新之路

一、引言 在全球化竞争日益激烈的今天&#xff0c;科技创新已成为推动国家经济增长和社会进步的关键动力。中国自改革开放四十年来&#xff0c;在科技创新领域取得了举世瞩目的成就&#xff0c;从跟踪模仿到自主研发&#xff0c;再到自主创新、开放创新和协同创新并举&#xf…...

Android 日志实时输出

开发中如果只是单纯的应用开发&#xff0c;Android studio基本上可以满足&#xff0c;但是如果应用和系统联调那就得用logcat实时输出了&#xff0c;我这里都是总结的实用经验&#xff0c;没那么多花里胡哨 Android 日志实时输出 1、输出 android log //分步&#xff0c;进入s…...

JavaEE初阶---多线程编程(一.线程与进程)

目录 &#x1f923;一.线程与进程的概念与联系&#xff1a; 进程的基本概念&#xff1a; 线程的基本概念&#xff1a; 进程和线程的区别与联系&#xff1a; &#x1f643;代码执行实列&#xff1a; 1.通过继承Thread父类来实现多线程 2.通过实现Runnable接口来实现多线程…...

react+vite创建

要在本地初始化一个结合了React和Vite的项目&#xff0c;你可以遵循以下步骤&#xff1a; 1、安装Node.js&#xff1a; 确保你的机器上已安装了Node.js。如果未安装&#xff0c;请前往Node.js官网下载并安装。 2、使用终端或命令提示符&#xff1a; 打开你的终端&#xff08;…...

软考 系统架构设计师系列知识点之杂项集萃(29)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;28&#xff09; 第46题 以下描述中&#xff0c;&#xff08; &#xff09;不是嵌入式操作系统的特点。 A. 面向应用&#xff0c;可以进行裁剪和移植 B. 用于特定领域&#xff0c;不需要支持多任…...

从Shadertoy到Cesium:那些GLSL移植时没人告诉你的分辨率陷阱

GLSL跨平台移植中的分辨率适配陷阱与实战解决方案 当我们将Shadertoy上令人惊艳的GLSL效果移植到Cesium等三维引擎时&#xff0c;往往会遇到一个看似简单却影响深远的问题——分辨率适配。这个问题不仅关乎视觉效果还原度&#xff0c;更直接影响着色器在不同设备上的表现一致性…...

SDMatte镜像结构详解:/opt/sdmatte-web目录布局与模型路径规范说明

SDMatte镜像结构详解&#xff1a;/opt/sdmatte-web目录布局与模型路径规范说明 1. 镜像概述 SDMatte 是一款面向高质量图像抠图场景的AI模型&#xff0c;特别适合处理以下任务&#xff1a; 商品图主体分离透明物体提取&#xff08;如玻璃器皿、薄纱等&#xff09;复杂边缘精…...

避开这5个坑!用HipSTR分析NGS数据时最容易出错的STR检测问题

避开这5个坑&#xff01;用HipSTR分析NGS数据时最容易出错的STR检测问题 STR检测在二代测序数据分析中扮演着关键角色&#xff0c;但实际操作中常会遇到各种"坑"。本文将结合实战经验&#xff0c;剖析使用HipSTR进行STR检测时最容易出错的五个关键环节&#xff0c;帮…...

PLC新手必看:三菱FX2N顺序功能图的5个常见错误及解决方法

三菱FX2N顺序功能图实战避坑指南&#xff1a;从原理到调试的完整解决方案 第一次接触三菱FX2N的顺序功能图编程时&#xff0c;那种既兴奋又忐忑的心情至今记忆犹新。看着逻辑清晰的流程图在仿真中运行失常&#xff0c;或是设备突然"抽风"时的茫然&#xff0c;是每个P…...

Phi-4-Reasoning-Vision入门指南:图文推理结果JSON结构与API对接说明

Phi-4-Reasoning-Vision入门指南&#xff1a;图文推理结果JSON结构与API对接说明 1. 工具概述 Phi-4-Reasoning-Vision是一款基于微软Phi-4-reasoning-vision-15B多模态大模型开发的高性能推理工具&#xff0c;专为双NVIDIA RTX 4090显卡环境优化。该工具严格遵循官方SYSTEM …...

GLM-OCR开发者实操手册:Gradio client调用+批量图片识别脚本示例

GLM-OCR开发者实操手册&#xff1a;Gradio client调用批量图片识别脚本示例 你是不是也遇到过这样的场景&#xff1a;手头有一堆发票、合同或者产品说明书图片&#xff0c;需要把里面的文字、表格甚至公式都提取出来&#xff1f;一张张手动录入或者用传统OCR工具&#xff0c;不…...

PostgreSQL 模式级权限迁移:一键批量修改所有表与对象的所有者

1. 为什么需要批量修改PostgreSQL对象所有者&#xff1f; 在实际的数据库运维工作中&#xff0c;经常会遇到需要批量修改数据库对象所有者的情况。我遇到过不少这样的场景&#xff1a;公司部门重组后&#xff0c;原先由开发团队A负责的项目转交给团队B维护&#xff1b;或者某个…...

一条命令搞定STM32程序下载:OpenOCD program命令的隐藏用法与避坑指南

STM32极速烧录秘籍&#xff1a;OpenOCD program命令高阶玩法全解析 每次调试STM32都要重复点击IDE的下载按钮&#xff1f;CI/CD流水线卡在烧录环节&#xff1f;是时候解锁OpenOCD的program命令了——这个被低估的"瑞士军刀"能让你用一行命令完成擦除、烧录、校验、复…...

终极免费Jable视频下载指南:3步搞定Chrome插件完整教程

终极免费Jable视频下载指南&#xff1a;3步搞定Chrome插件完整教程 【免费下载链接】jable-download 方便下载jable的小工具 项目地址: https://gitcode.com/gh_mirrors/ja/jable-download jable-download是一款专为普通用户设计的免费Jable视频下载工具&#xff0c;通过…...

美胸-年美-造相Z-Turbo真实案例:快速生成24套手游服装方案

美胸-年美-造相Z-Turbo真实案例&#xff1a;快速生成24套手游服装方案 1. 项目背景与挑战 在手游《幻境物语》的角色设计阶段&#xff0c;美术团队面临一个紧迫需求&#xff1a;为游戏中的"花语使者"职业设计24套不同风格的服装方案。传统手工绘制方案需要至少3周时…...