一、安装依赖
npm install @ffmpeg/core @ffmpeg/ffmpeg
"@ffmpeg/core": "^0.10.0",
"@ffmpeg/ffmpeg": "^0.10.1",
二、配置ffmpeg
安装好插件以后,需要配置一下代码,否则会报错:
1、在vue.config.js文件中配置请求头
devServer: {headers: {'Cross-Origin-Opener-Policy': 'same-origin','Cross-Origin-Embedder-Policy': 'require-corp'}
}
在页面中实例化ffmpeg的时候可能会报找不到模块儿的错误,最好将下载好的插件文件放到public文件夹里面就可以了 createFFmpegCore is not defined
node_modules@ffmpeg\core\dist中的三个文件复制到vue项目的public下
ffmpeg-core.js
ffmpeg-core.wasm
ffmpeg-core.worker.js
三、组件
<template><div class="video-box"><video id="video" controls object-fill="fill"></video><br /><input id="upload" type="file" accept="video/mp4" capture="camcorder" @change="upload"></div>
</template><script>
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
export default {data () {return {msg: '',videoWidth: '',videoHeight: '',duration: ''}},methods: {// 选择文件async upload (e) {console.log('start', e)console.log('start', e.target.files[0])var _this = thisif (e.target.files[0]) {var filename = e.target.files[0].namevar filetype = e.target.files[0].typeconst videoUrl = _this.getObjectURL(e.target.files[0])const video = document.getElementById('video')video.src = videoUrlthis.getVideoData().then((videoObj) => {const file = e.target.files[0]console.log('videoObj:', videoObj)const { width, height } = videoObjconst result = _this.squeezVideo(file, filename, filetype, width, height, _this.msg)result.then(res => {console.log('resultFile', res)})})}},// 压缩视频async squeezVideo (file, filename, filetype, width, height) {console.log('squeezingVideo file name: ', file.name)console.log('squeezingVideo file type: ', file.type)console.log('squeezingVideo file path: ', file.path)console.log('squeezingVideo file size: ', file.size)console.log('squeezingVideo file lastModified: ', file.lastModified)console.log('squeezingVideo file lastModifiedDate: ', file.lastModifiedDate)const _this = this// 分辨率const resolution = `${width / 2}x${height / 2}`// 实例化ffmpegconst ffmpeg = createFFmpeg({// ffmpeg路径corePath: 'ffmpeg-core.js',// 日志log: true,// 进度progress: ({ ratio }) => {_this.msg = `完成率: ${(ratio * 100.0).toFixed(1)}%`}})var { name } = filethis.msg = '正在加载 ffmpeg-core.js'// 开始加载await ffmpeg.load()this.msg = '开始压缩'// 把文件加到ffmpeg 写文件ffmpeg.FS('writeFile', name, await fetchFile(file))// await ffmpeg.run('-i', name, '-b', '2000000', '-fs', '4194304', '-preset medium', 'superfast', 'put.mp4')// 开始压缩视频await ffmpeg.run('-i', name, '-b', '2000000', '-crf', '23', '-fs', '4194304', '-s', resolution, 'put.mp4')this.msg = '压缩完成'// 压缩所完成, 读文件 压缩后的文件名称为 put.mp4const data = ffmpeg.FS('readFile', 'put.mp4')// 转换压缩后的视频格式 当前为 blob 格式var filed = _this.transToFile(data)console.log('transToFile: ', filed)return new Promise((resolve, reject) => {if (filed) {resolve({squzingFile: filed})}})},// 获取视频的宽高分辨率getVideoData () {return new Promise((resolve, reject) => {const videoElement = document.getElementById('video')videoElement.addEventListener('loadedmetadata', function () {resolve({width: this.videoWidth,height: this.videoHeight,duration: this.duration})})})},// 获取上传视频的urlgetObjectURL (file) {let url = nullwindow.URL = window.URL || window.webkitURLif (window.URL) {url = window.URL.createObjectURL(file)} else {url = URL.createObjectURL(file)}return url},// 类型转换 blob 转换 filetransToFile (data) {console.log(data)const _this = thisvar file = []// 转换bolb类型const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })// 这么写是因为文件转换是异步任务const transToFile = async (blob, fileName, fileType) => {return new window.File([blob], fileName, { type: fileType })}const textContain = transToFile(blob, 'put.mp4', 'video/mp4')// 转换完成后可以将file对象传给接口textContain.then((res) => {file.push(res)console.log('res', res)// _this.confirm(file)return file})}}
}
</script>