惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Schneier on Security
N
News and Events Feed by Topic
量子位
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
Hugging Face - Blog
Hugging Face - Blog
S
Security Affairs
J
Java Code Geeks
Schneier on Security
Schneier on Security
Google Online Security Blog
Google Online Security Blog
TaoSecurity Blog
TaoSecurity Blog
小众软件
小众软件
S
SegmentFault 最新的问题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Privacy International News Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
博客园 - 聂微东
T
Tor Project blog
博客园 - Franky
C
CERT Recently Published Vulnerability Notes
Cyberwarzone
Cyberwarzone
罗磊的独立博客
博客园_首页
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
大猫的无限游戏
大猫的无限游戏
Forbes - Security
Forbes - Security
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
腾讯CDC
Simon Willison's Weblog
Simon Willison's Weblog
S
Securelist
博客园 - 【当耐特】
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
博客园 - 司徒正美
AWS News Blog
AWS News Blog
WordPress大学
WordPress大学
Jina AI
Jina AI
G
GRAHAM CLULEY
V
V2EX
L
LINUX DO - 最新话题
H
Heimdal Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
IT之家
IT之家

张鑫旭-鑫空间-鑫生活

1分钟速度了解text-align match-parent声明 « 张鑫旭-鑫空间-鑫生活 光标的形状也能设置了,就是CSS caret-shape属性 « 张鑫旭-鑫空间-鑫生活 pretext与文字四面环绕效果的实现 « 张鑫旭-鑫空间-鑫生活 JSON.rawJSON方法的作用是什么? « 张鑫旭-鑫空间-鑫生活 如何使用CSS判断鼠标从哪个方向进入元素? « 张鑫旭-鑫空间-鑫生活 借助mediabunny纯JS实现视频水印、剪裁、合成等功能 « 张鑫旭-鑫空间-鑫生活 务必谨慎使用JS WeakRef弱引用 « 张鑫旭-鑫空间-鑫生活 CSS六边形头像的实现与蜂巢布局 « 张鑫旭-鑫空间-鑫生活 CSS corner-shape与背景底纹技术 « 张鑫旭-鑫空间-鑫生活 浅学WebTransport API:下一代Web双向通信技术 « 张鑫旭-鑫空间-鑫生活 HTML dialog元素新支持了closedBy属性 « 张鑫旭-鑫空间-鑫生活 HTML interestfor属性与悬停popover交互效果 « 张鑫旭-鑫空间-鑫生活 CSS3模拟window7炫酷界面效果展示 « 张鑫旭-鑫空间-鑫生活 图片旋转+剪裁js插件(兼容各浏览器) « 张鑫旭-鑫空间-鑫生活 纯js无图片无外链CSS图片幻灯片播放插件 « 张鑫旭-鑫空间-鑫生活 CSS border三角、圆角图形生成技术简介 « 张鑫旭-鑫空间-鑫生活 CSS “渐进增强”在web制作中常见应用举例 « 张鑫旭-鑫空间-鑫生活 让IE6/IE7/IE8浏览器支持CSS3属性 « 张鑫旭-鑫空间-鑫生活 jQuery – 高亮动态显示页面HTML代码插件 « 张鑫旭-鑫空间-鑫生活 翻译 – 逐渐消失的Flash网站 « 张鑫旭-鑫空间-鑫生活 CSS reset的重新审视 – 避免样式重置 « 张鑫旭-鑫空间-鑫生活 新浪微博插入话题后部分文字选中的js实现 « 张鑫旭-鑫空间-鑫生活 JavaScript实现http地址自动检测并添加URL链接 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变背景(gradient)效果 « 张鑫旭-鑫空间-鑫生活 CSS content内容生成技术以及应用 « 张鑫旭-鑫空间-鑫生活 CSS gradient渐变之webkit核心浏览器下的使用 « 张鑫旭-鑫空间-鑫生活 CSS渐变之CSS3 gradient在Firefox3.6下的使用 « 张鑫旭-鑫空间-鑫生活 区分IE8/IE7/IE6及其他浏览器-CSS “\9″hack « 张鑫旭-鑫空间-鑫生活 CSS实现跨浏览器兼容性的盒阴影效果 « 张鑫旭-鑫空间-鑫生活 CSS3&HTML5各浏览器支持情况一览表 « 张鑫旭-鑫空间-鑫生活 翻译 – CSS Sprites:实用技术还是生厌之物? « 张鑫旭-鑫空间-鑫生活 纯CSS实现易拉罐3D滚动效果 « 张鑫旭-鑫空间-鑫生活 纯CSS实现侧边栏/分栏高度自动相等 « 张鑫旭-鑫空间-鑫生活 CSS+JavaScript实现页面不同布局的切换 « 张鑫旭-鑫空间-鑫生活 JavaScript实现最简单的拖拽效果 « 张鑫旭-鑫空间-鑫生活 自己写的无图片版jQuery zxxbox弹出框插件 « 张鑫旭-鑫空间-鑫生活 中国古代道家思想与网页重构的思考 « 张鑫旭-鑫空间-鑫生活 让所有浏览器支持HTML5 video视频标签 « 张鑫旭-鑫空间-鑫生活 纯CSS实现各类气球泡泡对话框效果 « 张鑫旭-鑫空间-鑫生活 JS HEX十六进制与RGB, HSL颜色的相互转换 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变、高光等文字效果 « 张鑫旭-鑫空间-鑫生活 去除冗余 – 精简您的CSS样式代码 « 张鑫旭-鑫空间-鑫生活 对overflow与zoom”清除浮动”的一些认识 « 张鑫旭-鑫空间-鑫生活 jQuery Pagination Ajax分页插件中文详解 « 张鑫旭-鑫空间-鑫生活 absolute绝对定位的非绝对定位用法 « 张鑫旭-鑫空间-鑫生活 网页布局思想浅议-淘宝新版首页为实例 « 张鑫旭-鑫空间-鑫生活 回流与重绘:CSS性能让JavaScript变慢? « 张鑫旭-鑫空间-鑫生活 CSS float浮动的深入研究、详解及拓展(二) « 张鑫旭-鑫空间-鑫生活 CSS float浮动的深入研究、详解及拓展(一) « 张鑫旭-鑫空间-鑫生活 60个极富创造性的震撼的电影海报设计 « 张鑫旭-鑫空间-鑫生活 jQuery Lightbox(balupton版)图片展示插件讲解 « 张鑫旭-鑫空间-鑫生活 博客内嵌flash音乐播放器代码、下载与使用 « 张鑫旭-鑫空间-鑫生活 CSS3 animate实现图片墙3D翻转效果 « 张鑫旭-鑫空间-鑫生活 图片旋转效果的一些研究、jQuery插件及实例 « 张鑫旭-鑫空间-鑫生活 CSS3 border-image详解、应用及jQuery插件 « 张鑫旭-鑫空间-鑫生活 jQuery-两款不同原理的圆角插件讲解 « 张鑫旭-鑫空间-鑫生活 页面可用性之outline轮廓外框的一些研究 « 张鑫旭-鑫空间-鑫生活 CSS3 transition实现超酷图片墙动画效果 « 张鑫旭-鑫空间-鑫生活 HTML CSS列表元素ul,ol,dl的研究与应用 « 张鑫旭-鑫空间-鑫生活 jQuery图片文本滚动切换插件jCarousel中文翻译与详解 « 张鑫旭-鑫空间-鑫生活 酷酷的jQuery鼠标悬停图片放大切换显示效果 « 张鑫旭-鑫空间-鑫生活 IE6下z-index犯癫不起作用bug的初步研究 « 张鑫旭-鑫空间-鑫生活 checkbox复选框的一些深入研究与理解 « 张鑫旭-鑫空间-鑫生活 jQuery之使用slideToggle实现垂直下拉菜单 « 张鑫旭-鑫空间-鑫生活 jQuery-innerfade内部列表自动淡入淡出插件 « 张鑫旭-鑫空间-鑫生活 jQuery-火焰灯效果导航菜单 « 张鑫旭-鑫空间-鑫生活 IE下css bug集合-翻译自haslayout.net « 张鑫旭-鑫空间-鑫生活 翻译-IE7/8@font-face嵌入字体与文字平滑 « 张鑫旭-鑫空间-鑫生活 jQuery-马化腾产品设计与用户体验的一些技术实现 « 张鑫旭-鑫空间-鑫生活 像素的世界及其在web开发制作中的应用 « 张鑫旭-鑫空间-鑫生活 css行高line-height的一些深入理解及应用 « 张鑫旭-鑫空间-鑫生活 CSS实现圆角六色渐变自适应按钮详解 « 张鑫旭-鑫空间-鑫生活 我熟知的三种三栏网页宽度自适应布局方法 « 张鑫旭-鑫空间-鑫生活 jQuery照片图像剪裁插件Jcrop中文翻译详解 « 张鑫旭-鑫空间-鑫生活 Ajax Upload多文件上传插件翻译及中文演示 « 张鑫旭-鑫空间-鑫生活 告别图片—使用字符实现兼容性的圆角尖角效果beta版 « 张鑫旭-鑫空间-鑫生活 大小不固定的图片、多行文字的水平垂直居中 « 张鑫旭-鑫空间-鑫生活 jQuery boxy弹出层对话框插件中文演示及讲解 « 张鑫旭-鑫空间-鑫生活 JavaScript实现新浪微博文字放大显示动画效果 « 张鑫旭-鑫空间-鑫生活 翻译:让网络更快一些——最小化浏览器中的回流(reflow) « 张鑫旭-鑫空间-鑫生活 jQuery之addClasas与removeClass使用实例 « 张鑫旭-鑫空间-鑫生活 关于Google圆角高光高宽自适应按钮及其拓展 « 张鑫旭-鑫空间-鑫生活 JavaScript实现图片幻灯片滚动播放动画效果 « 张鑫旭-鑫空间-鑫生活 jQuery-鼠标经过显示大图并跟随鼠标效果插件 « 张鑫旭-鑫空间-鑫生活 关于gif图片(或png8)杂边锯齿的问题 « 张鑫旭-鑫空间-鑫生活 对html与body的一些研究与理解 « 张鑫旭-鑫空间-鑫生活 鲜为人知的一个解决兼容性问题的利器——小数 « 张鑫旭-鑫空间-鑫生活 搜狐白社会似iphone短信对话框效果的优化 « 张鑫旭-鑫空间-鑫生活 关于文字内容溢出用点点点(…)省略号表示 « 张鑫旭-鑫空间-鑫生活 jquery之append与insertBefore使用实例 « 张鑫旭-鑫空间-鑫生活 jQuery之图片关联伸缩效果 « 张鑫旭-鑫空间-鑫生活 jquery之图片左右切换动画效果 « 张鑫旭-鑫空间-鑫生活 jQuery之replace字符串替换实现不同尺寸图片切换 « 张鑫旭-鑫空间-鑫生活 jQuery-实现图片的放大镜显示效果 « 张鑫旭-鑫空间-鑫生活 jQuery-单击文字或图片内容放大显示效果插件 « 张鑫旭-鑫空间-鑫生活 reflection.js-实现图片投影倒影效果js插件 « 张鑫旭-鑫空间-鑫生活 jQuery-很酷的弹出层效果js插件 « 张鑫旭-鑫空间-鑫生活 复选框单选框与文字对齐问题的研究与解决 « 张鑫旭-鑫空间-鑫生活 css margin的相关属性,问题及应用 « 张鑫旭-鑫空间-鑫生活 IE6下png背景不透明问题的综合拓展 « 张鑫旭-鑫空间-鑫生活
JS audio加图片序列或canvas转webM/MP4的实现 « 张鑫旭-鑫空间-鑫生活
张鑫旭,zhangxinxu · 2023-05-21 · via 张鑫旭-鑫空间-鑫生活

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=10815 鑫空间-鑫生活
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

