记录---前端Vue使用ffmpeg压缩视频再上传

news/2024/11/14 22:18:44/文章来源:https://www.cnblogs.com/smileZAZ/p/18541958

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

保姆级操作步骤,从我实际运行中的项目中摘取的所有相关代码展示如下:

1.Vue项目中安装插件ffmpeg

1.1 插件版本依赖配置

两个插件的版本 "@ffmpeg/core": "^0.10.0", "@ffmpeg/ffmpeg": "^0.10.1"
package.json 和 package-lock.json 都加入如下ffmpeg的版本配置:

1.2 把ffmpeg安装(下载)到项目依赖目录里

terminal运行命令:

npm i
或直接运行命令安装ffmpeg:
npm install @ffmpeg/ffmpeg @ffmpeg/core -S
安装后package-lock.json会自动写入如下配置:

1.2.1 报错处理

如果出现安装问题:

 ①先在npm i命令后加--legacy-peer-deps 或者   --force运行

npm i --force
②如果上步不行,尝试删除这个安装依赖目录node_modules

 

和package-lock.json文件,重试npm i

请参考:

npm ERR! code ERESOLVEnpm ERR! ERESOLVE could not resolve 报错,版本冲突,最全解决步骤(#^.^#)_npm err! code eresolve npm err! eresolve could not-CSDN博客

1.2.2 镜像过期

安装ffmpeg可能提示镜像证书过期

你使用的镜像地址可能还是这个过期的淘宝镜像:https://registry.npm.taobao.org/

按如下步骤重设镜像地址:

①查看镜像:npm config list

②强制清理镜像缓存:npm cache clean --force

③设置镜像:npm config set registry https://registry.npmmirror.com/(国内推荐淘宝新镜像)

也可:npm config set registry https://registry.npmjs.org/

1.3 把ffmpeg安装到项目里

在项目里的ffmpeg插件目录下找到:

ffmpeg-core.js

ffmpeg-core.wasm

ffmpeg-core-worker.js

 复制到项目代码的public目录里

至此,项目里安装ffmpeg完毕。

接下来就是在代码块里使用ffmpeg

2 项目里引用并封装ffmpeg

在util目录下封装ffmpeg.js以便项目全局引用

 封装的工具通过:

import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';

把ffmpeg插件引入到项目里使用。

完整ffmpeg.js代码:

import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';
let ffmpeg = {};ffmpeg.squeezVideo = async function(file, filename, filetype, width, height, msg) {console.log('file', file);console.log('filename', filename);console.log('filetype', filetype);console.log('width', width);console.log('height', height);// 分辨率const resolution = `${width}x${height}`;// 实例化ffmpegconst ffmpegObj = createFFmpeg({// ffmpeg路径corePath: 'ffmpeg-core.js',// 日志log: true,// 进度progress: ({ ratio }) => {msg = `完成率: ${(ratio * 100.0).toFixed(1)}%`;}})var { name } = file;// msg = '正在加载 ffmpeg-core.js'// 开始加载await ffmpegObj.load();// msg = '开始压缩'// 把文件加到ffmpeg   写文件ffmpegObj.FS('writeFile', name, await fetchFile(file));// await ffmpeg.run('-i', name, '-b', '2000000', '-fs', '4194304', '-preset medium', 'superfast', 'output.mp4')// 开始压缩视频const compressedFileSize = this.computeFileSize(file);console.log("After compression,this file size is " + compressedFileSize + " Bytes.");await ffmpegObj.run('-i', name, '-b', '2000000', '-crf', '18', '-fs', compressedFileSize, '-s', resolution, 'output.mp4');// msg = '压缩完成'// 压缩所完成,   读文件  压缩后的文件名称为 output.mp4const data = ffmpegObj.FS('readFile', 'output.mp4');// 转换bolb类型const blob = new Blob([data], { type: 'text/plain;charset=utf-8' });return new Promise((resolve, reject) => {const file = new window.File([blob], filename, { type: filetype });resolve(file);})
}ffmpeg.computeFileSize = function(file) {if(!file){return '0';}if(file.size / 1024 / 1024 > 60){//30Mreturn '31457280';}else if(file.size / 1024 / 1024 <= 60 && file.size / 1024 / 1024 > 30){return file.size / 2;}else{return file.size;}
}// 获取上传视频的url
ffmpeg.getObjectURL = function(file) {let url = null;window.URL = window.URL || window.webkitURL;if (window.URL) {url = window.URL.createObjectURL(file);} else {url = URL.createObjectURL(file);}return url;
}// 获取视频的宽高分辨率
ffmpeg.getVideoData = function() {return new Promise((resolve, reject) => {const videoElement = document.getElementById('video');videoElement.addEventListener('loadedmetadata', function () {resolve({width: this.videoWidth,height: this.videoHeight,duration: this.duration})});})
}export default ffmpeg;

2.1 ffmpeg压缩参数配置

 

-b:指定视频比特率

-crf:恒定速率因子,控制输出视频质量的参数。

这个参数的取值范围为0~51,其中0为无损模式。数值越大,画质越差,生成的文件却越小。

从主观上讲,18~28是一个合理的范围。18被认为是视觉无损的(从技术角度上看当然还是有损的),它的输出视频质量和输入视频相当。

-fs:压缩到指定大小,单位Byte

-s:分辨率

控制压缩后视频质量的最重要的是后面三个参数:crf、fs、s

3.视频上传元素

<template><el-uploadref='operationVideoUpload':limit="1"list-type='text':class="{disabled:addModelParam.attachments.operationVideo.length>0}":action='actionUrl':on-success="(res,file)=>handleVideoSuccess(res,file,'operationVideo')":before-upload='beforeAvatarUploadVideo':on-remove="(file,fileList)=>handleRemove(file,fileList,'operationVideo')":auto-upload='true':on-exceed="handelFileExceed"accept='.mp4,.mov,.wmv,.flv,.mvi,.mkv'><el-button style="position: relative; margin: -5px"><i  class="el-icon-circle-plus-outline" style="color: #66b1ff;">上传附件</i></el-button><br/><br/><p>{{ msg }}</p></el-upload><video id="video" hidden controls object-fill="fill"></video></template>

如果不想要展示压缩视频,可以去掉video标签。

4.上传压缩脚本

把封装的ffmpeg.js导入到页面使用:

import ffmpeg from "@/utils/ffmpeg";

完整js脚本:

<script>
import ffmpeg from "@/utils/ffmpeg";export default {data() {return {msg: '',videoWidth: '',videoHeight: '',duration: '',actionUrl: '',addModelParam: {attachments: {operationVideo: []}},}},created() {this.actionUrl = "你的后端上传文件接口地址URL";},methods: {handleVideoSuccess(res, file, code) {this.msg = "已完成视频压缩后上传!";file.url = res.data.url;file.fileId = res.data.fileId;this.addModelParam.attachments[code].push(file.fileId);},handleAvatarSuccess(res, file, code) {file.url = res.data.url;file.fileId = res.data.fileId;this.addModelParam.attachments[code].push(file.fileId);},handleRemove(file, fileList, code) {this.addModelParam.attachments[code].splice(this.addModelParam.attachments[code].indexOf(file.fileId),1)},beforeAvatarUploadVideo(file) {const isLarge = file.size / 1024 / 1024 > 30;if (isLarge) {this.msg = "请稍等,过大的视频正在压缩上传中...";//压缩视频return this.uploadCompressVideo(file);}},handelFileExceed(){this.$message('文件数量超出限制!');},// 上传视频文件压缩后再上传uploadCompressVideo(file) {if (file) {let filename = file.name;let filetype = file.type;const videoUrl = ffmpeg.getObjectURL(file);const video = document.getElementById('video');video.src = videoUrl;return ffmpeg.getVideoData().then((videoObj) => {const {width, height} = videoObj;return ffmpeg.squeezVideo(file, filename, filetype, width, height, this.msg);})}},
},}
</script>

注意异步处理:异步压缩,再上传

可使用new Promise();

5.其他配置:

5.1 vue项目根目录下的vue.config.js里加配置

headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp'
}

module.exports = {publicPath: './',devServer: {client: {overlay: false,},port: 9002,headers: {'Cross-Origin-Opener-Policy': 'same-origin','Cross-Origin-Embedder-Policy': 'require-corp'}},transpileDependencies: []}

  以免出现如下SharedArrayBuffer的报错:

6.其他实现方案

插件video-conversion.js

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

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

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

相关文章

静电纺丝机PLC采集监控系统 —— 智能化生产利器

在现代化的工业生产中,数据采集与监控是提高效率、确保质量的关键。上海数采物联网科技有限公司凭借其在工业物联网数据采集领域的深厚底蕴,隆重推出静电纺丝机PLC采集监控系统,为纺织行业的智能化升级提供了强大动力。 一、产品优势高效数据采集:系统采用先进的PLC技术,…

工作任务管理有好用的工具推荐吗?

市场上有很多好用的工作任务管理工具,可以帮助提高个人和团队的生产力。不同的工具适用于不同的工作需求,比如任务跟踪、团队协作、项目管理等。以下是一些比较受欢迎的工作任务管理工具,供你参考: 1. 禅道 (ZenTao)特点:禅道是一款基于 Web 的项目管理工具,支持需求、任…

小白必看:2024年项目经理常犯的错误有哪些?

作为一名项目经理,无论是刚入职的新人还是经验丰富的老手,在项目管理过程中都可能遇到各种挑战。特别是对于新手来说,某些常见的错误可能会影响项目的顺利推进。以下是2024年项目经理常犯的一些错误以及如何避免这些错误的建议,帮助你在项目管理过程中更高效、专业。 1. 缺…

Nuxt.js 应用中的 vite:extendConfig 事件钩子详解

title: Nuxt.js 应用中的 vite:extendConfig 事件钩子详解 date: 2024/11/12 updated: 2024/11/12 author: cmdragon excerpt: vite:extendConfig 钩子允许开发者在 Vite 项目中扩展默认配置。这使得开发者可以根据特定需求自定义 Vite 的构建和开发行为,增强开发体验。 cate…

ElasticSearch 知识梳理笔记

ElasticSearch 是什么? ElasticSearch 是一个分布式的、基于 Lucene 的搜索引擎和数据分析引擎(服务器) ElasticSearch 提供了 RESTful 风格的操作 API,是用 java 语言编写的开源软件,可以提供 PB 级别的数据存储与搜索ElasticSearch 基本概念 ElasticSearch 是面向文档型…

1000%增长!我仅用一个小时搞定!AI智能体+AI小程序=MVP王炸组合!

前言 在万圣节的前一晚上10月30日,一位运营朋友跟我说了个点子万圣节头像生成器,然后大概给我分析了下整体思路,于是我用扣子Coze平台(coze.cn)搭建了一个AI智能体整个过程花了一个小时就搞定了!我一键部署到了我的AI小程序上,第二天随便发了下小程序访问页面数据直接增…

反光衣检测视频分析网关AI智能分析中的反光衣检测算法原理与应用场景

在众多高风险工作环境中,工作人员的安全始终是首要考虑的问题。反光衣作为一种重要的个人防护装备,在提高工作人员可见性、降低事故风险方面发挥着至关重要的作用。随着人工智能技术的飞速发展,特别是深度学习算法的应用,反光衣检测视频分析网关应运而生,为自动监控和提高…

ex8.7

from scipy.integrate import odeint import numpy as np import pylab as plt import sympy as spdy = lambda y, x: -2*y+2*x**2+2*x #自变量在后面 xx = np.linspace(0,3,31) s = odeint(dy, 1, xx) print(x={}\n对应的数值解y={}.format(xx, s.flatten())) plt.plot(xx, s…

ex8.8

from scipy.integrate import odeint import numpy as np import pylab as plt yx = lambda y,x: [y[1], np.sqrt(1+y[1]**2)/5/(1-x)] x0 = np.arange(0, 1, 0.00001) y0 = odeint(yx, [0,0], x0) plt.rc(font, size=16) plt.plot(x0, y0[:,0]); plt.show()

4G模组软件指南 | 必读篇之模块信息(hmeta)

今天我讲解的这篇关于4G模组软件的模块信息属于必读篇,望珍惜!今天我讲解的这篇关于4G模组软件的模块信息属于必读篇,望珍惜! 1、模块信息概述 模块信息是每一个模块携带的信息,就像人的身份证一样,这些信息确定了模块的唯一性; 包含设备唯一id,硬件型号,模组的硬件版本号,…

ABP框架+SqlSugar

一:使用ABP框架的主要原因包括以下几点‌: (1)安装abp框架步骤 ‌快速开发‌:ABP框架提供了一系列的代码生成器和基于集成测试的自动化测试工具,可以大大缩短开发周期、提高开发效率‌ ‌模块化设计‌:ABP框架以模块为单位进行组织和拓展,将应用程序分割成一些彼此独立的…