当前位置: 首页 > news >正文

Js使用ffmpeg在视频中添加png或gif

Js使用ffmpeg在视频中添加png或gif

ffmpeg

使用场景是需要在web端对视频进行编辑 添加图片和gif。


注意:

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

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

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


npm

npm install @ffmpeg/ffmpeg@^0.11.0npm install @ffmpeg/core@^0.11.0

视频添加png

<template></template><script setup>
import { ref, onUnmounted, onMounted } from 'vue'
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';const ffmpeg = createFFmpeg({ log: true });
const fileType = ref("") // 视频文件类型/*** 将图片合成到视频中* @param {string} url 视频在线地址* @param {object} picItem 图片素材对象* @param {string} picItem.startT 图片素材出现的开始时间* @param {number} picItem.duration 素材的出现持续时间* @param {number} picItem.scale 素材的放大比例* @param {string} picItem.url 图片素材url地址* @param {number} picItem.x 素材离视频顶部的距离* @param {number} picItem.y 素材离视频左侧的距离* @return {Promise<{outputName: string, fileUrl: string}> | undefined}*/
const videoCompose = async (url, picItem) => {if (!ffmpeg.isLoaded()) {await ffmpeg.load();}if (!url) return;const { duration, scale, startT, url: picUrl, x, y } = picItem;fileType.value = url.split(".").pop();const inputName = `input.${fileType.value}`;const outputName = `output.${fileType.value}`;const imageType = picUrl.split(".").pop();const imageFileName = `image.${imageType}`;await ffmpeg.FS('writeFile', inputName, await fetchFile(url));await ffmpeg.FS('writeFile', imageFileName, await fetchFile(picUrl));// 运行 FFmpeg 命令try {await ffmpeg.run(`-i`, `${inputName}`,`-i`, `${imageFileName}`,`-filter_complex`, `[1:v]scale=iw*${(scale).toFixed(1)}:ih*${(scale).toFixed(1)}[scaled];[0:v][scaled]overlay=${x}:${y}:enable='between(t,${+startT},${+startT + duration})'`,`${outputName}`,"-hide_banner");// 读取输出文件let arrayBuffer = ffmpeg.FS('readFile', outputName).buffer; // 读取缓存// 创建下载链接并通过回调下载保存到本地const fileUrl = URL.createObjectURL(new Blob([arrayBuffer])); // 转为Blob URL// 释放内存ffmpeg.FS('unlink', inputName);ffmpeg.FS('unlink', outputName);return {fileUrl,outputName};} catch (e) {console.log(e);}
}const downloadFile = (url, fileName = `clip.mp4`) => {const link = document.createElement('a');link.href = url;link.download = fileName;link.click();
}onMounted(async () => {const {fileUrl} = await videoCompose("http://xxx.mp4", {duration: 3,scale: 1,startT: "0.00",url: 'http://xxx.png',x: 100,y: 100})downloadFile(fileUrl)
})onUnmounted(() => {ffmpeg.exit();
})
</script>

视频添加gif

流程与添加图片类似,但添加滤镜的命令不相同。

/*执行FFmpeg命令的部分替换`-ignore_loop`, `0` 让gif图片循环播放 否则只播放一次`-itsoffset`, `${+startT}` gif图片在视频中出现时间fade=t=in:st=${+startT}:d=1:alpha=1[wm]; gif图片在视频中淡入的时间:shortest=1 视频的时长为初始视频时长 否则由于gif添加会导致视频时间增长:enable='between(t,${+startT},${+startT + duration})' gif的出现时间"-hide_banner" 隐藏ffmpeg的部分信息
*/
await ffmpeg.run(`-i`, `${inputName}`,`-ignore_loop`, `0`,`-itsoffset`, `${+startT}`,`-i`, `${imageFileName}`,`-filter_complex`, `[0:0]scale=iw:ih[a];[1:0]scale=iw*${(scale).toFixed(1)}:ih*${(scale).toFixed(1)},fade=t=in:st=${+startT}:d=1:alpha=1[wm];[a][wm]overlay=x=${x}:y=${y}:shortest=1:enable='between(t,${+startT},${+startT + duration})'`,`${outputName}`,"-hide_banner");