视频合成封面图

一、生成WebM视频

Web端基于图像素材生成webM格式的视频算是比较成熟的技术了,实现也比较简单。

我之前是使用whammy.js实现的:https://github.com/antimatter15/whammy

不过此项目已经多年不更新了,看看时间,七八年了。

时间

对于webP格式的图片序列,whammy会有黑屏的问题,因为21年的时候Chrome修改了 webp 图片的编码方法,从 WEBPVP8 改为了 WEBPVP8X,其并没有进行及时的更新。

不过JPG或者PNG图片序列功能不受影响,大家如果想使用也是可以的。

webm-writer

w3c官方项目demo使用的是更新的 webm-writer.js,这个项目是基于 Whammy 实现的,比较新,最近更新是2年前。

项目地址:https://github.com/thenickdude/webm-writer-js

这里,我就使用webm-writer示意下如何使用纯JS在前端生成webM视频。

您可以狠狠地点击这里:webm-writer.js实现webm视频合成并下载demo

点击页面的“生成webM视频”按钮,就可以在下方看到生成好的webM视频了,点击播放,可以预览效果,点击下载,可以下载该webM视频。

支持Chrome,Firefox以及Safari浏览器(桌面Safari 16+)。

例如,下面的MP4录屏就是我Chrome 112版本下的实现效果(不动点击播放):

