Js如何使用ffmpeg進行視頻剪輯和畫面截取等功能
更新時間:2024年04月11日 08:29:47 作者:Raccom
在日常處理視頻文件時常常會用到視頻片段的截取功能,FFmpeg支持該功能,下面這篇文章主要給大家介紹了關于Js如何使用ffmpeg進行視頻剪輯和畫面截取等功能的相關資料,需要的朋友可以參考下
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剪輯
<script setup> // "@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}`; // 將輸入文件保存到虛擬文件系統(tǒng) 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; // 讀取緩存 // 創(chuàng)建下載鏈接并通過回調下載保存到本地 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(); }) </script>
本地視頻文件剪輯
<template> <input type="file" @change="fileChange"> </template> <script setup> 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() // 將輸入文件保存到虛擬文件系統(tǒng) 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; // 讀取緩存 // 創(chuàng)建下載鏈接并通過回調下載保存到本地 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(); }) </script>
獲取視頻畫面截圖
<template> <input type="file" @change="fileChange"> </template> <script setup> 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() // 將輸入文件保存到虛擬文件系統(tǒng) 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 < count; i++) { let temp = i + 1; if (temp < 10) { temp = "0" + temp; } baseArr.push( arrayBufferToBase64(ffmpeg.FS("readFile", "image-" + temp + ".png")) ); } callBack && callBack(baseArr) // 釋放內存 ffmpeg.FS('unlink', inputName); } catch (e) {} } const arrayBufferToBase64 = (array) => { array = new Uint8Array(array); var length = array.byteLength; var table = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/']; var base64Str = ""; for (var i = 0; length - 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) | (num2 >>> 4)] + table[((num2 & 0b1111) << 2) | (num3 >>> 6)] + table[num3 & 0b111111]; } var lastByte = length - i; if (lastByte === 1) { var lastNum1 = array[i]; base64Str += table[lastNum1 >>> 2] + table[(lastNum1 & 0b11) << 4] + "=="; } else if (lastByte === 2) { // eslint-disable-next-line no-redeclare var lastNum1 = array[i]; var lastNum2 = array[i + 1]; base64Str += table[lastNum1 >>> 2] + table[((lastNum1 & 0b11) << 4) | (lastNum2 >>> 4)] + table[(lastNum2 & 0b1111) << 2] + "="; } return base64Str } onUnmounted(() => { ffmpeg.exit(); }) </script>
總結
到此這篇關于Js如何使用ffmpeg進行視頻剪輯和畫面截取等功能的文章就介紹到這了,更多相關Js ffmpeg視頻剪輯和畫面截取內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
js中document.referrer實現移動端返回上一頁
本文主要介紹了document.referrer實現移動端返回上一頁的方法,具有很好的參考價值,下面跟著小編一起來看下吧2017-02-02基于Bootstrap 3 JQuery及RegExp的表單驗證功能
這篇文章主要介紹了基于Bootstrap 3 JQuery及RegExp的表單驗證功能,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-02-02