当前位置: 代码网 > it编程>编程语言>Javascript > Js如何使用ffmpeg进行视频剪辑和画面截取等功能

Js如何使用ffmpeg进行视频剪辑和画面截取等功能

2024年05月29日 Javascript 我要评论
ffmpeg使用场景是需要在web端进行视频的裁剪,包括使用在线视频url或本地视频文件的裁剪,以及对视频内容的截取等功能。前端进行视频操作可能会导致性能下降,最好通过后端使用java,c++进行处理

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}`;

    // 将输入文件保存到虚拟文件系统
    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();
})
</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 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()

    // 将输入文件保存到虚拟文件系统
    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视频剪辑和画面截取内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com