代码示意

// 点击按钮的webM生成
button.onclick = function () {
    // 构造webm生成器
    var videoWriter = new WebMWriter({
        // 每秒30帧
        frameRate: 30
    });
    // 创建屏幕外 canvas
    var canvas = document.createElement('canvas');
    // 总共50帧canvas绘制
    var currentFrame = 1;
    var maxFrame = 50;
    for (var index = 1; index <= maxFrame; index++) {
        currentFrame = index;
        // 绘制函数略
        draw();
        videoWriter.addFrame(canvas);
        // 如果是最后一帧,那就完成
        if (currentFrame === maxFrame && complete) {
          videoWriter.complete().then(function(webMBlob) {
            var blobUrl = URL.createObjectURL(webMBlob);
            // blobUrl就是webM视频地址了,可播放,可下载
          });     
        }
    }
};

webM视频合成的实现其实很简单,主要就是下面三步:

  1. 构造:
    var videoWriter = new WebMWriter(options);
  2. 添加帧:
    videoWriter.addFrame(canvas);
  3. 结束添加,完成生成:
    videoWriter.complete().then(function(webMBlob) {
        video.src = URL.createObjectURL(webMBlob);
    })

其他

  • webm-writer似乎不支持直接使用图像元素作为帧内容添加,具体我没测,我是看源码得出的结论,这个就没有 Whammy 好用。
  • webm-writer好像都是用的webP图像进行视频合成的,所以,图像一定会有损失,不可能100%还原。

