离屏渲染 离屏渲染怎么优化

昨天微博搜索空降话题——“iPhone 15折叠屏渲染曝光”。

有多少人和小优一样,以为苹果的折叠屏真的要来了,兴奋地进去了。结果事实根本不是我们想的那样!

31df2d2b7c8d4740a01cf2da9d1109b8?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=A4N2mu0lnWqNHIm7xmmvEeLAEho%3D&index=0

简单来说,就是以@新浪热点为首的一群数码博主,转载了一段国外渲染器@4RMD关于折叠屏iPhone(代号iPhone 15 Flip)的自创视频。

ed4ebf23784c436abaa8775aa3c2d4f2?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=6qT7jhYSvxn7Q%2Ftfzox%2BhtOGLPU%3D&index=1

虽然视频中用鼻子和眼睛展示了iPhone 15翻盖的方方面面,比如垂直折叠,6.8寸展开,搭载A17芯片,可以折叠20万次。外置摄像头在小副屏旁边.

1b52aa3c057f49aa8159bbaf6cbc7612?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=FQ%2BtONuHcpnAgrEtNh41WcMGkhE%3D&index=2

但是!这些信息都来自于爆料的汇总,有些是果粉的猜测,有些甚至是谣言,无从考证真假。就连iPhone 15 Flip的型号名称都是自鸣得意的产物。

所以,整个视频充其量就是一个启示录衍生品。

fa6321bce4d24b40b09c0b1c82f77401?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=GKelbQnWYKOEVTxxtPZBKD2gnIs%3D&index=3

其次,视频制作者只是一个为爱发电的概念设计师,并不是苹果官方,也不是苹果供应链的相关人士。也就是说流出的渲染图/视频可信度相当低。

还记得去年的“iPhone 13粉色”热搜吗?

当时很多果粉都信了,还挺看好猛男粉iPhone的。

结果没几天事情就有了转机。

e87312205be04be589888480f3f7f0b9?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=06Qyv6pu2rVj7t%2BIAsDQAqWLgwY%3D&index=4

iPhone粉色效果图的制作者出面承认,自己制作图纸只是一时兴起。没想到图片被转载,诞生了“iPhone 13加粉色”的谣言,甚至几个月后上市时就被编造出来了。

68d7a5afbb8b46b184e44096f4182908?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=jf9N%2BGCquZMGBGIhyFNF6Ymdon8%3D&index=5

不过,新浪让这个“爆料衍生视频”成为热搜也不是没有道理。

今年设备的折叠趋势越来越强。我们熟悉的安卓厂商,比如三星、华为、OPPO、vivo、小米等。都推出了折叠屏手机,但苹果迟迟没有动作。

89a19506353a48a6aabbcab2398aed1b?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=TvWXWmKzJC8MJz%2FjGYtEI2EMsHs%3D&index=6

在这个节骨眼上,任何关于折叠屏iPhone的消息都能引起巨大的讨论,这就给了这个视频一个机会。稍微推波助澜一下就冲上了高级别的热搜。

值得一提的是,虽然折叠屏iPhone没有那么快,但是折叠屏iPad和Mac已经在路上了。

8a6c4873dace490384deecd90e2c30b0?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=FGWthpiKljgsg4GgamAaKvm3xQs%3D&index=7

两个月前,分析公司CCS Insight在年度预测报告中提到,苹果可能会在2024年推出折叠屏iPad。

昨天,外媒TheElec报道称,苹果正在与三星LG合作开发折叠屏幕,展开状态为20.25英寸,折叠状态为15.3英寸。这么大的尺寸是为MacBook视觉开发的。

85959095b68740da8db9f2439fb1a658?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=%2F8W6nwmeILP4sjwBZ3Gr3lD89OQ%3D&index=8

把这两条新闻放在一起看,苹果似乎是要先在大屏设备上测试水折叠技术,然后在小屏手机上推广。

为什么?

