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

这篇具有很好参考价值的文章主要介绍了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.0

npm 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"
            );

整合

可以在添加时对图片的类型进行判断,执行不同的添加逻辑文章来源地址https://www.toymoban.com/news/detail-759952.html

/**
 * 将图片合成到视频中
 * @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 URL
        const 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的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C# 使用Bitmap 将byte[] 转成.jpg/.png/gif等图片

    在 C# 中,你可以使用 System.Drawing 命名空间中的 Bitmap 类来将 byte[] 转换为 .jpg 图片。以下是一个示例代码: 在上面的示例中,GetImageBytes 方法是一个用于获取图片的 byte[] 数据的示例方法。你需要根据实际情况自行实现该方法,从文件、网络等地方读取图片数据,并返回 byt

    2024年01月19日
    浏览(36)
  • 【FFmpeg】视频与图片互相转换 ( 视频与 JPG 静态图片互相转换 | 视频与 GIF 动态图片互相转换 )

    执行 命令 , 将 输入文件 input.mp4 中的 第 2 秒 开始的 1 帧数据 转为一张 848x480 像素的图片 , 输出到 output.jpg 文件中 ; 上述命令解析 : -i input.mp4 : 指定输入文件为 input.mp4 , -i 参数用于设置输入文件 ; -y : 设置 如果输出文件已存在 , 直接覆盖 , 如果不设置该选项 , 会中断执行

    2024年04月23日
    浏览(47)
  • 使用ffmpeg实现给音频,视频添加水印的操作

    本文主要针对ffmpeg进行整理,从而解决在现实中可能存在的问题。 这里参考的是 Java后台用ffmpeg命令给视频添加水印 - ^身后有尾巴^ - 博客园 (cnblogs.com) 1:先去ffmpeg官网下载其压缩包  Download FFmpeg 下载,解压到指定位置  2.将压缩包拷贝到你想的任意位置并解压,正常解压出

    2023年04月08日
    浏览(40)
  • 音视频剪辑|FFMPEG|windows10下的音视频格式转换,遮挡填充,GIF动图制作,背景音频抽取,替换

    最近对于音视频和图像的处理问题比较感兴趣,但发现很多目前需要的功能要么需要付费但不会过于麻烦,要么比较麻烦,很可能某个功能实现需要安装很多软件 例如,视频转GIF动图,该功能的实现要么使用Photoshop全家桶,要么找在线网站,或者是wps充会员,或者找其它方法

    2024年02月20日
    浏览(56)
  • gocv读取gif多帧图像,mp4视频图像,opencv,VideoCaptureFile,opencv_ffmpeg

    读取GIF图像 opencv中无法读取gif图像,这是由于license原因。转而使用 videocapture 或者第三方的 PIL 库(Python),但是其实Golang的基础库 image 中就有读取gif图像的。于是一个简单的示例如下 这里只会播放一遍gif图像,我们还可以解析gif中的LoopCount来增加循环播放的逻辑。 读取

    2024年02月12日
    浏览(51)
  • Js使用ffmpeg进行视频剪辑和画面截取

    使用场景是需要在web端进行视频的裁剪,包括使用 在线视频url 或 本地视频文件 的裁剪,以及对视频内容的截取等功能。 前端进行视频操作可能会导致性能下降,最好通过后端使用java,c++进行处理,本文的案例是备选方案。 注意: 以下所有的使用案例均基于vue3 setup。 同时

    2024年02月07日
    浏览(37)
  • Vue 3 + ffmpeg + wasm 实现前端视频剪辑、音频剪辑、音波展示、视频抽帧、gif抽帧、帧播放器、字幕、贴图、时间轴、素材轨道

    预览 www.bilibili.com/video/BV1YT411Y7YJ 技术栈: 💪 Vue 3、Vue-Router 4、Vite、pnpm、esbuild、TypeScript ☀️ Pinia 状态管理 🌪 Tailwind 原子css集成 💥 ffmpeg、wasm 底层音视频处理集成 功能 多轨道时间轴,支持帧缩放,时间缩放 支持多种类型轨道的添加删除 多功能轨道调节,支持音视频轨

    2024年02月11日
    浏览(52)
  • 【JS】纯web端使用ffmpeg实现的视频编辑器

    废话不多,先上视频。 ffmpeg编辑器 这是一个纯前端实现的视频编辑器,用的ffmpeg的wasm,web框架用的vue3。界面手撸。 用vite的vue3模板创建一个就可以。 package.json 创建页面和路由,用的vue-router,简单的添加一下。 router.js 主要项目结构 组件代码 progress-dialog.vue resource-item.vue t

    2024年02月12日
    浏览(44)
  • windows使用ffmpeg将MP4转m3u8使用参数详解,视频添加水印和压缩

    目录 背景: 一、什么是m3u8: 二、为什么使用m3u8: 三、安装ffmpeg: 1、下载后直接解压: 2、配置环境变量: 四、开始转换m3u8: 五、视频添加水印和压缩: 1. 给视频加上水印图片 2.输出视频的尺寸 3.输出文件的起始文件 4.输出文件的最小大小 和 最大的大小(会影响视频质量

    2024年02月07日
    浏览(62)
  • 利用Python将照片按“拍摄日期”分类——包括JPG、PNG、GIF、HEIC

            一切的起因是因为换了新手机 (-,-),旧手机上的照片实在是太多了所以想腾出大部分到PC上面来释放一些存储空间。但是首先出现的问题就是照片有6000多个文件而且全都集中在一起,没有进行任何的分类。         所以我初步的想法,是按照日期时间进行分

    2024年02月22日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包