ToB企服应用市场:ToB评测及商务社交产业平台

标题: 最新的ffmepg.js前端VUE3实现视频、音频裁剪上传功能 [打印本页]

作者: 民工心事    时间: 2024-6-12 06:57
标题: 最新的ffmepg.js前端VUE3实现视频、音频裁剪上传功能
package.json

  1. "dependencies": {
  2.     "@ffmpeg/ffmpeg": "^0.12.10",
  3.     "@ffmpeg/util": "^0.12.1"
  4. }
复制代码
vue3组件代码

根据需要更改
  1. <script setup lang="ts">
  2. import { FFmpeg } from '@ffmpeg/ffmpeg';
  3. import { fetchFile, toBlobURL } from '@ffmpeg/util';
  4. import useInject from '@/utils/useInject';
  5. import { reactive, onUnmounted } from 'vue';
  6. const { $global, $fn } = useInject();
  7. const props: any = defineProps<{
  8.     params?: any;
  9.     url?: any;
  10. }>();
  11. let ffmpegObj: any = reactive({
  12.     file: null,
  13.     urlpre: null,
  14.     url: null,
  15.     params: {
  16.         ...(props?.params || {}),
  17.         ext: '',
  18.         starttime: 0,
  19.         endtime: 3,
  20.         maxtime: 0,
  21.     },
  22. });
  23. const ffmpeg = new FFmpeg();
  24. function filechange(e: any) {
  25.     ffmpegObj.file = e.target.files[0];
  26.     // 原视频预览方案一
  27.     const reader: any = new FileReader();
  28.     reader.readAsDataURL(ffmpegObj.file);
  29.     reader.onload = () => {
  30.         ffmpegObj.url = '';
  31.         ffmpegObj.urlpre = reader.result;
  32.         const audioElement: any = new Audio(ffmpegObj.urlpre);
  33.         audioElement.addEventListener('loadedmetadata', () => {
  34.             ffmpegObj.params.maxtime = audioElement.duration;
  35.             ffmpegObj.params.starttime = 0;
  36.             ffmpegObj.params.endtime = audioElement.duration;
  37.         });
  38.     };
  39.     // 原视频预览方案二
  40.     // const reader: any = new FileReader();
  41.     // reader.readAsArrayBuffer(ffmpegObj.file);
  42.     // let blob = null;
  43.     // reader.onload = (e: any) => {
  44.     //     if (typeof e.target.result === 'object') {
  45.     //         blob = new Blob([e.target.result]);
  46.     //     } else {
  47.     //         blob = e.target.result;
  48.     //     }
  49.     //     ffmpegObj.url = '';
  50.     //     if (blob == null) return;
  51.     //     const url = URL.createObjectURL(blob);
  52.     //     ffmpegObj.urlpre = url;
  53.     //     const audioElement = new Audio(url);
  54.     //     audioElement.addEventListener('loadedmetadata', function () {
  55.     //         ffmpegObj.params.maxtime = audioElement.duration;
  56.     //         ffmpegObj.params.starttime = 0;
  57.     //         ffmpegObj.params.endtime = audioElement.duration;
  58.     //     });
  59.     // };
  60. }
  61. async function doffmpeg() {
  62.     try {
  63.         if (!ffmpegObj.file) {
  64.             return;
  65.         }
  66.         ffmpegObj.fileext = ffmpegObj.file.name.split('.').pop();
  67.         const inputName = `input.${ffmpegObj.fileext}`;
  68.         const outputName = `output.${
  69.             ffmpegObj.params.ext ? ffmpegObj.params.ext : ffmpegObj.fileext
  70.         }`;
  71.         console.log(666.001, ffmpeg, ffmpegObj);
  72.         ffmpeg.on('log', ({ message: msg }) => {
  73.             ffmpegObj.msglogger = msg;
  74.         });
  75.         await ffmpeg.load({
  76.             coreURL: await toBlobURL(
  77.                 './ffmpeg/ffmpeg-core.js',
  78.                 'text/javascript'
  79.             ),
  80.             wasmURL: await toBlobURL(
  81.                 './ffmpeg/ffmpeg-core.wasm',
  82.                 'application/wasm'
  83.             ),
  84.             workerURL: await toBlobURL(
  85.                 `./ffmpeg/ffmpeg-core.worker.js`,
  86.                 'text/javascript'
  87.             ),
  88.         });
  89.         await ffmpeg.writeFile(inputName, await fetchFile(ffmpegObj.urlpre));
  90.         await ffmpeg.exec([
  91.             '-ss',
  92.             `${
  93.                 ffmpegObj.params.starttime !== undefined
  94.                     ? ffmpegObj.params.starttime
  95.                     : 0
  96.             }`,
  97.             '-t',
  98.             `${
  99.                 (ffmpegObj.params.endtime !== undefined
  100.                     ? ffmpegObj.params.endtime
  101.                     : 3) -
  102.                 (ffmpegObj.params.starttime !== undefined
  103.                     ? ffmpegObj.params.starttime
  104.                     : 0)
  105.             }`,
  106.             '-i',
  107.             inputName,
  108.             outputName,
  109.         ]);
  110.         ffmpegObj.data = await ffmpeg.readFile(outputName);
  111.         ffmpegObj.blob = new Blob([ffmpegObj.data.buffer], {
  112.             type:
  113.                 'video/' + ffmpegObj.params.ext
  114.                     ? ffmpegObj.params.ext
  115.                     : ffmpegObj.fileext,
  116.         });
  117.         ffmpegObj.url = URL.createObjectURL(ffmpegObj.blob);
  118.         ffmpegObj.urlpre = ''; // 清空原预览视频
  119.     } catch (err) {
  120.         alert('出错了');
  121.         throw err;
  122.     }
  123. }
  124. function blobToBase64(blob: any) {
  125.     console.log(666.3002, blob);
  126.     return new Promise((resolve, reject) => {
  127.         const fileReader = new FileReader();
  128.         fileReader.readAsDataURL(blob);
  129.         fileReader.onload = () => {
  130.             resolve(fileReader.result);
  131.         };
  132.         fileReader.onerror = () => {
  133.             reject(new Error('文件流异常'));
  134.         };
  135.     });
  136. }
  137. // function convertBlobToFile(blob, fileName) {
  138. //     blob.lastModifiedDate = new Date();
  139. //     blob.name = fileName;
  140. //     return blob;
  141. // }
  142. async function submit() {
  143.     await doffmpeg();
  144.     const resdata: any = await blobToBase64(ffmpegObj.blob);
  145.     // const resdata: any = convertBlobToFile(ffmpegObj.blob, 'aaa');
  146.     console.log(666.30002, resdata);
  147.     $fn.useApiFiles()
  148.         .request({
  149.             data: props.url
  150.                 ? { url: props.url }
  151.                 : {
  152.                       dir: 'chat/chat',
  153.                       uid: $fn.As.Uuid('CU'),
  154.                       ext:
  155.                           '.' +
  156.                           (ffmpegObj.params.ext
  157.                               ? ffmpegObj.params.ext
  158.                               : ffmpegObj.fileext),
  159.                       data: resdata,
  160.                   },
  161.         })
  162.         .then((res: any) => {
  163.             console.log(666.789, res);
  164.             props?.params?.fn(res);
  165.         })
  166.         .catch((err: any) => {
  167.             $global.tipsfn({ type: 'err', con: err });
  168.         });
  169. }
  170. //下载
  171. function downffmpeg() {
  172.     const oA: any = document.createElement('a');
  173.     oA.download =
  174.         'video_' +
  175.         Date.now() +
  176.         '.' +
  177.         (ffmpegObj.params.ext ? ffmpegObj.params.ext : ffmpegObj.fileext);
  178.     oA.href = ffmpegObj.url;
  179.     document.body.appendChild(oA);
  180.     oA.click();
  181.     // 释放 URL 对象
  182.     URL.revokeObjectURL(oA.href);
  183.     oA.remove();
  184. }
  185. onUnmounted(() => {
  186.     ffmpegObj = null;
  187. });
  188. </script>
  189. <template>
  190.     <div class="as-ff-area">
  191.         <div class="as-show-area">
  192.             <!-- <template v-if="ffmpegObj.urlpre"> -->
  193.             原视频
  194.             <video :src="ffmpegObj.urlpre" controls></video>
  195.             <!-- </template> -->
  196.             <!-- <template v-else> -->
  197.             裁剪后视频
  198.             <video :src="ffmpegObj.url" controls></video>
  199.             <!-- </template> -->
  200.             日志:
  201.             {{ ffmpegObj.params.starttime }}
  202.             -
  203.             {{ ffmpegObj.params.endtime }}
  204.             ({{ ffmpegObj.params.maxtime }})
  205.             <input
  206.                 type="range"
  207.                 v-model="ffmpegObj.params.starttime"
  208.                 min="0"
  209.                 :max="ffmpegObj.params.maxtime"
  210.             />
  211.             <input
  212.                 type="range"
  213.                 v-model="ffmpegObj.params.endtime"
  214.                 min="0"
  215.                 :max="ffmpegObj.params.maxtime"
  216.             />
  217.             <!-- <input type="number" v-model="ffmpegObj.params.starttime" />
  218.             <input type="number" v-model="ffmpegObj.params.endtime" /> -->
  219.             {{ ffmpegObj.msglogger }}
  220.             {{ ffmpegObj.msgprogress }}
  221.         </div>
  222.         <div class="as-file-area">
  223.             选择图片:
  224.             <input class="file" type="file" @change="filechange" />
  225.         </div>
  226.         <div class="as-btn-area">
  227.             <button @click="doffmpeg()">裁剪</button>
  228.             <button @click="downffmpeg()">下载</button>
  229.             <button @click="submit()">提交</button>
  230.         </div>
  231.     </div>
  232. </template>
  233. <style scoped>
  234. .as-ff-area {
  235.     width: 100%;
  236.     height: 100%;
  237.     display: flex;
  238.     flex-direction: column;
  239. }
  240. .as-btn-area {
  241.     text-align: center;
  242.     height: auto;
  243. }
  244. .as-btn-area > button {
  245.     user-select: none;
  246.     padding: 5px 12px;
  247.     margin: 15px 5px 0 5px;
  248. }
  249. .as-file-area {
  250.     padding: 5px 12px;
  251.     text-align: center;
  252.     height: auto;
  253.     width: auto;
  254.     display: inline-block;
  255.     background-color: var(--ch1);
  256. }
  257. .as-show-area {
  258.     flex-grow: 1;
  259.     width: 100%;
  260.     overflow: auto;
  261.     display: flex;
  262.     justify-content: center;
  263.     align-items: center;
  264.     flex-direction: column;
  265. }
  266. </style>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4