其实,有了canvas流,借助MediaRecorder API,我们无需使用第三方开源的JS组件,也能实现webM视频的合并,下面是案例,适合摄像头的视频流保存为视频的场景。

function record(canvas, time) {
    var recordedChunks = [];
    return new Promise(function (res, rej) {
        var stream = canvas.captureStream(25 /*fps*/);
        mediaRecorder = new MediaRecorder(stream, {
            mimeType: "video/webm; codecs=vp9"
        });
        
        //数据记录的起始时间 `time || 4000 ms`
        mediaRecorder.start(time || 4000);

        mediaRecorder.ondataavailable = function (event) {
            recordedChunks.push(event.data);
             //`dataavilable`事件结束后执行,只会执行一次
            if (mediaRecorder.state === 'recording') {
                mediaRecorder.stop();
            }
        }

        mediaRecorder.onstop = function (event) {
            var blob = new Blob(recordedChunks, {type: "video/webm" });
            var url = URL.createObjectURL(blob);
            res(url);
        }
    })
}

然而,无论是whammy还是webm-writer,虽然用来合成webM视频很方便,但是有个问题,那就是无法添加音频进行,也就是视频合成的时候,没法带声音。

这个问题就是我之前遇到的问题,所以后来寻求了使用ffmpeg.wasm来实现,也就是之前这篇文章“借助ffmpeg.wasm纯前端实现多音频和视频的合成”的由来。

长久以来,我一直以为此事无解,但是,随着浏览器的发展,事情出现了转机,Chrome 94开始支持了WebCodecs API(兼容性见下图),这是个图像、音频和视频编解码API集合,很强。

WebCodecs兼容性

有了WebCodecs API,纯前端,不依赖任何插件,迅速实现带音乐的视频合成成为了可能,这是本文要介绍的重点。

二、带audio声音的webM合成

实现原理也比较好理解,AudioEncoder编码音频,VideoEncoder编码视频,然后进行合并封装。

其中,编码视频和编码音频相关的API并不完全对等(根据我看一些老的资料,一开始,也就是规范阶段,浏览器还没支持的时候,是近似的,例如音频中还有AudioFrame的概念,现在没有了,只有VideoFrame)。

原理好懂,但是实操细节却不简单。

因为涉及到非常多的音视频概念,和各种API对象,例如,WebCodecs API中的Audio编码有个名叫AudioData的概念,这是新的概念,和Web Audio API中decodeAudioData(audioData)中的audioData参数不是一个东西。

想要完全了解,非一朝一夕,哪怕一周一月,都不太可能,也没有必要。

除非你是专门从事音视频开发的前端。