整合

可以在添加时对图片的类型进行判断,执行不同的添加逻辑

/*** 将图片合成到视频中* @param {string} url 视频在线地址* @param {object} picItem 图片素材对象* @param {string} picItem.startT 图片素材出现的开始时间* @param {number} picItem.duration 素材的出现持续时间* @param {number} picItem.scale 素材的放大比例* @param {string} picItem.url 图片素材url地址* @param {number} picItem.x 素材离视频顶部的距离* @param {number} picItem.y 素材离视频左侧的距离* @return {Promise<{outputName: string, fileUrl: string}> | undefined}*/
const videoCompose = async (url, picItem) => {if (!ffmpeg.isLoaded()) {await ffmpeg.load();}if (!url) return;const {duration, scale, startT, url: picUrl, x, y} = picItem;const type = url.split(".").pop();const inputName = `input.${type}`;const outputName = `output.${type}`;const imageType = picUrl.split(".").pop();const imageFileName = `image.${imageType}`;// 将输入文件保存到虚拟文件系统if (url.startsWith('blob:')) {// 处理 Blob URLconst arrayBuffer = await fetchBlobAsArrayBuffer(url);ffmpeg.FS('writeFile', inputName, new Uint8Array(arrayBuffer));} else if (url.startsWith('http://') || url.startsWith('https://')) {// 处理网络地址await ffmpeg.FS('writeFile', inputName, await fetchFile(url));}await ffmpeg.FS('writeFile', imageFileName, await fetchFile(picUrl));// 运行 FFmpeg 命令try {if (imageType === 'gif') {await ffmpeg.run(`-i`, `${inputName}`,`-ignore_loop`, `0`,`-itsoffset`, `${+startT}`,`-i`, `${imageFileName}`,`-filter_complex`, `[0:0]scale=iw:ih[a];[1:0]scale=iw*${(scale).toFixed(1)}:ih*${(scale).toFixed(1)},fade=t=in:st=${+startT}:d=1:alpha=1[wm];[a][wm]overlay=x=${x}:y=${y}:shortest=1:enable='between(t,${+startT},${+startT + duration})'`,`${outputName}`,"-hide_banner");} else {await ffmpeg.run(`-i`, `${inputName}`,`-i`, `${imageFileName}`,`-filter_complex`, `[1:v]scale=iw*${(scale).toFixed(1)}:ih*${(scale).toFixed(1)}[scaled];[0:v][scaled]overlay=${x}:${y}:enable='between(t,${+startT},${+startT + duration})'`,`${outputName}`,"-hide_banner");}// 读取输出文件let arrayBuffer = ffmpeg.FS('readFile', outputName).buffer; // 读取缓存// 创建下载链接并通过回调下载保存到本地const fileUrl = URL.createObjectURL(new Blob([arrayBuffer])); // 转为Blob URL// 释放内存ffmpeg.FS('unlink', inputName);ffmpeg.FS('unlink', outputName);return {fileUrl,outputName};} catch (e) {console.log(e);}
}

相关文章:

Js使用ffmpeg在视频中添加png或gif

Js使用ffmpeg在视频中添加png或gif ffmpeg 使用场景是需要在web端对视频进行编辑 添加图片和gif。 注意: 以下所有的使用案例均基于vue3 setup。 同时由于ffmpeg版本不同会导致使用的api不同&#xff0c;使用案例前需要注意ffmpeg版本问题。 如果使用的是0.12需要使用新的…...

多线程 Leetcode 打印零与奇偶数

