tips:
本地开发的时候需要在 vue.config.js 中添加
devServer: {
headers: {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
},
}
操作的文件名称中不能出现中文,否则会操作失败。。。
部署的时候需要配置 nginx 或者在后端配置。(配置在访问路径的静态资源请求中)
add_header Cross-Origin-Opener-Policy same-origin;
add_header Cross-Origin-Embedder-Policy require-corp;
1.下载引入FFmpeg
下载指定版本(最新版本使用方式不同)
npm install @ffmpeg/ffmpeg@0.10.1
npm install @ffmpeg/core@0.10.0
引入
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
2.使用
分割
<script setup>
let mp4Duration = ref(0)
const ffmpeg = createFFmpeg()
if (!ffmpeg.isLoaded()) {
ffmpeg.load().catch(err => {
console.log(err)
})
}
// 获取上传的视频文件时长
const getMp4Time = file => {
return new Promise(async (resolve, reject) => {
let url = URL.createObjectURL(file)
let audioElement = new Audio(url)
let durtaion = 0
// 下面需要注意的是在监听loadedmetadata绑定的事件中对duration直接进行赋值是无效的,需要在fun回调函数中进行赋值
audioElement.addEventListener('loadedmetadata', function () {
//音频/视频的元数据已加载时,会发生 loadedmetadata 事件
durtaion = audioElement.duration //时长以秒作为单位
fun(durtaion)
})
let fun = s => {
durtaion = s
resolve(durtaion)
}
})
}
// 分割上传视频文件
const sliceVideoFile = async file => {
let startTime = 0 // 截取开始时间 单位s
let step = 25 // 截取视频长度 单位s
let filName = file.name // 上传的文件名
let newName = 'newFile.' + file.name.split('.')[1] // 分割后的文件名 newFile.[视频格式]
try {
// fetchFile获取文件并返回一个 Uint8Array 变量供 ffmpeg.wasm 使用
await ffmpeg.FS('writeFile', filName, await fetchFile(file.raw)) // 先写入上传的视频文件
// 分割上传的视频文件,如果分割的视频小于了1s,可能没有关键帧,分割出来的视频无法播放,但是不影响合并
await ffmpeg.run('-ss', `${startTime}`, '-t', `${step}`, '-i', filName, '-vcodec', 'copy', '-acodec', 'copy', newName)
// 通过newName读取分割后的视频文件 格式为Uint8Array
let arrayBuffer = ffmpeg.FS('readFile', newName).buffer
let blob = new Blob([arrayBuffer])
// let newVideoUrl = URL.createObjectURL(blob)
// 将blob对象转换为file对象
let file11 = new File([blob], filName, { type: file.raw.type })
} catch (err) {
throw err
}
}
<script>
合并
// 将文件写入内存
await ffmpeg.FS('writeFile', 'mp4Name1.mp4', await fetchFile(file11))
await ffmpeg.FS('writeFile', 'mp4Name2.mp4', await fetchFile(file12))
// 将文件转为ts格式
await ffmpeg.run('-i', 'mp4Name1.mp4', '-c', 'copy', '-bsf:v', 'h264_mp4toannexb', '-f', 'mpegts', 'newTdsName1.ts')
await ffmpeg.run('-i', 'mp4Name2.mp4', '-c', 'copy', '-bsf:v', 'h264_mp4toannexb', '-f', 'mpegts', 'newTdsName2.ts')
// 清除缓存
await ffmpeg.FS('unlink', 'mp4Name1.mp4');
await ffmpeg.FS('unlink', 'mp4Name2.mp4');
// 合并视频
str = 'concat:newTdsName1.ts|newTdsName2.ts'
await ffmpeg.run('-i', `${str}`, '-c', 'copy', '-bsf:a', 'aac_adtstoasc', '-movflags','+faststart', 'outPut.mp4')
// 获取合并后的文件二进制流
let arrayBuffer = ffmpeg.FS('readFile', 'outPut.mp4').buffer
onUnmounted(() => { ffmpeg.exit(); })
一般运行内存为16g的电脑,合并时视频文件最大不能超过500M,否则浏览器内存将超出导致页面崩掉
参考:blog.51cto.com/u_15344825/… www.zhangxinxu.com/wordpress/2…