import { FFmpeg } from '@ffmpeg/ffmpeg';import { fetchFile, toBlobURL } from '@ffmpeg/util';import useInject _vue3 ffmpeg">
赞
踩
"dependencies": {
"@ffmpeg/ffmpeg": "^0.12.10",
"@ffmpeg/util": "^0.12.1"
}
根据需要更改
<script setup lang="ts"> import { FFmpeg } from '@ffmpeg/ffmpeg'; import { fetchFile, toBlobURL } from '@ffmpeg/util'; import useInject from '@/utils/useInject'; import { reactive, onUnmounted } from 'vue'; const { $global, $fn } = useInject(); const props: any = defineProps<{ params?: any; url?: any; }>(); let ffmpegObj: any = reactive({ file: null, urlpre: null, url: null, params: { ...(props?.params || {}), ext: '', starttime: 0, endtime: 3, maxtime: 0, }, }); const ffmpeg = new FFmpeg(); function filechange(e: any) { ffmpegObj.file = e.target.files[0]; // 原视频预览方案一 const reader: any = new FileReader(); reader.readAsDataURL(ffmpegObj.file); reader.onload = () => { ffmpegObj.url = ''; ffmpegObj.urlpre = reader.result; const audioElement: any = new Audio(ffmpegObj.urlpre); audioElement.addEventListener('loadedmetadata', () => { ffmpegObj.params.maxtime = audioElement.duration; ffmpegObj.params.starttime = 0; ffmpegObj.params.endtime = audioElement.duration; }); }; // 原视频预览方案二 // const reader: any = new FileReader(); // reader.readAsArrayBuffer(ffmpegObj.file); // let blob = null; // reader.onload = (e: any) => { // if (typeof e.target.result === 'object') { // blob = new Blob([e.target.result]); // } else { // blob = e.target.result; // } // ffmpegObj.url = ''; // if (blob == null) return; // const url = URL.createObjectURL(blob); // ffmpegObj.urlpre = url; // const audioElement = new Audio(url); // audioElement.addEventListener('loadedmetadata', function () { // ffmpegObj.params.maxtime = audioElement.duration; // ffmpegObj.params.starttime = 0; // ffmpegObj.params.endtime = audioElement.duration; // }); // }; } async function doffmpeg() { try { if (!ffmpegObj.file) { return; } ffmpegObj.fileext = ffmpegObj.file.name.split('.').pop(); const inputName = `input.${ffmpegObj.fileext}`; const outputName = `output.${ ffmpegObj.params.ext ? ffmpegObj.params.ext : ffmpegObj.fileext }`; console.log(666.001, ffmpeg, ffmpegObj); ffmpeg.on('log', ({ message: msg }) => { ffmpegObj.msglogger = msg; }); await ffmpeg.load({ coreURL: await toBlobURL( './ffmpeg/ffmpeg-core.js', 'text/javascript' ), wasmURL: await toBlobURL( './ffmpeg/ffmpeg-core.wasm', 'application/wasm' ), workerURL: await toBlobURL( `./ffmpeg/ffmpeg-core.worker.js`, 'text/javascript' ), }); await ffmpeg.writeFile(inputName, await fetchFile(ffmpegObj.urlpre)); await ffmpeg.exec([ '-ss', `${ ffmpegObj.params.starttime !== undefined ? ffmpegObj.params.starttime : 0 }`, '-t', `${ (ffmpegObj.params.endtime !== undefined ? ffmpegObj.params.endtime : 3) - (ffmpegObj.params.starttime !== undefined ? ffmpegObj.params.starttime : 0) }`, '-i', inputName, outputName, ]); ffmpegObj.data = await ffmpeg.readFile(outputName); ffmpegObj.blob = new Blob([ffmpegObj.data.buffer], { type: 'video/' + ffmpegObj.params.ext ? ffmpegObj.params.ext : ffmpegObj.fileext, }); ffmpegObj.url = URL.createObjectURL(ffmpegObj.blob); ffmpegObj.urlpre = ''; // 清空原预览视频 } catch (err) { alert('出错了'); throw err; } } function blobToBase64(blob: any) { console.log(666.3002, blob); return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.readAsDataURL(blob); fileReader.onload = () => { resolve(fileReader.result); }; fileReader.onerror = () => { reject(new Error('文件流异常')); }; }); } // function convertBlobToFile(blob, fileName) { // blob.lastModifiedDate = new Date(); // blob.name = fileName; // return blob; // } async function submit() { await doffmpeg(); const resdata: any = await blobToBase64(ffmpegObj.blob); // const resdata: any = convertBlobToFile(ffmpegObj.blob, 'aaa'); console.log(666.30002, resdata); $fn.useApiFiles() .request({ data: props.url ? { url: props.url } : { dir: 'chat/chat', uid: $fn.As.Uuid('CU'), ext: '.' + (ffmpegObj.params.ext ? ffmpegObj.params.ext : ffmpegObj.fileext), data: resdata, }, }) .then((res: any) => { console.log(666.789, res); props?.params?.fn(res); }) .catch((err: any) => { $global.tipsfn({ type: 'err', con: err }); }); } //下载 function downffmpeg() { const oA: any = document.createElement('a'); oA.download = 'video_' + Date.now() + '.' + (ffmpegObj.params.ext ? ffmpegObj.params.ext : ffmpegObj.fileext); oA.href = ffmpegObj.url; document.body.appendChild(oA); oA.click(); // 释放 URL 对象 URL.revokeObjectURL(oA.href); oA.remove(); } onUnmounted(() => { ffmpegObj = null; }); </script> <template> <div class="as-ff-area"> <div class="as-show-area"> <!-- <template v-if="ffmpegObj.urlpre"> --> 原视频 <video :src="ffmpegObj.urlpre" controls></video> <!-- </template> --> <!-- <template v-else> --> 裁剪后视频 <video :src="ffmpegObj.url" controls></video> <!-- </template> --> 日志: {{ ffmpegObj.params.starttime }} - {{ ffmpegObj.params.endtime }} ({{ ffmpegObj.params.maxtime }}) <input type="range" v-model="ffmpegObj.params.starttime" min="0" :max="ffmpegObj.params.maxtime" /> <input type="range" v-model="ffmpegObj.params.endtime" min="0" :max="ffmpegObj.params.maxtime" /> <!-- <input type="number" v-model="ffmpegObj.params.starttime" /> <input type="number" v-model="ffmpegObj.params.endtime" /> --> {{ ffmpegObj.msglogger }} {{ ffmpegObj.msgprogress }} </div> <div class="as-file-area"> 选择图片: <input class="file" type="file" @change="filechange" /> </div> <div class="as-btn-area"> <button @click="doffmpeg()">裁剪</button> <button @click="downffmpeg()">下载</button> <button @click="submit()">提交</button> </div> </div> </template> <style scoped> .as-ff-area { width: 100%; height: 100%; display: flex; flex-direction: column; } .as-btn-area { text-align: center; height: auto; } .as-btn-area > button { user-select: none; padding: 5px 12px; margin: 15px 5px 0 5px; } .as-file-area { padding: 5px 12px; text-align: center; height: auto; width: auto; display: inline-block; background-color: var(--ch1); } .as-show-area { flex-grow: 1; width: 100%; overflow: auto; display: flex; justify-content: center; align-items: center; flex-direction: column; } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。