CCS Insight的研究主管本伍德(Ben Wood)对此进行了分析:

首先,折叠屏iPhone是个吃力不讨好的产品,做不好会招来很多非议。是真的。很多竖屏折叠手机都被形容为“漂亮的小废物”,看着没用。

18d401bcbb4f46e89284e893a8a09b6c?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=lP%2FMyBBmI%2FUMhr8utRdr0r5RWkY%3D&index=9

其次,现在的iPhone已经是手机界的顶级价位了。折叠屏iPhone一旦做出来,定价一定要越来越高,才不会影响现有iPhone产品线的销售。

总结一下Ben Wood的观点:折叠屏iPhone是一个高价高风险的产品。苹果自己也觉得这个东西悬,所以短期内不愿意涉足。

b69b67ff3d394ad8b691a6a64b60dd8f?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=dzuP1bza%2BCWPTyJdbltt%2Fx21FJY%3D&index=10

那为什么苹果愿意做折叠屏Mac?

肖佑这样认为:

首先,Mac比较大,为了实现折叠形状,加铰链和调整组件位置的难度可能比iPhone小(仅小优愚见)。

其次,现有的MAC价格不是普通人能承受的,顶级的MAC早就有了。然后,一个折叠版放上更高的价格,以前买不起的现在也买不起了。这难道不是无关紧要的吗?自然不会碰其他在售苹果产品的蛋糕。

d586f1e7462b4bac9716245c20d73156?_iz=31825&from=article.detail&x-expires=1702423220&x-signature=uGKN6ubgucz2pzhnmMkSAhLlyfk%3D&index=11

离屏渲染怎么优化

首先,通过fetch请求音频数据以获得ArrayBuffer对象。

