借助mediabunny纯JS实现视频水印、剪裁、合成等功能
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12166
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
一、推荐使用mediabunny
大约2年前,我更新了大量的音视频处理的文章,不过里面的技术实现大都使用原生代码和WebCodecs API手搓的实现。
因为那个时候,WebCodecs API刚出来,技术还不成熟。
自然而然,就陆续出现了不少基于WebCodecs API封装的音视频处理框架。
经过这些年的发展,有一个媒体工具包异军突起,那就是mediabunny!
项目地址:https://github.com/Vanilagy/mediabunny
2个月前,我在微博介绍过的MP4/MOV视频转WebM格式在线工具就使用了此项目。
![]()
mediabunny的能力不仅仅在于视频格式转换与压缩,添加水印、时长剪裁等都不在话下,本文就通过我跑通的demo给大家看下这类需求该如何实现。
二、给视频添加水印
话不多说,先直接上手体验。
您可以狠狠地点击这里:纯前端实现视频添加水印效果demo
选择视频和需要的水印图片,就可以得到最终的效果了,如下截图所示:
![]()
其中,最关键的合成就是下面这部分代码:
let ctx = null;
const conversion = await Conversion.init({
input,
output,
video: {
process: (sample) => {
if (!ctx) {
// 创建canvas
const canvas = new OffscreenCanvas(
sample.displayWidth,
sample.displayHeight
);
ctx = canvas.getContext('2d');
}
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
sample.draw(ctx, 0, 0);
ctx.drawImage(watermark, 80, 80 * watermark.naturalHeight / watermark.naturalWidth);
return ctx.canvas;
}
}
});
使用Conversion.init解码视频的每一帧(sample),然后使用canvas将画面和水印图重新绘制,再返回当前canvas即可。
其实不仅是水印合成,任何画面特效,字幕添加,遮罩,尺寸设置都可以使用此方法实现,原理都是一样的,都是对图像进行处理。
三、Video视频前后剪裁
同样的,先看实现效果。
您可以狠狠地点击这里:纯前端实现视频首尾剪裁demo
选择任意的视频,然后拖选滑竿选择需要的视频片段,点击红色的剪裁按钮,就可以看到被剪裁后的视频了:
![]()
实际生产环境,拖拽的应该是缩列图的左右两个小翅膀,这里为了简化使用,使用了LuLu UI的双滑块模拟。
其核心实现代码极为简单:
const input = new Input({
formats: ALL_FORMATS,
source: new BlobSource(videoFile),
});
const output = new Output({
format: new Mp4OutputFormat(), // The format of the file
target: new BufferTarget(),
});
const eleRange = range.querySelector('input');
const conversion = await Conversion.init({
input,
output,
trim: {
start: eleRange.from,
end: eleRange.to,
},
});
await conversion.execute();
使用trim参数,指定起止时间就可以了。
完整代码可以访问演示页面。
四、多音频和画面的视频合成
一例胜千言,您可以狠狠地点击这里:纯前端实现画面加音频的视频合成demo
默认提供了字幕、背景图、台词,背景音乐可选,用户可以自己上传,可以合成最终的视频:
![]()
我查了下API,mediabunny中似乎缺少AudioBuffer处理方法,当然,也可能有,我自己没找到。
这里的AudioBuffer剪裁和合并用的是我自己之前手搓的方法。
相关源码在页面左侧(移动端在下方)有完整展示,基本上相关的视频合成都可以实现了。
这里提供下核心实现部分:
// 定义一个视频合成输出
const output = new Output({
format: new Mp4OutputFormat(),
target: new BufferTarget(),
});
// 添加视频轨道,画面源自canvas
const videoSource = new CanvasSource(canvas, {
codec: 'avc',
bitrate: QUALITY_HIGH,
});
output.addVideoTrack(videoSource);
// 添加音轨
const audioSource = new AudioBufferSource({
codec: 'aac',
bitrate: QUALITY_HIGH,
});
output.addAudioTrack(audioSource);
await output.start();
// 获取音频文件
const duration = audioFile.duration;
// 每秒30帧
for (let frame = 0; frame < 30 * duration; frame++) {
draw(frame);
await videoSource.add(frame / 30, 1 / 30);
}
// 获取音频的 audioBuffer……(代码略),然后添加
await audioSource.add(audioBuffer);
await output.finalize();
五、广告时间
推荐下我几年前在掘金上更新的人文类课程《技术写作指南》。
既是关于写作,也是关注个人成长!
OK,就说这么多,如果你觉得本文内容对你的工作与学习有所帮助,欢迎转发,点赞!
😉😊😇
🥰😍😘
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12166
(本篇完)










