纯前端实现音视频合成

Posted 薛定谔的猫96

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了纯前端实现音视频合成相关的知识,希望对你有一定的参考价值。

通常,可能有纯视频与纯音频进行合成的需求,可以借助借助 ffmpeg.wasm 来实现。

关于 ffmpeg.wasm

FFmpeg 是C/C++编写的,是整个软件界非常著名的音视频等流媒体处理工具,非常强大。因为WebAssembly,ffmpeg.wasm 则是 FFmpeg 在浏览器中运行的版本。WebAssembly的兼容性如下:

由于要想使用 ffmpeg,需要引入ffmpeg.min.js,ffmpeg.min.js会去加载同源目录下 ffmpeg-core 资源,虽然也有CDN,但是毕竟都是外网,速度堪忧:

  • ffmpeg-core.js
  • ffmpeg-core.worker.js
  • ffmpeg-core.wasm (22.4M)

如何使用:

<script src="./ffmpeg.min.js"></script>
<script>
const  createFFmpeg, fetchFile  = FFmpeg;
const ffmpeg = createFFmpeg(
    corePath: "./ffmpeg-core.js",
    log: true,
);
// ...
</script>

视频与音频合成

首先在页面上创建一个 video 元素:

<video id="player" controls height="344" width="412"></video>

1. 单音频与视频合成实现

<script src="./ffmpeg.min.js"></script>
<script>
const  createFFmpeg, fetchFile  = FFmpeg;
const ffmpeg = createFFmpeg(
    corePath: "./ffmpeg-core.js",
    log: true,
);
(async () => 
    await ffmpeg.load();
    
    const dataInputVideo = await fetchFile('bj.mp4');
    const dataInputAudio = await fetchFile('record.mp3');

    ffmpeg.FS('writeFile', 'bj.mp4', dataInputVideo);
    ffmpeg.FS('writeFile', 'record.mp3', dataInputAudio);
    
    /** ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental -map 0:v:0 -map 1:a:0 output.mp4 */
    await ffmpeg.run('-i', 'bj.mp4', '-i', 'record.mp3', '-c:v', 'copy', '-c:a', 'aac', '-strict', 'experimental', '-map', '0:v:0', '-map', '1:a:0', 'output.mp4');
    
    const data = ffmpeg.FS('readFile', 'output.mp4');
    const video = document.getElementById('player');
    video.src = URL.createObjectURL(new Blob([data.buffer],  type: 'video/mp4' ));
)();
</script>

 2. 视频指定位置合成多音频实现

(async () => 
    await ffmpeg.load();

    const dataInputVideo = await fetchFile('zhangxinxu.mp4');
    const dataInputAudio1 = await fetchFile('1.mp3');
    const dataInputAudio2 = await fetchFile('2.mp3');
    const dataInputAudio3 = await fetchFile('3.mp3');
    const dataInputAudio4 = await fetchFile('4.mp3');

    ffmpeg.FS('writeFile', 'zhangxinxu.mp4', dataInputVideo);
    ffmpeg.FS('writeFile', '1.mp3', dataInputAudio1);
    ffmpeg.FS('writeFile', '2.mp3', dataInputAudio2);
    ffmpeg.FS('writeFile', '3.mp3', dataInputAudio3);
    ffmpeg.FS('writeFile', '4.mp3', dataInputAudio4);

    await ffmpeg.run('-i', 'input.mp4', '-i', '1.mp3', '-i', '2.mp3', '-i', '3.mp3', '-i', '4.mp3',     
    '-filter_complex', '[1]adelay=2000|2000[aout1];[2]adelay=10000|10000[aout2];[3]adelay=15000|15000[aout3];[4]adelay=20000|20000[aout4];[aout1][aout2][aout3][aout4]amix=4[aout]',
    '-c:v', 'copy', '-c:a', 'aac', '-strict', 'experimental', '-map', '0:v:0', '-map', '[aout]', 'output.mp4');
    
    const data = ffmpeg.FS('readFile', 'output.mp4');
    const video = document.getElementById('player');
    video.src = URL.createObjectURL(new Blob([data.buffer],  type: 'video/mp4' ));
)();