fetchData() {

获取(this.url)。然后((响应)={

return response . array buffer();

}).然后((缓冲)={

this.decodeAudioData(缓冲区);//解码

ArrayBuffer看似处理二进制数据流,但JS没有办法直接处理(读写)其内容,必要时需要转换成TypedArray 。

接下来,通过audioContext对象,可以使用接口的decodeAudioData()方法异步解码音频文件中的ArrayBuffer 。

decodeAudioData(缓冲区){

const audioCtx=new(窗口。audio context | | window . webkitaudiocontext)();

audioCtx.decodeAudioData(

(音频缓冲区)={

const { sampleRate }=audiobuffer//获取采样率

const channel data=audio buffer . getchanneldata(0);

this . draw(channel data);//绘图

解码成功后会得到AudioBuffer对象。

它包含音频持续时间、长度、通道数量和采样率。

采样是将模拟声音信号转换为数字声音信号的过程。采样率是单位时间内采集音频信号的次数,用赫兹(Hz)或千赫兹(kHz)来度量。MP3的采样率一般为44.1kHz,即每秒44100次声音分析,记录每次分析的差值。采样越高,声音信息就越完整。

这里,总持续时间*采样率=总长度。总时长会与实际相差0.1-0.2秒,在音频dom上获得的实际音频时长为94.32秒。我们将把这个作为标准

然后调用getChannelData()方法返回TypedArray对象,该对象包含与通道关联的PCM数据。通道参数定义(0表示第一个通道)不能大于numberOfChannels 。

TypedArray是描述ArrayBuffer的类数组视图。虽然没有TypedArray的全局属性和构造函数,但是提供了基于其特定数据类型的一系列数组(可以理解为TypedArray是一个接口及其扩展类)

【更多音视频学习资料,点击下方链接免费领取这样你就可以先码起来不迷路啦~】

点击接收音视频开发基础知识与资料包。

知道音频时长后,确定绘制的波形画布的宽度,设置为每秒100像素,时长94.32秒,得到画布宽度为9432像素。

模板

div id='应用程序'

音频控件:src=' URL ' @ loaded metadata=' load data '/audio

canvas ref=' timeline 'width=' 360 px 'height='auto' /

canvas ref='wave'width='360px 'height='auto' /

/div

/模板

导出默认值{

unitwidth=' 360px像素'height='auto' /

总时间:0,

宽度=' 360像素'高度='自动'/

loadData() {

this . total time=e . target . duration;

this.width='360px 'height='auto' /

this.timelineCtx=this。$ refs . timeline . get context(' 2d ');

this.waveCtx=this。$ refs . wave . get context(' 2d ');

this . fetch data();

所解码的channelData的长度为4150273,画布的宽度为9432个像素,所以每个像素分配了440.02个数据,相当于channelData 每440.02个点渲染一个像素。

但是440.02不是整数,每100个像素会有两个数据偏差,每22000个像素会有一个像素。音频持续时间越长,偏差越大。况且这里的小数只有0.2,小数越大偏差越明显

所以接下来,四舍五入440.02,微调单位宽度=' 360px '高度=' auto'/

draw(channelData) {

const step=math . floor(channel data . length/(this . total time * this . unit width=' 360 px 'height='auto' /

this.unitwidth='360px 'height='auto' /

this.width='360px 'height='auto' /

this . draw timeline();//绘制时间线

this.drawWave(channelData,step);//绘制波形

画了时间轴,这里就不分析了。

drawTimeline() {

for(设I=0;I math . ceil(this . total time);i=1) {

this . timeline CTX . font=' 10px Arial '

this . timeline CTX . fill style=' rgba(0,0,0,1)'

this . timeline CTX . fill rect(this . unit width=' 360 px 'height='auto' /

如果(i 0) {

this.timelineCtx.fillText(

durationToTime(i)。拆分('')[0],

this.unitwidth='360px 'height='auto' /

绘制波形需要对整个通道数据进行遍历,每440 个数据,算出最大值和最小值,最大值与最小值的差值越大,则整个波形也越大

drawWave(channelData,step) {

设步进索引=0;

设xIndex=0;

设min=1;

设max=-1;

对于(设I=0;我通道数据长度;i=1) {

步进指数=1;

const item=channel data[I]| | 0;

如果(最小项目){

最小值=项目;

} else if (item max) {

最大=项目

if (stepIndex=step) {

xIndex=1;

this.waveCtx.fillStyle='rgba(0,0,0,0.3)'

const l=(max-min)* 40 * 0.8;

this.waveCtx.fillRect(xIndex,40 – (l/2),1,Math.max(1,l));

步进索引=0;

尝试下一段26 分钟的音频,发现波形并不能渲染出来。按照之前的方案,一段26 分钟的音频,画布的宽度已经高达16 万多像素,这时肯定需要将帆布分段\\ u200b

以2分钟为一段,将26 分钟多的视频分为14 段,算出对应宽度并定位布局

模板

div id='应用程序'

音频控件:src=' URL ' @ loaded metadata=' load data '/audio

div class='wave-box '

差异

v-for='画布中的项目'

:key='item.key '

:ref='`timeline${item.key} ` '

高度='20 '

:width='360px 'height='auto' /

:style='{ left: `${item.left}px`} '

' class='时间轴'

/画布

/div

差异

v-for='画布中的项目'

:key='item.key '

:ref='`wave${item.key} ` '

高度='80 '

:width='360px 'height='auto' /

:style='{ left: `${item.left}px`} '

'挥手'

/画布

/div

/div

/div

/模板

loadData(e) {

这个。总时间=e .目标。持续时间;

this.width='360px 'height='auto' /

const w=this.unitwidth='360px 'height='auto' /

const num=数学。ceil(这个。宽度=' 360像素'高度='自动'/

const canvas=[];

对于(设I=0;i numi=1) {

画布。推({

宽度=' 360像素,高度='自动'/

左:我* w,

this.canvas=画布;

这个. nextTick(()={

对于(设I=0;我这个。画布。长度;i=1) {

这个[`wave${i}Ctx`]=这个refs[`wave${i}`][0].获取上下文(“2d”);

this[`timeline${i}Ctx`]=this .$refs[`timeline${i}`][0].获取上下文(“2d”);

这个。获取数据();

【更多音视频学习资料,点击下方链接免费领取,先码住不迷路~】

点击领取音视频开发基础知识和资料包

时间轴分段渲染

时间轴渲染方案较原先做一点改版,每一秒时间先得到对应帆布画布的索引,在对应画布上渲染

drawTimeline() {

对于(设I=0;我数学。ceil(这个。总时间);i=1) {

const n=数学。地板(I/120);

这[`timeline${n}Ctx`] .font=” 10px Arial

这[`timeline${n}Ctx`] .fillStyle='rgba(0,0,0,1)'

这[`timeline${n}Ctx`] .fillRect(this.unitwidth='360px 'height='auto' /

如果(i 0) {

这[`timeline${n}Ctx`] .fillText(

持续时间(一).拆分('')[0],

this.unitwidth='360px 'height='auto' /

同理,渲染每个像素点前,得到对应的画布

drawWave(channelData,step) {

设步进索引=0;

设xIndex=0;

设min=1;

设max=-1;

对于(设I=0;我通道数据长度;i=1) {

步进指数=1;

const item=channel data[I]| | 0;

如果(最小项目){

最小值=项目;

} else if (item max) {

最大=项目

if (stepIndex=step) {

xIndex=1;

const n=数学。楼层(xIndex/(120 *这个。单位宽度=' 360像素'高度='自动'/

这个[`wave${n}Ctx`] .fillStyle='rgba(0,0,0,0.3)'

const l=(max-min)* 40 * 0.8;

这个[`wave${n}Ctx`] .填充rect(xIndex %(120 * this。单位宽度=' 360像素'高度='自动'/

步进索引=0;

最终效果

在绘制波形的时候,我发现浏览器会直接被阻塞卡死,这里我加上了时间跟状态(加载数据、解码、绘图、完成)

上面可交换的图像格式中可以看出,在3.7 秒时卡住,状态直接跳过了”绘图”

我们再给绘图加上日志,看花费了多少时间

draw(channelData) {

console.time('时长');

这个。绘制时间轴();

this.drawWave(channelData,step);

console.timeEnd('时长');

可以看到,整个绘图过程花费一秒多,在这一秒内,浏览器被阻塞无法做任何动作。所以我想将这些任务根据帆布的数量拆分开来,异步地一个个去执行

这里将渲染时间轴方法写成单个任务,每次执行渲染一个画布

绘制时间线(n) {

常数start=n * 120

const end=n===this。画布。长度-1?数学。ceil(这个。总时间):开始120;

对于(设i=开始我结束;i=1) {

这[`timeline${n}Ctx`] .font=” 10px Arial

这[`timeline${n}Ctx`] .fillStyle='rgba(0,0,0,1)'

这[`timeline${n}Ctx`] .fillRect(this.unitwidth='360px 'height='auto' /

如果(i % 120) {

这[`timeline${n}Ctx`] .fillText(

持续时间(一).拆分('')[0],

this.unitwidth='360px 'height='auto' /

同理,将波形渲染方法写成单个任务,并计算当前任务的通道数据数据的位置

drawWave(channelData,step,n) {

设步进索引=0;

设xIndex=0;

设min=1;

设max=-1;

const数据长度=120 * this。采样率;//每2分钟的数据长度时间* 采样频率

const start=n *数据长度

const end=n===this。画布。长度-1?数学。ceil(这个。总时间)*这个。采样率:起始数据长度;

对于(设i=开始我结束;i=1) {

步进指数=1;

const item=channel data[I]| | 0;

如果(最小项目){

最小值=项目;

} else if (item max) {

最大=项目

if (stepIndex=step) {

xIndex=1;

这个[`wave${n}Ctx`] .fillStyle='rgba(0,0,0,0.3)'

const l=(max-min)* 40 * 0.8;

这个[`wave${n}Ctx`] .fillRect(xIndex,40 – (l/2),1,Math.max(1,l));

步进索引=0;

最后利用设置超时一个个执行任务

draw(channelData) {

对于(设I=0;我这个。画布。长度;i=1) {

setTimeout(()={

这个。绘制时间线(一);

this.drawWave(channelData,step,I);

},I * 100);

从可交换的图像格式可以看到原本需要卡顿一秒,现在被分割成多个任务异步渲染,也将卡顿时间拆分,增加用户体验

这次再来挑战一小时54 分钟音频

上图看到即便做了异步的优化,但本质不能减少卡顿时间,长时间音频依然得花大量时间计算、渲染。

那如何去减少卡顿的时间?

我们知道卡顿是因为有大量的数据去计算波形的最大值、最小值,计算过程中会直接阻塞浏览器从而造成卡顿。减少卡顿必须得对这段计算进行”特殊处理”。

可以想到不阻塞浏览器有网络工作者和requestIdleCallback,熟悉反应的同学肯定知道,我们可以通过requestIdleCallback api去把计算任务放到浏览器空闲时间去做

下面我将一次渲染任务一分为10,每次渲染12 秒音频波形,浏览器空闲时间执行12 秒波形渲染,首先创建一个工作任务类

课程任务{

构造函数(ctx,{

数量、总目标、采样率、总时间、步长、通道数据、

这个数字=数字

这个。通道数据=通道数据;

这个。start=(num-1)* 120 *采样率;

this.end=num===totoal?(总时间-(num-1)* 120)*采样率:num * 120 *采样率;

这个。步进索引=0;

这个。min=-1;

这个。max=0;

这个。xindex=0;

这一步=一步

this.ctx=ctx

这个。次数=1;

this.maxTimes=10

这个。渲染长度=数学。ceil((这个。结束这一切。开始)/这个。最大次数);

if (this.times tiis.maxTimes) {

返回空

const start=(this。乘以-1)*这个。渲染长度。开始;

const end=this。倍===这个。最大次数?这个。结束:开始这个。渲染长度;

对于(设i=开始我结束;i=1) {

这个。步进指数=1;

常量项=this。通道数据[I]| | 0;

if (item this.min) {

this.min=item

} else if (item this.max) {

this.max=item

if (this.stepIndex=this.step) {

这个。xindex=1;

this.ctx.fillStyle='rgba(0,0,0,0.1)'

const l=(this。麦克斯-这个。min)* 40 * 0.8;

this.ctx.fillRect(this.xIndex,40 – (l/2),1,Math.max(1,l));

这个。步进索引=0;

这个。min=1;

这个。max=-1;

这个。次数=1;

还这个;

导出默认任务;

上面工作类作用就是每调用奔跑方法就渲染12 秒的波形,第11 次调用后会返回空告诉程序渲染下一条画布

【更多音视频学习资料,点击下方链接免费领取,先码住不迷路~】

点击领取音视频开发基础知识和资料包

drawWave(channelData,step) {

const drawWork=(截止日期)={

if (deadline.timeRemaining() 0) {

if (i=this.canvas.length) {

如果(!绘制){

绘制=新任务(这[`wave${i – 1}Ctx`],{

总计:this.canvas .长度,

sampleRate: this.sampleRate

totalTime: this.totalTime,

channelData,

画=画。run();

如果(!绘制){

if (i=this.canvas.length) {

requestIdleCallback(绘制工作);

if (requestIdleCallback) {

requestIdleCallback(drawWork,{ time out:1000 });

//不支持requestIdleCallback采用异步方案

this.status='完成;

效果明显好多了,但是任务分得越多越细,波形对应时间的误差也会越大。因为任务分10 段时,数据是直接除以10 的,不一定是步骤的倍数,所以会造成偏差,下面再做一步优化

这个。渲染长度=数学。ceil((这个。结束这一切。开始)/步骤/这个。最大次数)*步长同理时间轴也可以做时间切片优化,这里就不介绍了\\ u200b

这次换一个3小时43 分钟的音频,页面直接崩溃

查明原因是在解码阶段解码音频数据方法解析不了太大数据,下面就对请求到的缓冲器进行分段,分别去解码\\ u200b

方案有2种,一是使用承诺。所有得到排列数据

解码音频数据(缓冲区){

const audioCtx=new(窗口音频上下文| |窗口。webkitaudiocontext)();

const promise array=[];

常量大小=1024 * 1024 * 0.1

const num=数学。细胞(缓冲。字节长度/大小);

对于(设I=0;i numi=1) {

常数p=新承诺((解决)={

audioCtx.decodeAudioData(

buffer.slice(大小* i,大小*(I ^ 1)),

(音频缓冲区)={

const { sampleRate }=音频缓冲器

常量通道数据=音频缓冲区。getchanneldata(0);

这个。采样速率=采样速率;

解析(渠道数据);

无极阵。推(p);

Promise.all(promiseArray)。然后((res)={

控制台。日志(分辨率);

得到的结果

解码音频数据其实也有承诺写法,但回调函数语法兼容性更好,我只看铬对我没影响

另一种是递归,得到数组通道数据数据

解码音频数据(缓冲区){

const audioCtx=new(窗口音频上下文| |窗口。webkitaudiocontext)();

常量大小=1024 * 1024 * 0.1

const num=数学。细胞(缓冲。字节长度/大小);

常量通道数据=[];

让len=0

const decode=()={

audioCtx.decodeAudioData(

buffer.slice(大小* i,大小*(I ^ 1)),

(音频缓冲区)={

const { sampleRate }=音频缓冲器

这个。采样速率=采样速率;

const CD=音频缓冲器。getchanneldata(0);

channelData.push(光盘);

莱恩=cd.length//记录通道数据长度

如果(识别号){

控制台。日志(通道数据);

2种方案得到数据一样,用时上承诺。所有更优秀,但我更倾向于递归方案,因为还可以做后续优化

接着因为通道数据的数据结构变了,从原来TypedArray变成数组类型数组,再加个获取通道数据对应数据的方法

getChannelDataItem(index) {

if (this.cdl index) {

归还这个。渠道数据【这个。我][索引-这个。cdll];

这个。I=1;

for(;这个。我这个。频道数据。长度;this.i=1) {

这个。cdll=这个。CDL;

这个。CDL=这个。渠道数据【这个。我].长度;

if (this.cdl index) {

归还这个。渠道数据【这个。我][索引-这个。cdll];

这个方法里加一层缓存,减少计算量,因为传入的参数指数是稳定累加的

【更多音视频学习资料,点击下方链接免费领取,先码住不迷路~】

点击领取音视频开发基础知识和资料包

最终效果

但是问题来了,这解码音频数据解码时间也太长了,上图显示花费了25 秒,总不能让用户干等着,况且还没算上加载、渲染时间

所以这里再做一下优化,解码多少数据,优先渲染多少数据,不必等到所有数据解码后再渲染

解码音频数据(缓冲区){

const audioCtx=new(窗口音频上下文| |窗口。webkitaudiocontext)();

常量大小=1024 * 1024 * 0.1

const num=数学。细胞(缓冲。字节长度/大小);

常量通道数据=[];

设len=0;

let buffer data=new float 32 array();//储存多余数据

const decode=()={

audioCtx.decodeAudioData(

buffer.slice(大小* i,大小*(I ^ 1)),

(音频缓冲区)={

const { sampleRate }=音频缓冲器

这个。采样速率=采样速率;

const CD=音频缓冲器。getchanneldata(0);

channelData.push(光盘);

常数步长=数学。地板(这个。总时间*采样率/(100 *数学。ceil(这个。总时间)));

if (i===1) {

this.draw(null,step);//这里改成渲染时间轴

if (bufferData.length 0) {

const data=新的float 32数组(缓冲区数据。长度CD。长度);

data.set(bufferData,0);

data.set(cd,缓冲数据。长度);//合并数据

this.drawWave(data.slice(0,data.length – data.length % step),len,step);

len=(数据长度-数据长度%步长);

缓冲数据=数据。切片(数据。长度-数据。长度%步长,数据。长度);

} else { //第一次解码

this.drawWave(cd.slice(0,cd.length – cd.length % step),len,step);

len=(cd.length – cd.length %步长);//记录解码的累计长度

缓冲数据=CD。切片(CD。长度-CD。长度%步长。长度);//存储多余的数据

如果(识别号){

这里加了bufferData变量,主要是因为解码出来的数据长度假设为44500,而步骤为400 (400个数据渲染一个像素)最终渲染出111 个像素,多出来的100 个数据就被抛弃,造成了误差\\ u200b

所以这里加了bufferData来储存多余数据,下次译后拼接起来

接着修改牵引波方法

拉伸波(通道数据,长度,步长){

让我们抽签=新任务(这个,{

channelData,

x:镜头/步长,

unitwidth=' 360px像素像素,height='auto' /

const drawWork=(截止日期)={

如果(截止日期。剩余时间()10){

画=画。run();

如果(绘制){

requestIdleCallback(drawWork,{ time out:1000 });

if (requestIdleCallback) {

requestIdleCallback(drawWork,{ time out:1000 });

然后修改下工作类,之前是基于时间,每2分钟一个工作实例,再分成10 分运行计算。现在则是基于解码音频数据解码出来的一段channelData,每一段一个工作实例,持续调用奔跑方法结算数据、渲染\\ u200b

课程任务{

构造函数(虚拟机,{

channelData,

unitwidth=' 360px像素像素,height='auto' /

this.w=unitwidth='360px 'height='auto' /

这个。通道数据=通道数据;

this.vm=vm

this.x=x

这一步=一步

this.maxTimes=20

这个。渲染长度=数学。ceil(通道数据。长度/步长/这个。最大次数)*步长;

stepIndex=0

if (this.times this.maxTimes) {

返回空

const start=(this。乘以-1)*这个。渲染长度;

const end=开始这个。渲染长度;

对于(设i=开始我结束;i=1) {

这个。步进指数=1;

常量项=this。通道数据[I]| | 0;

if (item this.min) {

this.min=item

} else if (item this.max) {

this.max=item

if (this.stepIndex=this.step) {

这个。x=1;

const num=数学。地板(这个。x/这个。w);

if (this.vm[`wave${num}Ctx`]) {

this.vm[`wave${num}Ctx`] .fillStyle='rgba(0,0,0,0.1)'

const l=(this。麦克斯-这个。min)* 40 * 0.8;

this.vm[`wave${num}Ctx`] .fillRect((this.x % this.w),40 – (l/2),1,Math.max(1,l));

这个。步进索引=0;

这个。min=1;

这个。max=-1;

这个。次数=1;

还这个;

导出默认t;

这里的最大次数并不一定写死,最好能把单个任务控制在10ms左右

最终结果

相比下再也不用等待25 秒了。但是似乎还是有点卡顿?

用表演来查看下,是什么导致的。选中英国制药学会会员红色的点(表示帧数低)查看火焰图上耗时的函数,再点击具体代码位置

结果是储存bufferData花费了很多时间,打印下具体时间

那换成不储存,浪费就浪费误差就误差试试效果

仔细看是有好一点,具体的取舍还是看实际业务吧\\ u200b

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

综合资源

【五育并举】墨云校庆与书华篇

2024-11-8 21:18:47

苹果的MR耳机将在未来几个月发布。

2022-8-30 23:27:46

购物车
优惠劵
搜索