一、安装依赖
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 = this
if (e.target.files[0]) {
var filename = e.target.files[0].name
var filetype = e.target.files[0].type
const videoUrl = _this.getObjectURL(e.target.files[0])
const video = document.getElementById('video')
video.src = videoUrl
this.getVideoData().then((videoObj) => {
const file = e.target.files[0]
console.log('videoObj:', videoObj)
const { width, height } = videoObj
const 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}`
// 实例化ffmpeg
const ffmpeg = createFFmpeg({
// ffmpeg路径
corePath: 'ffmpeg-core.js',
// 日志
log: true,
// 进度
progress: ({ ratio }) => {
_this.msg = `完成率: ${(ratio * 100.0).toFixed(1)}%`
}
})
var { name } = file
this.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.mp4
const 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
})
})
})
},
// 获取上传视频的url
getObjectURL (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
},
// 类型转换 blob 转换 file
transToFile (data) {
console.log(data)
const _this = this
var 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>