adelay 表示 audio 插入位置的延时,管道符写法表示不同声道的延时。如果同时延时,管道符前后时间设为一样。

amix表示合并,多个音频合成一个。

总结

ffmpeg.wasm 的核心文件 ffmpeg-core 的体积的确有点大,就算Gzip为7M多。要想在用户侧使用,估计要么让用户首次安装 ffmpeg.wasm 插件,体验才可以。

前端每日实战:152# 视频演示如何用纯 CSS 创作一个圆点错觉效果

技术图片

效果预览

按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。

https://codepen.io/comehope/pen/gBwzKR

可交互视频

此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。

请用 chrome, safari, edge 打开观看。

https://scrimba.com/p/pEgDAM/ca82VAM

源代码下载

每日前端实战系列的全部源代码请从 github 下载:

https://github.com/comehope/front-end-daily-challenges

代码解读

此项目无用户自定义的 dom 元素,利用系统默认的 <body> 元素作为容器。

定义页面尺寸,背景设置为黑色:

body {
    margin: 0;
    width: 100vw;
    height: 100vh;
    background-color: black;
}

用线性渐变画出一横一竖二条灰色的细线:

body {
    margin: 0;
    width: 100vw;
    height: 100vh;
    background-color: black;
    background-image: 
        linear-gradient(
            to bottom,
            #555 2vmin,
            transparent 2vmin
        ),
        linear-gradient(
            to right,
            #555 2vmin,
            transparent 2vmin
        );
}

用径向渐变在左上角画一个白色的圆点:

body {
    margin: 0;
    width: 100vw;
    height: 100vh;
    background-color: black;
    background-image: 
        radial-gradient(
            circle at 1vmin 1vmin,
            white 1vmin,
            transparent 1vmin
        ),
        linear-gradient(
            to bottom,
            #555 2vmin,
            transparent 2vmin
        ),
        linear-gradient(
            to right,
            #555 2vmin,
            transparent 2vmin
        );
}

平铺背景:

body {
    margin: 0;
    width: 100vw;
    height: 100vh;
    background-color: black;
    background-image: 
        radial-gradient(
            circle at 1vmin 1vmin,
            white 1vmin,
            transparent 1vmin
        ),
        linear-gradient(
            to bottom,
            #555 2vmin,
            transparent 2vmin
        ),
        linear-gradient(
            to right,
            #555 2vmin,
            transparent 2vmin
        );
    background-size: 10vmin 10vmin;
}

为避免圆点紧贴在左侧和顶部,为背景增加一点偏移量:

body {
    margin: 0;
    width: 100vw;
    height: 100vh;
    background-color: black;
    background-image: 
        radial-gradient(
            circle at 1vmin 1vmin,
            white 1vmin,
            transparent 1vmin
        ),
        linear-gradient(
            to bottom,
            #555 2vmin,
            transparent 2vmin
        ),
        linear-gradient(
            to right,
            #555 2vmin,
            transparent 2vmin
        );
    background-size: 10vmin 10vmin;
    background-position: 5vmin 5vmin;
}

现在,如果视线在页面中移动,就会看到黑色小圆点,这实际上是错觉。

大功告成!

以上是关于纯前端实现音视频合成的主要内容,如果未能解决你的问题,请参考以下文章

前端视频帧提取 ffmpeg + Webassembly

看前端如何通过WebAssembly实现播放器预览能力

H.265网页播放器EasyPlayer实现WebRTC视频实时录像功能

实践解析丨如何通过 WebAssembly 在 Web 进行实时视频人像分割

用WebAssembly在浏览器中对视频进行转码

前端每日实战:102# 视频演示如何用纯 CSS 创作一个小和尚