Js使用ffmpeg在视频中合成音频背景音乐

Js使用ffmpeg在视频中合成音频背景音乐

ffmpeg

使用场景是需要在web端对视频的背景音乐进行混音合成。


注意:

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

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

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


npm

npm install @ffmpeg/ffmpeg@^0.11.0

npm install @ffmpeg/core@^0.11.0

视频中合成背景音乐

<template></template>

<script setup>
import {
      ref, onUnmounted, onMounted } from 'vue'
import {
      createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';

const ffmpeg = createFFmpeg({
      log: true });

/**
 * 根据在线的音频地址将音频合成到视频背景音乐中
 * @param {string} url 在线视频链接
 * @param {string} type 视频类型
 * @param {object} voiceItem 音频素材对象
 * @param {string} voiceItem.startT 音频素材出现的开始时间
 * @param {number} voiceItem.url 音频素材的地址url
 */
const videoVoiceCompose = async (url, type, voiceItem) => {
     
    if (!ffmpeg.isLoaded()) {
     
        await ffmpeg.load();
    }
    if (!url) return;

    const {
     url: voiceUrl, startT: startTime} = voiceItem;

    const inputName = `input.${ type}`;
    const outputName = `output.${ type}`;
    const voiceType = voiceUrl.split(".").pop();
    const voiceFileName = `image.${ voiceType}`;

    // 将输入文件保存到虚拟文件系统
    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', voiceFileName, await fetchFile(voiceUrl));

    // 运行 FFmpeg 命令
    try {
     
        await ffmpeg.run(
            '-i', inputName,
            '-i', voiceFileName,
            '-filter_complex', `[1:a]adelay=${ startTime * 1000}|${ startTime * 1000}[a1];[0:a][a1]amix=inputs=2:duration=first[aout]`,
            '-map', `0:v`,
            '-map', `[aout]`,
            '-c:v', 'copy',
            '-c:a', 'aac',
            "-strict", "experimental",
            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 url = "http://xxx.mp4"
	const type = /\.([a-zA-Z0-9]+)$/.exec(url)?.[1];
	// 从2s开始将 http://xxx.mp3 中的背景音乐合成到url的视频背景音乐中
    const {
     fileUrl} = await videoVoiceCompose (url, type, {
     url: "http://xxx.mp3", startT: 2})
    downloadFile(fileUrl)
})

onUnmounted(() => {
     
    ffmpeg.exit();
})
</script>

相关推荐

  1. Js使用ffmpeg视频合成音频背景音乐

    2024-01-09 07:00:05       45 阅读
  2. ffmpeg合并视频音频

    2024-01-09 07:00:05       41 阅读
  3. ffmpeg将一个视频音频合并到另一个视频

    2024-01-09 07:00:05       7 阅读
  4. Android使用MediaPlayer播放音频视频

    2024-01-09 07:00:05       15 阅读
  5. ffmpeg视频添加语音、背景音乐和字幕的方法

    2024-01-09 07:00:05       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-09 07:00:05       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-09 07:00:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-09 07:00:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-09 07:00:05       18 阅读

热门阅读

  1. 详解Nacos和Eureka的区别

    2024-01-09 07:00:05       28 阅读
  2. ffmpeg api-codec-param-test.c源码讲解

    2024-01-09 07:00:05       31 阅读
  3. 数据结构与算法Python版:计数排序

    2024-01-09 07:00:05       35 阅读
  4. 收到的字符串写入xml并且将这个xml写入.zip文件中

    2024-01-09 07:00:05       37 阅读
  5. Android-设计模式

    2024-01-09 07:00:05       29 阅读