vite+vue3中使用FFmpeg@0.12.15实现视频编辑功能,不依赖SharedArrayBuffer!!!

FFmpeg@0.12.15完全不依赖SharedArrayBuffer!!!强烈推荐使用

本文章主要是在vite+vue3项目中使用FFmpeg,只展示了如何在项目中引入和基础的使用

更多详细参数可参照 ffmpeg官网https://ffmpeg.org/

一、安装FFmpeg

可通过npm直接安装

npm install @ffmpeg/core@0.12.10 @ffmpeg/ffmpeg@0.12.15 @ffmpeg/util@0.12.2

二、在代码中使用

1、初始化FFmpeg

首先找到node_modules/@ffmpeg/core/dist/esm下的这两个文件,并放到public文件夹下,例如

import { FFmpeg } from '@ffmpeg/ffmpeg'
import { fetchFile, toBlobURL } from '@ffmpeg/util'
import { ref, onMounted } from 'vue'
let ffmpeg = null
const initFFmpegFn = async () => {if (ffmpeg) return// 初始化ffmpeg ffmpeg = new FFmpeg();// 如果需要当前编辑视频进度let progress = ref(0);ffmpeg.on('log', ({ type, message }) => {if (type === 'stderr') {// 匹配日志中的时间信息(例如:time=00:00:05.12)const timeMatch = message.match(/time=(\d+:\d+:\d+\.\d+)/);if (timeMatch && totalDuration.value) {const currentTime = parseTimeToSeconds(timeMatch[1]);const newProgress = Math.min(Math.round((currentTime / totalDuration.value) * 100), 100);progress.value = newProgress;}}});// 加载FFmpeg核心try {// ffmpeg.loaded 核心是否加载if (!ffmpeg.loaded) {let ffmpegBaseUrl = '/FFmpeg/dist'await ffmpeg.load({coreURL: await toBlobURL(`${ffmpegBaseUrl}/ffmpeg-core.js`, 'text/javascript'),wasmURL: await toBlobURL(`${ffmpegBaseUrl}/ffmpeg-core.wasm`, 'application/wasm'),});console.log('加载完成', ffmpeg);}} catch (err) {console.error('FFmpeg核心加载失败:', err);}}
// 工具函数:将时间字符串(如00:00:05.12)转换为秒
const parseTimeToSeconds = (timeStr) => {const [hours, minutes, seconds] = timeStr.split(':').map(Number);return hours * 3600 + minutes * 60 + seconds;
};
onMounted(() => {initFFmpegFn()
})

2、加载出错处理(如果通过上一步能正常加载完成,可忽略)

由于ffmpeg中会使用vite中的worker,可能会导致控制台中有一个链接为http://localhost:9090/node_modules/.vite/deps/worker.js?worker_file&type=module一直处于pending状态,无法加载成功

需要在vite.config.js中使用optimizeDeps.exclude 是指定不需要进行依赖预构建。

3、编辑视频:是否静音-调整视频宽高-裁剪视频时长

const processVideoFn = async (fileBlob, processOptions = {}) => {// fileBlob 视频文件blob对象if (!fileBlob || !(fileBlob instanceof Blob)) {console.error('错误:请传入有效的视频Blob对象');return { success: false, error: '无效的视频Blob', url: null, blob: null };}if (fileBlob.size === 0) {console.error('错误:传入的Blob为空(大小0字节)');return { success: false, error: '输入Blob为空', url: null, blob: null };}const {needClearVoice = false,//裁剪后是否静音resizeInfo = {width:800,height:800},//裁剪后视频宽高cropInfo = { startTime:0, duration:60 }// startTime:裁剪视频开始时间   duration:总裁剪时长} = processOptions;const { startTime = 0, duration = 60 } = cropInfo;progress.value = 0;//进度条归0totalDuration.value = duration;//总裁剪时长,用于计算进度条const timestamp = Date.now();const inputFileName = `input_video.mp4`;const outputFileName = `output_video_${timestamp}.mp4`;let outputData = null; // 存储输出数据,避免提前清理try {if (!ffmpeg || !loadSuccess.value) {throw new Error('FFmpeg核心未加载完成');}const fileData = await fetchFile(fileBlob); // fetchFile返回Uint8Arrayawait ffmpeg.writeFile(inputFileName, fileData); // 直接传文件名+数据const ffmpegCommand = ['-i', inputFileName];// 裁剪处理(校验参数)if (cropInfo) {if (startTime < 0 || duration <= 0) {throw new Error(`裁剪参数无效:startTime=${startTime}(需≥0),duration=${duration}(需>0)`);}ffmpegCommand.push('-ss', startTime.toFixed(2), '-t', duration.toFixed(2));}// 尺寸调整(校验参数)if (resizeInfo) {let { width, height } = resizeInfo;if (width <= 0 || height <= 0) {throw new Error(`尺寸参数无效:width=${width}(需>0),height=${height}(需>0)`);}const scaleFilter = `scale=w=${width}:h=${height}:force_original_aspect_ratio=decrease`;const padFilter = `pad=w=${width}:h=${height}:x=(ow-iw)/2:y=(oh-ih)/2:color=white`;//视频宽高不够时填充白色边框ffmpegCommand.push('-vf', `${scaleFilter},${padFilter}`);}// 音频处理if (needClearVoice) {ffmpegCommand.push('-an'); // 移除音频} else {ffmpegCommand.push('-c:a', 'aac', '-strict', 'experimental'); // 保留音频}ffmpegCommand.push('-c:v', 'libx264',       // H.264编码(通用)'-pix_fmt', 'yuv420p',   // 兼容所有播放器(避免仅支持yuv444p的问题)'-crf', '30',            // 控制质量(值越小质量越高,28为平衡值)'-preset', 'ultrafast',  // ultrafast/superfast/veryfast/faster/fast/medium(默认值)/slow/slower/veryslow 从前到后处理速度越来越慢,处理视频越精致'-b:v', '1M',            // 视频比特率(避免输出过小/过大)'-y',                    // 覆盖已有文件outputFileName);await ffmpeg.exec(ffmpegCommand);outputData = await ffmpeg.readFile(outputFileName);if (!outputData || outputData.length === 0) {throw new Error('FFmpeg读取输出文件为空');}const resultBlob = new Blob([outputData], { type: 'video/mp4' });if (resultBlob.size === 0) {throw new Error('生成的Blob为空');}const previewUrl = URL.createObjectURL(resultBlob);return {url: previewUrl,//生成的临时视频urlblob: resultBlob,//生成的新视频blob对象};} catch (err) {console.error('视频处理失败:',err);} finally {if (ffmpeg && outputData) {if (await ffmpeg.listDir(inputFileName).catch(() => false)) {await ffmpeg.unlink(inputFileName).catch(err => console.warn('清理输入文件失败:', err));}if (await ffmpeg.listDir(outputFileName).catch(() => false) && outputData) { // 确保读取后再删除输出await ffmpeg.unlink(outputFileName).catch(err => console.warn('清理输出文件失败:', err));}}}
};

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

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

相关文章

构网型5MW中压储能变流升压一体机技术方案

1 构网型储能背景概述1.1 新型电力系统亟需构网支撑众所周知&#xff0c;新型电力系统具有两高特征&#xff1a;高比例新能源大规模并网、高比例电力电子大范围接入。近年来风光装机占比越来越高&#xff0c;而传统火电装机占比越来越低&#xff0c;并在2023年首次降至50%以下…

SRE 系列(七)| 从技术架构到团队组织

目录SRE落地与组织架构实践技术架构与组织架构的匹配技术架构示例运维职责分工技术保障体系SRE 多角色团队总结SRE落地与组织架构实践 在落地 SRE 时&#xff0c;很多团队最关心的问题之一就是组织架构&#xff1a;我们究竟需要怎样的团队形态&#xff0c;才能支撑微服务和分…

香港期权市场的主要参与者有哪些?

本文主要介绍香港期权市场的主要参与者有哪些&#xff1f;香港期权市场作为全球重要的金融衍生品市场&#xff0c;其参与者结构呈现多元化、专业化的特征&#xff0c;主要涵盖以下核心群体。香港期权市场的主要参与者有哪些&#xff1f;1. 机构投资者&#xff08;主导力量&…

搜维尔科技:全身可穿戴Teslasuit动捕服的功能,自立式FES装置

功能性电刺激 (FES) 设备广泛应用于康复和医疗实践。其底层技术利用低能量电脉冲&#xff0c;在中风、脊髓损伤、多发性硬化症、脑瘫等各种疾病患者中人工产生身体运动。一般来说&#xff0c;FES系统可以分为三类&#xff1a;开环、有限状态控制和闭环方法。这三种方法描述了 F…

【深度学习新浪潮】MoE是什么技术?

混合专家模型(Mixture of Experts,MoE)是大模型时代提升计算效率与模型能力的核心技术之一。其核心思想是将复杂任务分解为多个子任务,通过动态路由机制激活特定专家网络处理输入数据,从而在保持模型容量的同时大幅降低计算成本。以下是技术细节与实际应用的深度解析: 一…

Java进阶教程,全面剖析Java多线程编程,实现Callable接口实现多线程,笔记05

Java进阶教程&#xff0c;全面剖析Java多线程编程&#xff0c;实现Callable接口实现多线程&#xff0c;笔记05 参考资料 多线程&JUC-05-多线程的第三种实现方式一、实现Callable接口实现多线程 二、三种方式对比 优点缺点继承Thread类编程比较简单&#xff0c;可以直接使…

轨道交通绝缘监测—轨道交通安全的隐形防线

轨道交通绝缘监测作为保障行车安全的核心环节&#xff0c;正面临多重技术与环境挑战。复杂运营环境是首要痛点&#xff0c;隧道内高湿度&#xff08;月均湿度达95%&#xff09;会增大钢轨表面电导率&#xff0c;雾气中的盐分更会加速扣件绝缘性能下降&#xff0c;导致过渡电阻骤…

tar-符号连接(软连接)

1.符号连接是什么符号链接&#xff08;symbolic link&#xff0c;也叫软链接&#xff09;本质上是一个 指向路径的特殊文件。例如&#xff1a;ln -s /etc/passwd passwd_link这会创建一个叫 passwd_link 的文件&#xff0c;但它本身不存放 /etc/passwd 的内容&#xff0c;而是存…

ffmpeg切割音频

ffmpeg切割音频 我希望对指定音频切割&#xff0c;按照开始时间&#xff0c;结束时间&#xff0c;切割成新文件&#xff0c;自动保存&#xff0c;非常好用 step1: from pydub import AudioSegment import os# 配置FFmpeg路径&#xff08;确保路径正确&#xff09; ffmpeg_path …

Python 批量处理:Markdown 与 HTML 格式相互转换

文章目录引言与同类工具的优势对比Python 将 Markdown 转换为 HTMLPython 将 HTML 转换为 Markdown批量转换与自动化处理引言 在多平台内容分发与管理的场景中&#xff0c;文档格式转换已成为内容生态系统中的关键环节。Markdown 作为轻量级标记语言&#xff0c;以其语法简洁、…

御控物联网远程控制水泵启停智能自控解决方案

在农业灌溉、城市排水、工业供水等场景中&#xff0c;水泵作为核心设备&#xff0c;长期面临以下难题&#xff1a;人工依赖度高&#xff1a;需24小时值守&#xff0c;暴雨或干旱时响应滞后&#xff1b; 能耗浪费严重&#xff1a;空转、过载运行导致电费居高不下&#xff1b; …

RedisI/O多路复用:单线程网络模型epoll工作流程

epoll1. 在内核创建eventpoll结构体&#xff0c;返回句柄epfd&#xff08;唯一标识&#xff09;eventpoll包含存放被监听的fd的红黑树&#xff0c;和存放已就绪的fd的链表2. 将要监听的fd加入到epoll红黑树中&#xff0c;并设置callback回调函数callback触发时&#xff0c;就将…

SmartBear API Hub助力MCP开发,无缝、安全的连接AI与外部工具

人工智能&#xff08;AI&#xff09;技术的应用场景日益广泛&#xff0c;如何让不同的AI系统之间实现高效、无缝的交互&#xff0c;成为了业界的重要课题。随着人工智能技术的不断进步&#xff0c;模型上下文协议&#xff08;MCP&#xff09;应运而生。MCP为不同AI系统之间提供…

如何选择高性价比的iOS签名服务?关键因素与价格区间

作为一名摸爬滚打多年的开发者&#xff0c;我来和你聊聊怎么挑一个靠谱又不坑的iOS签名服务。这玩意儿选不好&#xff0c;轻则测试团队干瞪眼&#xff0c;重则App下架&#xff0c;用户投诉&#xff0c;简直是我们开发者的噩梦。别光看价格&#xff01;先想清楚你的核心需求在选…

MoonBit 正式加入 WebAssembly Component Model 官方文档 !

我们非常高兴地宣布&#xff0c;MoonBit 已正式收录在 WebAssembly Component Model 的官方文档中。这不仅是对 MoonBit 技术路线的一次肯定&#xff0c;也让我们有机会和 Rust、Go、C# 等语言一起&#xff0c;出现在开发者查阅组件模型的入口页面中。一、 关于 WebAssembly Co…

Python快速入门专业版(三十二):匿名函数:lambda表达式的简洁用法(结合filter/map)

目录引一、lambda表达式的基本语法&#xff1a;一行代码定义函数示例1&#xff1a;lambda表达式与普通函数的对比二、lambda表达式的应用场景&#xff1a;临时与灵活1. 临时使用&#xff1a;无需定义函数名的简单功能2. 作为参数传递给高阶函数三、结合filter()&#xff1a;筛选…

【LeetCode 每日一题】3025. 人员站位的方案数 I——(解法一)暴力枚举

Problem: 3025. 人员站位的方案数 I 文章目录整体思路完整代码时空复杂度时间复杂度&#xff1a;O(N^3)空间复杂度&#xff1a;O(1)整体思路 这段代码旨在解决一个几何计数问题&#xff1a;给定平面上的 n 个点&#xff0c;计算满足特定条件的“点对” (i, j) 的数量。 根据代…

Roo Code 诊断集成功能:智能识别与修复代码问题

这里是引用在日常编程中&#xff0c;遇到代码错误或警告是再常见不过的事。但如何高效定位并解决这些问题&#xff0c;往往考验开发者的经验和工具链的支持。 Roo Code 中有一项非常实用的功能——诊断集成&#xff08;Diagnostics Integration&#xff09;。它能够与 VSCode 的…

Redis 与微服务架构结合:高并发场景下的架构艺术

&#x1f50c; Redis 与微服务架构结合&#xff1a;高并发场景下的架构艺术 文章目录&#x1f50c; Redis 与微服务架构结合&#xff1a;高并发场景下的架构艺术&#x1f9e9; 一、微服务架构下的挑战⚠️ 典型痛点分析&#x1f4ca; 性能瓶颈对比⚙️ 二、Redis作为配置中心&a…

鸿蒙应用冷启动优化:本地 KV 缓存预热实战指南

在鸿蒙&#xff08;HarmonyOS&#xff09;应用开发中&#xff0c;冷启动速度直接影响用户的初始体验。许多应用在启动后需要加载大量常用配置&#xff08;如用户偏好设置、主题配置&#xff09;或基础数据&#xff08;如上次登录信息、常用功能参数&#xff09;&#xff0c;若每…