现有函数 printNumber 可以用一个整数参数调用&#xff0c;并输出该整数到控制台。 例如&#xff0c;调用 printNumber(7) 将会输出 7 到控制台。 给你类 ZeroEvenOdd 的一个实例&#xff0c;该类中有三个函数&#xff1a;zero、even 和 odd 。ZeroEvenOdd 的相同实例将会传递…...

杭电oj--数列有序

有n(n<100)个整数&#xff0c;已经按照从小到大顺序排列好&#xff0c;现在另外给一个整数x&#xff0c;请将该数插入到序列中&#xff0c;并使新的序列仍然有序。 输入数据包含多个测试实例&#xff0c;每组数据由两行组成&#xff0c;第一行是n和m&#xff0c;第二行是已…...

PHPEXCEL解决行数超过65536不显示问题

起因自然是导出数据到excel文件时&#xff0c;数据缺少现象。 百度讲解是将xls文件另存为xlsx文件。 除了这里的原因&#xff0c;还有一点是phpExcel存在两个写入类PHPExcel_Writer_Excel2007和PHPExcel_Writer_Excel5&#xff0c;而只有PHPExcel_Writer_Excel2007支持超过65…...

新媒体时代如何做好新型的网络口碑营销?

从人类开始交换商品的时代开始&#xff0c;口碑营销就已经存在&#xff0c;是靠口耳传播的营销方式。小马识途认为进入当今移动互联网时代&#xff0c;口碑营销又有了新的发展&#xff0c;网络口碑营销推广开始普及。营销人员将传统口碑营销与移动互联网营销相结合&#xff0c;…...

MySQL中InnoDB插入缓冲区(Insert Buffer)

一、插入缓冲区的基本原理 插入缓冲区&#xff08;Insert Buffer&#xff0c;也称作 Change Buffer&#xff09;&#xff0c;是InnoDB存储引擎的一种内部机制&#xff0c;它允许系统将对非聚集索引页的写操作&#xff08;例如插入、删除和更新&#xff09;暂时缓存在内存中&am…...

VUE前端判断是电脑端还是移动端

背景需求 ruoyi框架&#xff0c;前后端分离。现在要在用户访问的时候根据不同的设备跳转到不同的登录页面。 教程 router/index.js 修改src/router/index.js&#xff0c;在这里增加自己的要跳转的页面 permission.js 在白名单中添加自己的登录页面 增加以下识别的代码 le…...

OpenGL —— 2.8、漫游之摄像机飞行移动(附源码,glfw+glad)

源码效果 C源码 纹理图片 需下载stb_image.h这个解码图片的库&#xff0c;该库只有一个头文件。 具体代码&#xff1a; vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; layout(location 1) in vec2 aUV;out vec2 outUV;uniform mat4 _modelMatrix; …...

AM@麦克劳林公式逼近以及误差分析

abstract 麦克劳林公式及其近似表示的应用误差估计和分析 Lagrange型泰勒公式的估计误差 由Lagrange型余项泰勒公式可知,多项式 p n ( x ) p_n(x) pn​(x)近似表达函数 f ( x ) f(x) f(x)时,其误差为 ∣ R n ( x ) ∣ |R_{n}(x)| ∣Rn​(x)∣ R n ( x ) R_{n}(x) Rn​(x) f …...

gitlab 离线安装问题解决:NOKEY,signature check fail

1&#xff0c;rpm安装gitlab问题 test1:/opt # rpm -ivh gitlab-ce-16.0.3-ce.0.el7.x86_64.rpm --force warning: gitlab-ce-16.0.3-ce.0.el7.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID f27eab47: NOKEY error: [upel]: gitlab-ce NOKEY error: [upel]: gitlab-ce …...

uniapp使用uQRCode绘制二维码,下载到本地,调起微信扫一扫二维码核销

1.效果 2.在utils文件夹下创建uqrcode.js // uqrcode.js //--------------------------------------------------------------------- // github https://github.com/Sansnn/uQRCode //---------------------------------------------------------------------let uQRCode {…...

