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

原生Js 提取视频中的音频

Js提取视频中的音频


将视频中的音频轨道分离出来,生成 wav 文件播放或下载( Vue3 setup

代码实现

  1. template
<button><label for="file" id="filename">选择视频文件</label><input type="file" name="file" id="file" accept="video/*,audio/*" @change="fileChange">
</button>
  1. scss
button {position: absolute;top: calc(50vh - 30px);left: 10%;width: 80%;height: 60px;background-color: transparent;border: 1px solid gainsboro;border-radius: 10px;padding: 10px;
}input[type=file] {position: absolute;top: 0;left: 0;width: 100%;height: 100%;opacity: 0;filter: alpha(opacity=0);cursor: pointer;
}
  1. setup
const fileChange = (e) => {const file = e.target.files[0]if (!file) returnconst label = document.getElementById('filename')label.innerHTML = file.namevideoToAudio(file).then(audio => {console.log('audio', audio)audio && (label.innerHTML = audio.fileName)})
}/**** video-to-audio* creater:qc* reference://github.com/mdn/webaudio-examples/tree/master/offline-audio-context-promise*/
const videoToAudio = async (file) => {try {console.log('videoToAudio file', file)const fileData = new Blob([file]) // video fileconst arrayBuffer = await new Promise((resolve) => {const reader = new FileReader()reader.onload = () => {const arrayBuffer = reader.resultresolve(arrayBuffer)}reader.readAsArrayBuffer(fileData)})console.log('arrayBuffer', arrayBuffer)const audioContext = new (window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext)()const decodedAudioData = await audioContext.decodeAudioData(arrayBuffer)console.log('decodedAudioData', decodedAudioData)const fileDuration = durationTrans(decodedAudioData.duration)console.log('fileDuration', fileDuration)const offlineAudioContext = new OfflineAudioContext(decodedAudioData.numberOfChannels, decodedAudioData.sampleRate * decodedAudioData.duration, decodedAudioData.sampleRate)const soundSource = offlineAudioContext.createBufferSource()soundSource.buffer = decodedAudioDatasoundSource.connect(offlineAudioContext.destination)soundSource.start()const renderedBuffer = await offlineAudioContext.startRendering()console.log('renderedBuffer', renderedBuffer) // outputs audiobufferconst wav = audioBufferToWav(renderedBuffer)const fileType = `wav`const fileName = `${file.name}.${fileType}`// -----------下载音频文件---------------------downloadWav(wav, fileName)// ------------------------------------------// -----------播放音频文件---------------------audioContext.decodeAudioData(wav, function (buffer) {const source = audioContext.createBufferSource();source.buffer = buffer;source.connect(audioContext.destination);source.start();// 在这里继续下一步}, function (error) {console.error('解码音频数据失败:', error);});// ------------------------------------------return {fileName, fileType, fileDuration}} catch (error) {// {code: 0, name: 'EncodingError', message: 'Unable to decode audio data'} Case:No audio in the video file ? Maybeconsole.log('videoToAudio error', error)return null} finally {console.log('videoToAudio finally')}
}/*** audiobuffer-to-wav* creater:https://github.com/Jam3/audiobuffer-to-wav*/
const audioBufferToWav = (buffer, opt) => {opt = opt || {}var numChannels = buffer.numberOfChannelsvar sampleRate = buffer.sampleRatevar format = opt.float32 ? 3 : 1var bitDepth = format === 3 ? 32 : 16var resultif (numChannels === 2) {result = interleave(buffer.getChannelData(0), buffer.getChannelData(1))} else {result = buffer.getChannelData(0)}return encodeWAV(result, format, sampleRate, numChannels, bitDepth)
}const encodeWAV = (samples, format, sampleRate, numChannels, bitDepth) => {var bytesPerSample = bitDepth / 8var blockAlign = numChannels * bytesPerSamplevar buffer = new ArrayBuffer(44 + samples.length * bytesPerSample)var view = new DataView(buffer)/* RIFF identifier */writeString(view, 0, 'RIFF')/* RIFF chunk length */view.setUint32(4, 36 + samples.length * bytesPerSample, true)/* RIFF type */writeString(view, 8, 'WAVE')/* format chunk identifier */writeString(view, 12, 'fmt ')/* format chunk length */view.setUint32(16, 16, true)/* sample format (raw) */view.setUint16(20, format, true)/* channel count */view.setUint16(22, numChannels, true)/* sample rate */view.setUint32(24, sampleRate, true)/* byte rate (sample rate * block align) */view.setUint32(28, sampleRate * blockAlign, true)/* block align (channel count * bytes per sample) */view.setUint16(32, blockAlign, true)/* bits per sample */view.setUint16(34, bitDepth, true)/* data chunk identifier */writeString(view, 36, 'data')/* data chunk length */view.setUint32(40, samples.length * bytesPerSample, true)if (format === 1) { // Raw PCMfloatTo16BitPCM(view, 44, samples)} else {writeFloat32(view, 44, samples)}return buffer
}const interleave = (inputL, inputR) => {var length = inputL.length + inputR.lengthvar result = new Float32Array(length)var index = 0var inputIndex = 0while (index < length) {result[index++] = inputL[inputIndex]result[index++] = inputR[inputIndex]inputIndex++}return result
}const writeFloat32 = (output, offset, input) => {for (var i = 0; i < input.length; i++, offset += 4) {output.setFloat32(offset, input[i], true)}
}const floatTo16BitPCM = (output, offset, input) => {for (var i = 0; i < input.length; i++, offset += 2) {var s = Math.max(-1, Math.min(1, input[i]))output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true)}
}const writeString = (view, offset, string) => {for (var i = 0; i < string.length; i++) {view.setUint8(offset + i, string.charCodeAt(i))}
}const downloadWav = (wav, fileName = 'audio') => {try {const blob = new window.Blob([new DataView(wav)], {type: 'audio/wav'})if ('download' in document.createElement('a')) {const url = window.URL.createObjectURL(blob)const anchor = document.createElement('a')document.body.appendChild(anchor)anchor.style = 'display: none'anchor.href = urlanchor.download = fileNameanchor.click()window.URL.revokeObjectURL(url)document.body.removeChild(anchor)} else {navigator.msSaveBlob(blob, fileName)}} catch (error) {console.log('downloadWav error', error)} finally {console.log('downloadWav finally')}
}const durationTrans = (a) => {let b = ''let h = parseInt(a / 3600),m = parseInt(a % 3600 / 60),s = parseInt(a % 3600 % 60)if (h > 0) {h = h < 10 ? '0' + h : hb += h + ':'}m = m < 10 ? '0' + m : ms = s < 10 ? '0' + s : sb += m + ":" + sreturn b
}

相关文章:

原生Js 提取视频中的音频

Js提取视频中的音频 将视频中的音频轨道分离出来&#xff0c;生成 wav 文件播放或下载&#xff08; Vue3 setup &#xff09; 代码实现 template <button><label for"file" id"filename">选择视频文件</label><input type"fi…...

设计模式-备忘录模式(Memento Pattern)

文章目录 前言一、备忘录模式的概念二、备忘录模式的实现三、备忘录优缺点优点&#xff1a;缺点&#xff1a;总结 前言 备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;它用于捕获和存储对象的内部状态&#xff0c;以便在以后可以恢复到先…...

PHP对接阿里云虚拟号的实现(号码隐私保护)

fastadmin 封装框架 实现功能&#xff1a;AXN隐私号绑定、解绑&#xff1b; 场景&#xff1a;为店铺手机号开通虚拟号&#xff0c;用户联系店铺展示虚拟号码&#xff1b; 官方开放文档地址&#xff1a;https://help.aliyun.com/document_detail/59655.html?spma2c4g.111742…...

刷新单年发射纪录:SpaceX成功发射62次猎鹰9号火箭

SpaceX一直都致力于推进航天领域的发展。近日&#xff0c;该公司的猎鹰9号火箭再次刷新了单年发射纪录&#xff0c;目前已经成功发射了62次。除此之外&#xff0c;今年SpaceX还发射了一枚猎鹰火箭和一枚巨型火箭。马斯克表示&#xff0c;他的目标是实现每月10次猎鹰飞行&#x…...

项目打包docker镜像 | 上传nexus | jenkins一键构建

文章目录 前言准备实操1、打开docker的远程访问2、编写dockerfile文件3、指定nexus环境4、配置jenkins5、使用jenkins构建 总结 前言 Docker部署项目是指使用Docker容器化技术将应用程序及其依赖项打包成一个独立的、可移植的运行环境&#xff0c;并在各种操作系统和平台上进行…...

ios 运行ipa包 日志查看方式

方法一&#xff1a; 使用ideviceinstaller工具 # 安装ipa命令 brew install ideviceinstaller ideviceinstaller -i xxx.ipa# 查看运行日志 idevicesyslog# idevicesyslog 查找命令 idevicesyslog | grep test -A 3 -B 2 # 输出关键字所在行后3行&#xff0c;前2行) idevic…...

AUTOSARCAN-Tp协议

目录 一.单帧、首帧、连续帧、流控帧 单帧传输 SF单帧&#xff1a; 多帧传输 FF&#xff08;首帧&#xff09;&#xff1a; CF&#xff08;连续帧&#xff09;&#xff1a; FC&#xff08;流控帧&#xff09;&#xff1a; 一.单帧、首帧、连续帧、流控帧 CAN诊断由发送端…...

【设计模式】组合模式实现部门树实践

1.前言 几乎在每一个系统的开发过程中&#xff0c;都会遇到一些树状结构的开发需求&#xff0c;例如&#xff1a;组织机构树&#xff0c;部门树&#xff0c;菜单树等。只要是需要开发这种树状结构的需求&#xff0c;我们都可以使用组合模式来完成。 本篇将结合组合模式与Mysq…...

恒林家居引入纷享销客CRM系统,领跑家居行业营销数字化进程

近日&#xff0c;恒林家居股份有限公司&#xff08;&#xff08;股票代码&#xff1a;603661以下简称为“恒林家居”&#xff09;携手纷享销客在湖州召开了CRM项目启动会。双方领导及核心项目人员齐聚一堂&#xff0c;展开了深度交流并达成了重要共识。 作为家居行业的领军企业…...

多线程-锁的种类

1 作用 Java中的锁主要用于保障多并发线程情况下数据的一致性。在多线程编程中为了保障数据的一致性&#xff0c;我们通常需要在使用对象或者方法之前加锁&#xff0c;这时如果有其他线程也需要使用该对象或者该方法,则首先要获得锁,如果某个线程发现锁正在被其他线程使用,就会…...

Hive 和 HDFS、MySQL 之间的关系

文章目录 HiveHDFSMySQL三者的关系 Hive、MySQL 和 HDFS 是三个不同的数据存储和处理系统&#xff0c;它们在大数据生态系统中扮演不同的角色&#xff0c;但可以协同工作以支持数据管理和分析任务。 Hive Hive 是一个基于 Hadoop 生态系统的数据仓库工具&#xff0c;用于管理和…...

【面试题】如何实现数组去重的?有几种方式?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 【国庆头像】- 国庆爱国 程序员头像&#xff01;总有一款适合你&#xff01; 1. 方法一&#xff1a;利用两层循环数组的splice方法 通过两层循环对数组…...

使用TCP方式拉取Canal数据

1 Canal对接Kafka联调 1.1 配置修改 canal.properties 修改 zk&#xff1a; canal.zkServers 10.51.50.219:2181instance.properties 开启配置项&#xff1a; canal.mq.dynamicTopic 是 Canal 的 MQ 动态 Topic 配置项&#xff1a; test_javaedge_01 是kafka 的 topicte…...

Docker安装mysql实战说明

安装前准备 在安装MySQL之前&#xff0c;你需要确保已经正确安装和配置了Docker&#xff0c;可以通过以下命令检查Docker是否已正确安装&#xff1a; docker --version如果Docker已经成功安装&#xff0c;你将看到Docker的版本信息。 下载mysql的镜像 Docker Hub是一个存储…...

前端DOM操作精解:基础概念、方法与最佳实践

引言 本文将深入探讨前端开发中的DOM操作&#xff0c;包括基础概念、常用方法和最佳实践。通过清晰易懂的解释和实际案例分析&#xff0c;我们将一起了解如何最有效地使用DOM操作来提升前端应用的用户体验。 一、DOM操作入门 在深入探讨DOM操作之前&#xff0c;我们先要理解…...

python sorted函数详解2023.9.11

sorted函数详解 1. 输入和输出2. key传入函数 1. 输入和输出 help(sorted) Help on built-in function sorted in module builtins: sorted(iterable, /, *, keyNone, reverseFalse)Return a new list containing all items from the iterable in ascending order.A custom k…...

Spring Reactive:响应式编程与WebFlux的深度探索

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

Qt应用开发(基础篇)——工具按钮类 QToolButton

一、前言 QToolButton类继承于QAbstractButton&#xff0c;该部件为命令或选项提供了一个快速访问按钮&#xff0c;通常用于QToolBar中。 按钮基类 QAbstractButton QToolButton是一个特殊的按钮&#xff0c;一般显示文本&#xff0c;只显示图标&#xff0c;结合toolBar使用。它…...

【数据结构面试题】栈与队列的相互实现

目录 1.队列实现栈 1.1创建栈 1.2判断是否为空 1.3入栈 1.4出栈 1.5获取栈顶元素 1.6完整代码 2. 用栈实现队列 2.1创建队列 2.2判断是否为空 2.3入队列 2.4出队列 2.5获取队头元素 2.6完整代码 1.队列实现栈 用队列实现栈https://leetcode.cn/problems/impleme…...

华为认证和红帽认证哪个比较好考呢

华为认证和红帽认证的考试难度、学习内容、适用范围等方面都有所不同&#xff0c;因此哪个比较好考要视具体情况而定&#xff1a; 考试难度&#xff1a;红帽认证的考试难度较高&#xff0c;需要考生具备较高的技术水平和实践经验&#xff1b;而华为认证则更注重基础知识的考察…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...