Js使用ffmpeg进行视频剪辑和画面截取
ffmpeg
使用场景是需要在web端进行视频的裁剪,包括使用 在线视频url 或 本地视频文件 的裁剪,以及对视频内容的截取等功能。
前端进行视频操作可能会导致性能下降,最好通过后端使用java,c++进行处理,本文的案例是备选方案。
注意:
以下所有的使用案例均基于vue3 setup。
同时由于@ffmpeg版本不同会导致使用的api不同,使用案例前需要注意@ffmpeg版本问题。
如果使用的是0.12+需要使用新的api,详情请看 文档
npm
npm install @ffmpeg/ffmpeg@^0.10.0npm 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}`;// 将输入文件保存到虚拟文件系统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 URLcallBack && 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()// 将输入文件保存到虚拟文件系统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 URLcallBack && 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()// 将输入文件保存到虚拟文件系统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-redeclarevar 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进行视频剪辑和画面截取
ffmpeg 使用场景是需要在web端进行视频的裁剪,包括使用 在线视频url 或 本地视频文件 的裁剪,以及对视频内容的截取等功能。 前端进行视频操作可能会导致性能下降,最好通过后端使用java,c进行处理,本文的案例是备选方…...
Linux基本命令,基础知识
进到当前用户目录:cd ~ 回到上级目录:cd .. 查看当前目录层级:pwd 创建目录:mkdir mkdir ruanjian4/linux/zqm41 -p级联创建文件夹(同时创建多个文件夹需要加-p) 查看详细信息:ls -l (即 ll) 查看所有详细信息:ls -al 隐藏文件是以.开头的 查看:l…...
【Android知识笔记】进程通信(三)
在上一篇探索Binder通信原理时,提到了内存映射的概念,其核心是通过mmap函数,将一块 Linux 内核缓存区映射到一块物理内存(匿名文件),这块物理内存其实是作为Binder开辟的数据接收缓存区。这里有两个概念,需要理解清楚,那就是操作系统中的虚拟内存和物理内存,理解了这两…...
云上亚运:所使用的高新技术,你知道吗?
作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号:网络豆云计算学堂 座右铭:低头赶路,敬事如仪 个人主页: 网络豆的主页 目录 前言 一.什么是云上亚运会 二.为什么要使用云…...
数据结构简述,时间、空间复杂度,学习网站推荐
目录 IT 学习路线 相关坚韧大厚书 相关有趣/耐看书或视频 数据结构与算法学习网站推荐 刷题 时间、空间复杂度 数据结构简述 基本概念 数据结构与算法简述和CS综述整理。本文非基础的教程,本文会列出大量学习和参考网站。老惯例,一个文章是一个集…...
在线安装qt5.15之后任意版本
下载qt现在安装包: window安装包链接 进入cmd,用命令行打开安装包,并指定组件下载地址(这个是关键,之前用的是腾讯镜像,出现了版本灰色无法选中问题) .\qt-unified-windows-x64-4.6.1-online…...
【kafka实战】01 3分钟在Linux上安装kafka
本节采用docker安装Kafka。采用的是bitnami的镜像。Bitnami是一个提供各种流行应用的Docker镜像和软件包的公司。采用docker的方式3分钟就可以把我们想安装的程序运行起来,不得不说真的很方便啊,好了,开搞。使用前提:Linux虚拟机&…...
yum安装mysql8
记录一下安装过程用于后面项目参考 目录 说明安装步骤yum安装默认目录修改默认的数据目录必要的my.cnf属性修改卸载Mysql 说明 一般情况下都是docker安装,部分特殊情况下,例如老外的项目部分禁用docker,那一般二进制安装或者yum直接安装。 …...
十五)Stable Diffusion使用教程:另一个线稿出3D例子
案例:黄金首饰出图 1)线稿,可以进行色阶加深,不易丢失细节; 2)文生图,精确材质、光泽、工艺(抛光、拉丝等)、形状(包括深度等,比如镂空)和渲染方式(3D、素描、线稿等)提示词,负面提示词; 3)seed调-1,让ai随机出图; 4)开启controlnet,上传线稿图,选择cann…...
2023icpc网络预选赛I. Pa?sWorD(dp)
题目给定字符串长度n以及字符串s 其中出现小写字母可以代表小写字母和大写字母 比如a可以代表a和A 出现?可以代表26个小写字母和26个大写字母和10个数字 出现大写字母和数字就是原本的数 同时要求大写字母,小写字母,数字一定都存在替换完的字符串中…...
maven本地安装jar包
在实际开发中,有些jar包不能通过公共库下载,只能本地安装。可以按照以下步骤操作: 1、安装命令 mvn install:install-file -DgroupIdcom.chinacreator.sm -DartifactIdfbm-sm-common -Dversion0.0.1 -Dpackagingjar -Dfile../newJar/fbm-sm…...
QT中的inherits
目录 简介: 实例: 简介: 在Qt中,可以使用inherits函数来判断一个对象是否属于某个类或其派生类。inherits函数是QObject类的成员函数,因此只能用于继承自QObject的类的对象。 以下是inherits函数的一般用法…...
全国职业技能大赛云计算--高职组赛题卷①(容器云)
全国职业技能大赛云计算--高职组赛题卷①(容器云) 第二场次题目:容器云平台部署与运维任务1 Docker CE及私有仓库安装任务(5分)任务2 基于容器的web应用系统部署任务(15分)任务3 基于容器的持续…...
基于springboot+vue的入校申报审批系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...
安卓逆向 - EdXposed LSPosed VirtualXposed
一、引言 接上篇:安卓逆向 - Xposed入门教程_小馒头yy的博客-CSDN博客 我们介绍了Xposed入门安装使用,但是只支持到Android 8,并且安装模块需要重启。今天我们来看看Xposed的其他版本。 二、各种Xposed框架对比 1、Xposed 只支持到安卓8&…...
Linux三大搜索指令的区别
find:可以在指定的路径下进行文件的搜索 —— 真的在磁盘文件中查找 例如find /usr/bin/ -name ls which 可以在指令路径下,/usr/bin,搜索指令文件 例如:which ls whereis:在系统特定的路径下查找,既可以找到可执行程序ÿ…...
C++ -- 特殊类设计
目录 设计一个类,不能被拷贝 C98的做法 C11的做法 设计一个类,只能在堆上创建对象 实现方式1 实现方式2 设计一个类,只能在栈上创建对象 实现方式1 方式1的优化 实现方式2 设计一个类,不能被继承 设计模式 什么是设计…...
指针和数组笔试题的透析
指针---进阶篇(三) 一、前言二、一维数组例题透析:三、指针笔试题1.例一:2.例二:3.例三:4.例四:5.例五:6.例六: 一、前言 那么好了好了,宝子们,从…...
「UG/NX」Block UI 超级点SuperPoint
✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#...
Linux——kafka常用命令
一、Kafka的常用命令包括: 1. 启动Zookeeper服务 前台启动: ./bin/zookeeper-server-start.sh config/zookeeper.properties 后台启动: ./bin/zookeeper-server-start.sh -daemon config/zookeeper.properties 2. 停止Zookeeper服务 .…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