手写一个PrattParser基本运算解析器3: 基于Swift的PrattParser的项目概述

点击查看 基于Swift的PrattParser项目 PrattParser项目概述 前段时间一直想着手恶补 编译原理 的相关知识, 一开始打算直接读大学的 编译原理, 虽然内容丰富, 但是着实抽象难懂. 无意间看到B站的熊爷关于普拉特解析器相关内容, 感觉是一个非常好的切入点.所以就写了基于Swift版…...

三江学院“火焰杯”软件测试高校就业选拔赛颁奖仪式

11月25日下午&#xff0c;“火焰杯”软件测试开发选拔赛及三江-慧科卓越工程师班暑期编程能力训练营颁奖仪式在s楼会议室隆重举行。计算机科学与工程学院院长刘亚军、副院长叶传标、曹阳、吴德、院党总支副书记王兰英、系主任杨少雄、慧科企业代表尹沁伊人、项目负责人王旭出席…...

面试题-消息中间件篇-主流的消息中间件

消息中间件篇 第一章 主流的消息中间件对比 1、主流的消息中间件有 Kafka、RabbitMQ、ActiveMQ 等。 Kafka&#xff1a; Kafka 是一种高吞吐量、分布式、可扩展的发布/订阅消息系统&#xff0c;主要用于大数据处理和分析。Kafka 采用消息日志的方式来存储消息&#xff0c;可以…...

PyQt学习笔记-获取Hash值的小工具

目录 一、概述1.1 版本信息&#xff1a;1.2 基本信息&#xff1a;1.2.1 软件支持的内容&#xff1a;1.2.2 支持的编码格式 1.3 软件界面图 二、代码实现2.1 View2.2 Controller2.3 Model 三、测试示例 一、概述 本工具居于hashlibPyQtQFileDialog写的小工具&#xff0c;主要是…...

【(数据结构)— 双向链表的实现】

&#xff08;数据结构&#xff09;— 双向链表的实现 一.双向链表的结构二. 双向链表的实现2.1 头文件 ——双向链表的创建及功能函数的定义2.2 源文件 ——双向链表的功能函数的实现2.3 源文件 ——双向链表功能的测试2.4 双向链表各项功能测试运行展示2.4.1 双向链表的初始化…...

酷克数据发布HD-SQL-LLaMA模型,开启数据分析“人人可及”新时代

随着行业数字化进入深水区&#xff0c;企业的关注点正在不断从“数字”价值转向“数智”价值。然而&#xff0c;传统数据分析的操作门槛与时间成本成为了掣肘数据价值释放的阻力。常规的数据分析流程复杂冗长&#xff0c;需要数据库管理员设计数据模型&#xff0c;数据工程师进…...

FL Studio21最新中文破解进阶高级完整版安装下载教程

目前水果软件最版本是FL Studio21&#xff0c;它让你的计算机就像是全功能的录音室&#xff0c;大混音盘&#xff0c;非常先进的制作工具&#xff0c;让你的音乐突破想象力的限制。喜欢音乐制作的小伙伴千万不要错过这个功能强大&#xff0c;安装便捷的音乐软件哦&#xff01;如…...

MDN--Web性能

CSS 动画与 JavaScript 动画 动画的实现可以有很多种方式&#xff0c;比如 CSS transition 和 animation 或者基于 JavaScript 的动画(使用 requestAnimationFrame()) CSS 过渡和动画 CSS transiton :创建当前样式与结束状态样式之间的动画。尽管一个元素处于过渡状态中&…...

Vue3.js:自定义组件 v-model

Vue3的自定义v-model和vue2稍有不同 文档 https://cn.vuejs.org/guide/components/v-model.html 目录 原生组件自定义组件CustomInput实现代码1CustomInput实现代码2 v-model 的参数 原生组件 <input v-model"searchText" />等价于 <input:value"s…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

【WebSocket】SpringBoot项目中使用WebSocket

1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖&#xff0c;添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...