所以,我们可以借助社区的力量帮助我们上手WebCodecs API的使用。

不过,由于WebCodecs API刚出来没多久,目前学习资源有限,MDN上虽然有对API的介绍,但基本上都看不到example演示,所以,相关的学习与尝试,还是花了我不少时间的。

webm-muxer项目

找到了一个基于WebCodecs API实现的Webm视频合并项目:https://github.com/Vanilagy/webm-muxer

muxer 其实是计算机中的一个术语,指合并,例如将视频文件、音频文件和字幕文件合并为某一个视频格式就是典型的muxer,还有个demuxer,表示拆分。

此项目提供了两个demo,可以将麦克风录音和canvas绘制合并成webm视频,如下截图示意。

demo示意

不知道是不是我设备的问题,我保存的视频是绿屏。

视频绿屏

不过这个不重要,重要的是此demo为我们的需求解决提供了重要的参考。

demo之canvas+mp3=>webm视频

你可以狠狠地点击这里:webm-muxer实现带音乐的webm视频demo

在Chrome浏览器下,点击“生成webm”按钮,稍等数秒,就可以看到合成的webm视频了,如下图所示:

视频生成效果截图

还可以点击右侧的“下载”按钮下载此webM视频。

实现过程概述

1. 构造

构造合并器muxer,音视频解码器,下面这些代码结构都是固定的,一些参数值,例如视频尺寸和帧率根据实际情况自行设置。

// 构造包装器
var muxer = new WebMMuxer.Muxer({
    target: new WebMMuxer.ArrayBufferTarget(),
    video: {
        codec: 'V_VP9',
        width: 600,
        height: 400,
        frameRate: 30
    },
    audio: {
        codec: 'A_OPUS',
        sampleRate: 48000,
        numberOfChannels: 1
    },
    firstTimestampBehavior: 'offset'
});

// 音视频编码器,这里使用的是WebCodese API
var videoEncoder = new VideoEncoder({
    output: (chunk, meta) => muxer.addVideoChunk(chunk, meta),
    error: e => console.error(e)
});
videoEncoder.configure({
    codec: 'vp09.00.10.08',
    width: 600,
    height: 400,
    bitrate: 1e6
});
// 音频的
var audioEncoder = new AudioEncoder({
    output: (chunk, meta) => muxer.addAudioChunk(chunk, meta),
    error: e => console.error(e)
});
audioEncoder.configure({
    codec: 'opus',
    numberOfChannels: 1,
    sampleRate: 22050,
    bitrate: 64000
});

提示:如果遇到不兼容的提示(Input audio buffer is incompatible with codec parameters),一般都是configure()中的sampleRate设置的不对,和音频文件的采样率不匹配。

2. 音频编码

这里是实现的难点,我一开始是尝试直接fetch MP3音频文件流,然后借助AudioEncoder进行编码,结果发现路走不通,总是提示,不是需要的音频数据。

查了很多资料,也未见相关实现案例,隐隐觉得,技术上就不通,不然不会都是借助MediaDevices的getUserMedia()方法实现的例子,也就是麦克风或摄像头捕捉的数据。

所以,我就退而求其次,音频播放的时候,基于播放的音频流进行编码,这也是为何demo页面合成时候,会播放音频的原因。

// 音频资源获取
const myAudio = new Audio();
fetch(audio.src).then(res => {
    var reader = res.body.getReader();
    return reader.read().then(result => {
        return result;
    });
}).then(data => {
    var blob = new Blob([data.value], {
        type: 'audio/mp3'
    });
    var blobUrl = URL.createObjectURL(blob);

    // 创建音频对象
    myAudio.src = blobUrl;
    // 隐藏不可见
    myAudio.hidden = true;
    // 静音,避免干扰(静音后,合成的视频也会没声音)
    // myAudio.muted = true;
    // 在页面内,方便播放
    document.body.append(myAudio);
});

// 捕捉播放的音轨
const audioTrack = myAudio.captureStream().getAudioTracks()[0];
// MediaStreamTrackProcessor可以用来生成媒体帧流
let trackProcessor = new MediaStreamTrackProcessor({
    track: audioTrack
});

// 音频播放,并实时抓取视频流
// 交给webcodecs API进行编码
myAudio.play();
// 编码音频数据
let consumer = new WritableStream({
    write(audioData) {
        if (!audioEncoder) {
            return;
        }
        audioEncoder.encode(audioData);
        audioData.close();
    }
});
trackProcessor.readable.pipeTo(consumer);

