京东小程序接入ARVR的技能计划和功能调优
作者:京东零售 戴旭
京东小程序是一个敞开技能渠道,正在被越来越多的头部品牌挑选,用于站内私域流量的营销和运营。比方各种日化、奢侈品等品牌对ARVR有较多的诉求,期望京东小程序引擎供给一些底层才能,叠加品牌自主的个性化开发和定制,以支撑愈加丰厚的场景和玩法,比方AR试妆、试戴等。
咱们小程序引擎联合ARVR团队,在两边产研测的尽力和协作下,完结了相关才能的规划和开发。全体功用于京东APP11.6.6版别发布上线,等候为更多的商家和品牌赋能。
体会途径和作用(担任相关模块的产品小姐姐友谊录屏)
技能计划
这儿以人脸辨认为例,先介绍全体的技能计划。
概念介绍
技能关键词:相机、实时帧、AR算法、同层烘托、WebGL。
这几个关键词里边,前三个比较好了解,人脸辨认,会用相机收集人脸的实时帧数据,调用AR算法,获取计算结果,把数据传输给小程序前端。
后边两个关键词和小程序的场景有联系,WebGL技能是小程序为了支撑游戏、ARVR等高功能烘托的需求,选用原生的OpenGL完结了一套WebGL的接口。小程序页面是WebView烘托,而咱们已然说到了选用OpenGL原生烘托,就需求把原生组件,正确的刺进到Web的视图层级,同层烘托便是将原生组件和WebView DOM 元素放在一同进行混合烘托的技能,能够保证原生组件和 DOM 元素在烘托层级、翻滚、接触工作处理等方面保持共同。
全体流程
小程序引擎在底层原生支撑了相机、实时帧、AR、WebGL等才能,一起暴露了若干 js 的api。小程序开发者经过相关api的调用,履行敞开相机、获取实时帧数据,调用AR接口,获取计算结果数据,进行WebGL烘托等操作。扼要的流程如下:
分层规划
从分层的视点看整个技能计划的规划,大致如下:
其间在AR引擎这一层,分为内置和外部AR引擎,也是因为小程序自身是敞开的技能渠道,咱们选用了接口协议化的规划,支撑第三方宿主选用自主的AR引擎,一起供给了相机、实时帧、WebGL等原子化才能,小程序服务商能够构建专有的AR引擎为上层事务赋能。
技能应战
WebGL技能原理的篇幅过大,它也不仅仅是为了ARVR这个场景服务,所以包括AR算法之内,都不在本篇的详细介绍规模之内。
在这部分,咱们专心于小程序和ARVR叠加的范畴:内存和帧率的优化。
咱们知道在赏识电视和电影画面时,只需画面刷新率到达24帧/秒,就能满意人们的需求,也便是说咱们至少要在中端乃至中低端的机器上到达24帧以上的帧率。
为了保证根本的画质,相机实时帧的分辨率设置为1280*720,以RBGA格局存储,那么每一帧的数据是1280*720*4=3686400Byte,约3.5MB,每秒24帧以上的帧率,这个是不小的数据量。总的来说,在功能优化上,咱们遇到的首要应战如下:
应战1,数据从原生传输到js,在从js传递到原生,如此大的数据量将会成为js和原生通讯的瓶颈;
应战2,在iOS渠道上,相机output只能指定BGRA格局,因为原始相机实时帧 CMSampleBufferRef目标内包括CVPixelBuffer目标,CoreVideo目标不支撑RGBA格局,参阅官方文档
https://developer.apple.com/library/archive/qa/qa1501/_index.html
而WebGL规范的接口不支撑BGRA格局,参阅文档:
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D,数据格局的转化会加剧功能的担负;
应战3,即使以24帧为规范,每一帧的处理时刻大约只要41ms,需求阅历原生相机出产、数据格局转化、数据双向传输、ar算法、webgl制作等流程,每一环节都很重,咱们需求考虑怎么运用并发调度优势,而且保证实时帧的时序不会发生紊乱,因为时序一旦乱了,印象尽管一向在输出,可是视觉感触是紊乱的。
针对上述应战,进行了一系列的优化,终究在中低端手机(iPhone8 Plus)上到达均匀26~27帧的帧率,全体体会较为流通,详细调优下面详细介绍。
功能调优
1、数据传输优化
原生和js之间传输很多的数据会成为功能的瓶颈,数据传输优化便是削减数据传输频次,最好是数据保存一份,只传递数据的符号。
咱们规划了一个NativeBuffer缓存来优化这个问题。首要流程如下
可是在js环境中,终究仍是要运用js目标,原生相机实时帧的数据需求被转化为js目标。那么怎么做才能让数据只保存一份呢?
NO COPY
iOS端挑选运转小程序的js结构是JavaScriptCore,JavaScriptCore供给了一些C言语的接口办法,能够以NO COPY的办法,把一个void类型的二进制数据指针作为backing store,创立相对应的js目标,一般类型是ArrayBuffer或许TypeArray。也便是说原生和js目标背面的数据是同一份,同享这部分内存。
这样一来咱们只需求保证缓存的原始相机实时帧的数据不开释,那么js目标引证的这部分数据就会一向有用。那这部分数据要在什么时分去整理呢?
毁掉
在创立js目标的时分,能够指定一个C的函数指针作为入参。当JavaScriptCore检测到这个js目标毁掉的时分,会主动触发该C函数的调用。咱们需求依照指定的函数原型完结一个C的办法,在这个函数里去做缓存的整理,能够看一下这个函数的原型:
typedef void (*JSTypedArrayBytesDeallocator)(void* bytes, void* deallocatorContext);
该函数有2个参数,第一个bytes是原始相机实时帧的二进制数据,第二个是上下文环境,这儿咱们传的是NativeBuffer办理类的实例,在这个函数的详细完结中,咱们去匹配NativeBuffer办理的缓存地址,找到相关数据进行整理。
写入优化
前面咱们说过,数据流通是双向的。原生把相机的数据传输到js侧,js调用ARVR的人脸检测接口,还需求把这份数据在传输到原生。因为相机和人脸检测是彼此独立的接口,js拿到相机数据不一定非要调用人脸检测,调用人脸检测的数据也不一定非要来自于相机,还能够是一个本地的图片。
相对应的,咱们在NativeBuffer的规划中,供给数据双向传递的接口,getNativeBuffer:id和setNativeBuffer:id。在原生传递到js的数据中,咱们用了NO Copy的办法去做优化,那么在js传递到原生的数据,因为咱们不知道数据来历,所以需求拓荒一份新的内存空间,调用memcpy仿制数据。可是实践上,咱们在做数据仿制之前,能够用JavaScriptCore供给的接口,从js的ArrayBuffer目标中提取到实在数据的内存地址,然后在NativeBuffer缓存池中查找,假如找到了则无需再做数据仿制。这样保证了数据一直只要一份。
数据类型
在实践的过程中,js端在挑选二进制目标的数据类型的时分,或许会用ArrayBuffer或许TypeArray。一旦js端进行了数据类型转化,比方ArrayBuffer转TypeArray,引擎在调用setNativeBuffer的时分,传递的是转化后的数据类型,将会导致setNativeBuffer内部的写入优化失效,进而在低端机上带来显着的卡顿。在这儿,咱们共同运用共同的数据类型,不能随意的转化数据类型。
2、相机实时帧格局转化
在技能应战中咱们说到,iOS渠道上,相机output只能指定为BGRA格局,而WebGL规范的接口不支撑该格局。假如不进行格局转化,会导致红蓝色彩倒置,赤色物体呈现蓝色,蓝色物体呈现赤色。所以在数据缓存和传输之前,要做格局转化,咱们需求找到一个快速低成本的办法。
要想做数据格局转化,需求了解一些根本的图画数据在内存中的布局状况,如下图所示。
这儿咱们选取的BGRA和RGBA格局都是32位,也便是每一个像素点是4个字节。
实在图画数据因为内存对齐的原因,巨细并不一定是width*height*4个字节,CoreVideo结构供给了获取相机数据宽高的办法,咱们要计算出待处理的字节巨细,每4个字节做一次循环,把第一位和第三位做一个互换,就能无需malloc内存,把BGRA转化为RGBA格局。
3、并发调度
在技能应战中还说到,每一帧的处理时刻大约只要41ms,需求阅历原生相机出产、数据格局转化、数据双向传输、ar算法、webgl制作等这么多流程,怎么运用并发优势,而且保证实时帧的时序不会发生紊乱呢?
咱们为了保证UI主线程的流通,要尽或许把更多的环节放到子线程履行,这个时分哪怕写入缓存这样一个轻量的操作放到主线程都或许会带来画面的卡顿。
实时帧的处理、AR算法别离放在不同的线程,为了保证实时帧时序,均选用串行行列。
选用了多线程之后,NativeBuffer数据的存储和整理需求加上线程安全维护。
这样全体运用了多核的优势,并保证了调用时序。线程调度和处理流通如下图所示:
4、资源办理
抱负状况下,原生相机发生一个实时帧数据,JS耗费一个,在中高端机器上,功能能够满意需求,全体体现较为平稳,可是在低端机器中,线程抢占十分频频,当主线程和子线程发生线程抢占的时分,会导致供需不匹配,一旦实时帧数据耗费不及时,内存会发生爆破式的增加,所以需求限制缓存池的容量,这个一般能够依据实践调试的状况指定一个数值即可。
还有一旦呈现内存正告或许当缓存满的时分,需求去整理缓存池,buffer假如正在被运用,就不能去整理,不然或许会呈现白屏的现象,咱们给buffer加了一个是否被消费的符号,当一个buffer被消费后,它不能以惯例的办法整理,需求等候js消费完结之后整理,这个在上面也有介绍。
在页面退出的时分,引擎需求监听相关的工作,保证实时帧的监听被中止,不然会呈现多个js相机的监听工作并存,一个数据被屡次消费而引发反常。
结语
京东小程序致力于打造杰出的技能敞开渠道,咱们在提高功能、用户体会上不断尽力,咱们也在建造和完善小程序的各种才能,欢迎我们供给名贵的主张。