Js使用ffmpeg进行视频剪辑和画面截取 您所在的位置:网站首页 ae怎么截取视频片段 Js使用ffmpeg进行视频剪辑和画面截取

Js使用ffmpeg进行视频剪辑和画面截取

2024-06-15 05:28| 来源: 网络整理| 查看: 265

ffmpeg

使用场景是需要在web端进行视频的裁剪,包括使用 在线视频url 或 本地视频文件 的裁剪,以及对视频内容的截取等功能。

前端进行视频操作可能会导致性能下降,最好通过后端使用java,c++进行处理,本文的案例是备选方案。

注意:

以下所有的使用案例均基于vue3 setup。

同时由于@ffmpeg版本不同会导致使用的api不同,使用案例前需要注意@ffmpeg版本问题。

如果使用的是0.12+需要使用新的api,详情请看 文档

npm npm install @ffmpeg/ffmpeg@^0.10.0 npm install @ffmpeg/core@^0.10.0 在线视频url剪辑 // "@ffmpeg/core": "^0.10.0", // "@ffmpeg/ffmpeg": "^0.10.0", import { ref, onMounted, onUnmounted } from 'vue' import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'; const ffmpeg = createFFmpeg({ log: true }); const fileType = ref("") // 视频文件类型 /** * 根据在线的视频地址截取片段 * @param {string} url 在线视频链接 * @param {number|string} startTime 截取开始时间 * @param {number|string} endTime 截取结束时间 * @param {Function} callBack 回调函数 */ const videoCut = async (url, startTime, endTime, callBack) => { if (!ffmpeg.isLoaded()) { await ffmpeg.load(); } if(!url) return; fileType.value = url.split(".").pop() const inputName = `input.${fileType.value}`; const outputName = `output.${fileType.value}`; // 将输入文件保存到虚拟文件系统 await ffmpeg.FS('writeFile', inputName, await fetchFile(url)); // 运行 FFmpeg 命令 try { await ffmpeg.run( '-ss', `${startTime}`, '-t', `${endTime - startTime}`, '-i', inputName, '-vcodec', 'copy', '-acodec', 'copy', outputName ); // 读取输出文件 let arrayBuffer = ffmpeg.FS('readFile', outputName).buffer; // 读取缓存 // 创建下载链接并通过回调下载保存到本地 const fileUrl = URL.createObjectURL(new Blob([arrayBuffer])); // 转为Blob URL callBack && callBack(fileUrl) // 释放内存 ffmpeg.FS('unlink', inputName); ffmpeg.FS('unlink', outputName); } catch (e) { } } const downloadFile = (url, fileName = `clip.${fileType.value}`) => { const link = document.createElement('a'); link.href = url; link.download = fileName; link.click(); } onMounted(() => { videoCut("https://视频.mp4", 0, 3, downloadFile) }) onUnmounted(() => { ffmpeg.exit(); }) 本地视频文件剪辑 import { ref, onUnmounted } from 'vue' import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'; const ffmpeg = createFFmpeg({ log: true }); const fileType = ref("") // 视频文件类型 const fileChange = (e) => { if (!e.target.files[0]) return; const file = e.target.files[0]; fileType.value = file.name.split(".").pop() videoCut(file, 0, 3, downloadFile) } /** * 根据选择的视频文件截取片段 * @param {file} file 选择的视频文件 * @param {number|string} startTime 截取开始时间 * @param {number|string} endTime 截取结束时间 * @param {Function} callBack 回调函数 */ const videoCut = async (file, startTime, endTime, callBack) => { if (!ffmpeg.isLoaded()) { await ffmpeg.load(); } if(!file) return; const inputName = `input.${fileType.value}`; const outputName = `output.${fileType.value}`; const orgFileBuffer = await file.arrayBuffer() // 将输入文件保存到虚拟文件系统 await ffmpeg.FS('writeFile', inputName, await fetchFile(new Blob([orgFileBuffer]))); try { await ffmpeg.run( '-ss', `${startTime}`, '-t', `${endTime - startTime}`, '-i', inputName, '-vcodec', 'copy', '-acodec', 'copy', outputName ); // 读取输出文件 let arrayBuffer = ffmpeg.FS('readFile', outputName).buffer; // 读取缓存 // 创建下载链接并通过回调下载保存到本地 const fileUrl = URL.createObjectURL(new Blob([arrayBuffer])); // 转为Blob URL callBack && callBack(fileUrl) // 释放内存 ffmpeg.FS('unlink', inputName); ffmpeg.FS('unlink', outputName); } catch (e) {} } const downloadFile = (url, fileName = `clip.${fileType.value}`) => { const link = document.createElement('a'); link.href = url; link.download = fileName; link.click(); } onUnmounted(() => { ffmpeg.exit(); }) 获取视频画面截图 import { ref, onUnmounted } from 'vue' import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'; const ffmpeg = createFFmpeg({ log: true }); const fileType = ref("") // 视频文件类型 const fileChange = (e) => { if (!e.target.files[0]) return; const file = e.target.files[0]; fileType.value = file.name.split(".").pop() // 由于这里一秒截取一帧 ,截取5次, 所以如果视频不足5秒会导致截取和读取失败 // 回调中是base64图片组成的数组,需要在前面拼接 "data:image/png;base64," ,然后在img的src中赋值即可 videoFrame(file, 5, 1, (data) => console.log(data)) } /** * 根据选择的视频文件获取视频截图 * @param {file} file 选择的视频文件 * @param {number|string} count 截取图片的次数 * @param {number|string} interval 截取图片的间隔 * @param {Function} callBack 回调 */ const videoFrame = async (file, count, interval, callBack) => { if (!ffmpeg.isLoaded()) { await ffmpeg.load(); } if(!file) return; const inputName = `input.${fileType.value}`; const orgFileBuffer = await file.arrayBuffer() // 将输入文件保存到虚拟文件系统 await ffmpeg.FS('writeFile', inputName, await fetchFile(new Blob([orgFileBuffer]))); try { await ffmpeg.run( "-i", inputName, "-r", `${interval}`, "-ss", "0", "-vframes", `${count}`, "-f", "image2", "-s", "88*50", "image-%02d.png" ); const baseArr = [] for (let i = 0; i = 3; i += 3) { var num1 = array[i]; var num2 = array[i + 1]; var num3 = array[i + 2]; base64Str += table[num1 >>> 2] + table[((num1 & 0b11) > 4)] + table[((num2 & 0b1111) > 6)] + table[num3 & 0b111111]; } var lastByte = length - i; if (lastByte === 1) { var lastNum1 = array[i]; base64Str += table[lastNum1 >>> 2] + table[(lastNum1 & 0b11) > 2] + table[((lastNum1 & 0b11) > 4)] + table[(lastNum2 & 0b1111)


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有