这里可能是我的积累还不够,如果有谁知道直接fetch音频并encode()的方法,欢迎不吝赐教。

更新于2023年9月20日

找到了直接fetch音频的方法了,可以参见下面的MP4合成demo示意。

3. 视频编码

视频编码案例比较多,相对简单的多。

视频中,有专门的VideoFrame,只需要进行制定每一帧的资源、时间间隔,以及关键帧即可。

可以直接使用canvas作为资源,IMG也是可以的。

demo中的实现示意:

// 创建屏幕外 canvas
var canvas = document.createElement('canvas');
canvas.width = 600;
canvas.height = 400;

// 编码视频数据
var startTime = document.timeline.currentTime;
var frameCounter = 0;
// handleDraw源码可右键页面查看
// 每次绘制都会走一遍后面的function函数
handleDraw(canvas, function () {
    // 定义视频帧
    let frame = new VideoFrame(canvas, {
        timestamp: (frameCounter * 1000 / 30) * 1000
    });

    frameCounter++;
    // 制定关键帧,这是规范要求,最多多少秒之内一定要有个关键帧的
    videoEncoder.encode(frame, { 
        keyFrame: frameCounter % 30 === 0 
    });
    frame.close();
});

4. 结束编码

当视频完全绘制结束,同时确保音频播放到视频时长,可以结束。

async () => {
    await videoEncoder?.flush();
    await audioEncoder?.flush();
    muxer.finalize();
};

5. 视频生成

let { buffer } = muxer.target;
// buffer就是视频数据
// 我们可以将其作为blobURL地址进行播放或下载
var blobUrl = URL.createObjectURL(new Blob([buffer]));

以上就是实现全部过程。

三、MP4视频的合成

webm-muxer项目的作者还弄了个类似的项目,mp4-muxer,可以辅助我们在Web浏览器中合成MP4视频。

项目地址:https://github.com/Vanilagy/mp4-muxer

语法和webm-muxer项目类似,我就不赘述了,我们直接看demo实现的效果。

您可以狠狠地点击这里:mp4-muxer实现带声音的mp4视频demo

下面的视频就是生成的(点击播放,有音频,注意场合):

虽说代码类似,但也完全不一样。

其中一个区别就是,MP4视频合成对音频文件的质量要求更高。

采样率至少是44100,品质较低的音频是不行的。

可能是mp4a编码格式要求的,为此,我专门下载了个高质量的MP3背景音乐,这是相关的配置:

audioEncoder.configure({
    codec: 'mp4a.40.2',
    numberOfChannels: 2,
    sampleRate: 44100,
    bitrate: 128000
});

代码实现逻辑和webm-muxer类似,我就不重复展示了,代码都在demo页面上,都是原生的,非常适合大家学习上手WebCodecs API。

更新于2023-09-20

无需播放音频,直接根据audioData数据合成MP4的demo弄出来了。

您可以狠狠地点击这里:canvas图片序列加声音合成mp4视频demo

1.67s的视频,80ms就完成了,强无敌。

兴奋,激动,ffmpeg再见了。

不带音频的MP4合成

如果不带音频,使用WebCodecs API合成mp4视频的速度极快,秒生成。

有兴趣想要体验的可以狠狠地点击这里:mp4-muxer实现纯画面mp4视频demo

点击按钮后,只需要0.02秒就可以得到视频,快如闪电。

MP4视频时间示意

MP4视频所有浏览器,所有操作系统都能播放,因此,上面这个demo可能反而会更加实用。

五、终于结语了

继上一篇使用“WebCodecs API之ImageDecoder解码GIF”已经过去两周了,一直在盘这篇文章,不容易,终于要发布了。

算是目前关于浏览器音视频合成,尤其WebCodecs API这块比较稀缺的内容了。

好东西就是要让大家都知道的,欢迎,点赞。

在学习的过程中,还是发现自己对各种stream、buffer(如sharedArrayBuffer、ringbuffer)、chunk、track等理解还不够深入,还需要多多积累。

以写作为契机,逼迫自己学深入自己未曾深入的领域,是非常高效的一种学习方法,推荐给大家。

好了,就说这么多。

如果你觉得本文的内容对你的学习很有帮助,嗯……买本《CSS新世界》支持下吧。

本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=10815

(本篇完)