首页 文章 精选 留言 我的

精选列表

搜索[三大系统],共10000篇文章
优秀的个人博客,低调大师

Android系统的开机画面显示过程分析(11)

BootAnimation类的成员函数movie的实现比较长,我们分段来阅读: boolBootAnimation::movie() { ZipFileRO&zip(mZip); size_tnumEntries=zip.getNumEntries(); ZipEntryROdesc=zip.findEntryByName("desc.txt"); FileMap*descMap=zip.createEntryFileMap(desc); LOGE_IF(!descMap,"descMapisnull"); if(!descMap){ returnfalse; } String8desString((charconst*)descMap->getDataPtr(), descMap->getDataLength()); charconst*s=desString.string(); Animationanimation; //Parsethedescriptionfile for(;;){ constchar*endl=strstr(s,"\n"); if(!endl)break; String8line(s,endl-s); constchar*l=line.string(); intfps,width,height,count,pause; charpath[256]; if(sscanf(l,"%d%d%d",&width,&height,&fps)==3){ //LOGD(">w=%d,h=%d,fps=%d",fps,width,height); animation.width=width; animation.height=height; animation.fps=fps; } if(sscanf(l,"p%d%d%s",&count,&pause,path)==3){ //LOGD(">count=%d,pause=%d,path=%s",count,pause,path); Animation::Partpart; part.count=count; part.pause=pause; part.path=path; animation.parts.add(part); } s=++endl; } 从前面BootAnimation类的成员函数readyToRun的实现可以知道,如果目标设备上存在压缩文件/data/local/bootanimation.zip,那么BootAnimation类的成员变量mZip就会指向它,否则的话,就会指向目标设备上的压缩文件/system/media/bootanimation.zip。无论BootAnimation类的成员变量mZip指向的是哪一个压缩文件,这个压缩文件都必须包含有一个名称为“desc.txt”的文件,用来描述用户自定义的开机动画是如何显示的。 文件desc.txt的内容格式如下面的例子所示: 60048024 p10part1 p010part2 第一行的三个数字分别表示开机动画在屏幕中的显示宽度、高度以及帧速(fps)。剩余的每一行都用来描述一个动画片断,这些行必须要以字符“p”来开头,后面紧跟着两个数字以及一个文件目录路径名称。第一个数字表示一个片断的循环显示次数,如果它的值等于0,那么就表示无限循环地显示该动画片断。第二个数字表示每一个片断在两次循环显示之间的时间间隔。这个时间间隔是以一个帧的时间为单位的。文件目录下面保存的是一系列png文件,这些png文件会被依次显示在屏幕中。 以上面这个desct.txt文件的内容为例,它描述了一个大小为600 x 480的开机动画,动画的显示速度为24帧每秒。这个开机动画包含有两个片断part1和part2。片断part1只显示一次,它对应的png图片保存在目录part1中。片断part2无限循环地显示,其中,每两次循环显示的时间间隔为10 x (1 / 24)秒,它对应的png图片保存在目录part2中。 上面的for循环语句分析完成desc.txt文件的内容后,就得到了开机动画的显示大小、速度以及片断信息。这些信息都保存在Animation对象animation中,其中,每一个动画片断都使用一个Animation::Part对象来描述,并且保存在Animation对象animation的成员变量parts所描述的一个片断列表中。 接下来,BootAnimation类的成员函数movie再断续将每一个片断所对应的png图片读取出来,如下所示: //readallthedatastructures constsize_tpcount=animation.parts.size(); for(size_ti=0;i<numEntries;i++){ charname[256]; ZipEntryROentry=zip.findEntryByIndex(i); if(zip.getEntryFileName(entry,name,256)==0){ constString8entryName(name); constString8path(entryName.getPathDir()); constString8leaf(entryName.getPathLeaf()); if(leaf.size()>0){ for(intj=0;j<pcount;j++){ if(path==animation.parts[j].path){ intmethod; //supportsonlystoredpngfiles if(zip.getEntryInfo(entry,&method,0,0,0,0,0)){ if(method==ZipFileRO::kCompressStored){ FileMap*map=zip.createEntryFileMap(entry); if(map){ Animation::Frameframe; frame.name=leaf; frame.map=map; Animation::Part&part(animation.parts.editItemAt(j)); part.frames.add(frame); } } } } } } } } 每一个png图片都表示一个动画帧,使用一个Animation::Frame对象来描述,并且保存在对应的Animation::Part对象的成员变量frames所描述的一个帧列表中。 获得了开机动画的所有信息之后,接下来BootAnimation类的成员函数movie就准备开始显示开机动画了,如下所示: //clearscreen glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mDisplay,mSurface); glBindTexture(GL_TEXTURE_2D,0); glEnable(GL_TEXTURE_2D); glTexEnvx(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); glTexParameterx(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterx(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameterx(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameterx(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); constintxc=(mWidth-animation.width)/2; constintyc=((mHeight-animation.height)/2); nsecs_tlastFrame=systemTime(); nsecs_tframeDuration=s2ns(1)/animation.fps; RegionclearReg(Rect(mWidth,mHeight)); clearReg.subtractSelf(Rect(xc,yc,xc+animation.width,yc+animation.height)); 前面的一系列gl函数首先用来清理屏幕,接下来的一系列gl函数用来设置OpenGL的纹理显示方式。 变量xc和yc的值用来描述开机动画的显示位置,即需要在屏幕中间显示开机动画,另外一个变量frameDuration的值用来描述每一帧的显示时间,它是以纳秒为单位的。 Region对象clearReg用来描述屏幕中除了开机动画之外的其它区域,它是用整个屏幕区域减去开机动画所点据的区域来得到的。 准备好开机动画的显示参数之后,最后就可以执行显示开机动画的操作了,如下所示: for(inti=0;i<pcount&&!exitPending();i++){ constAnimation::Part&part(animation.parts[i]); constsize_tfcount=part.frames.size(); glBindTexture(GL_TEXTURE_2D,0); for(intr=0;!part.count||r<part.count;r++){ for(intj=0;j<fcount&&!exitPending();j++){ constAnimation::Frame&frame(part.frames[j]); if(r>0){ glBindTexture(GL_TEXTURE_2D,frame.tid); }else{ if(part.count!=1){ glGenTextures(1,&frame.tid); glBindTexture(GL_TEXTURE_2D,frame.tid); glTexParameterx(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameterx(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); } initTexture( frame.map->getDataPtr(), frame.map->getDataLength()); } if(!clearReg.isEmpty()){ Region::const_iteratorhead(clearReg.begin()); Region::const_iteratortail(clearReg.end()); glEnable(GL_SCISSOR_TEST); while(head!=tail){ constRect&r(*head++); glScissor(r.left,mHeight-r.bottom, r.width(),r.height()); glClear(GL_COLOR_BUFFER_BIT); } glDisable(GL_SCISSOR_TEST); } glDrawTexiOES(xc,yc,0,animation.width,animation.height); eglSwapBuffers(mDisplay,mSurface); nsecs_tnow=systemTime(); nsecs_tdelay=frameDuration-(now-lastFrame); lastFrame=now; longwait=ns2us(frameDuration); if(wait>0) usleep(wait); } usleep(part.pause*ns2us(frameDuration)); } //freethetexturesforthispart if(part.count!=1){ for(intj=0;j<fcount;j++){ constAnimation::Frame&frame(part.frames[j]); glDeleteTextures(1,&frame.tid); } } } returnfalse; } 第一层for循环用来显示每一个动画片断,第二层的for循环用来循环显示每一个动画片断,第三层的for循环用来显示每一个动画片断所对应的png图片。这些png图片以纹理的方式来显示在屏幕中。 注意,如果一个动画片断的循环显示次数不等于1,那么就说明这个动画片断中的png图片需要重复地显示在屏幕中。由于每一个png图片都需要转换为一个纹理对象之后才能显示在屏幕中,因此,为了避免重复地为同一个png图片创建纹理对象,第三层的for循环在第一次显示一个png图片的时候,会调用函数glGenTextures来为这个png图片创建一个纹理对象,并且将这个纹理对象的名称保存在对应的Animation::Frame对象的成员变量tid中,这样,下次再显示相同的图片时,就可以使用前面已经创建好了的纹理对象,即调用函数glBindTexture来指定当前要操作的纹理对象。 如果Region对象clearReg所包含的区域不为空,那么在调用函数glDrawTexiOES和eglSwapBuffers来显示每一个png图片之前,首先要将它所包含的区域裁剪掉,避免开机动画可以显示在指定的位置以及大小中。 每当显示完成一个png图片之后,都要将变量frameDuration的值从纳秒转换为毫秒。如果转换后的值大小于,那么就需要调用函数usleep函数来让线程睡眠一下,以保证每一个png图片,即每一帧动画都按照预先指定好的速度来显示。注意,函数usleep指定的睡眠时间只能精确到毫秒,因此,如果预先指定的帧显示时间小于1毫秒,那么BootAnimation类的成员函数movie是无法精确地控制地每一帧的显示时间的。 还有另外一个地方需要注意的是,每当循环显示完成一个片断时,需要调用usleep函数来使得线程睡眠part.pause * ns2us(frameDuration)毫秒,以便可以按照预先设定的节奏来显示开机动画。 最后一个if语句判断一个动画片断是否是循环显示的,即循环次数不等于1。如果是的话,那么就说明前面为它所对应的每一个png图片都创建过一个纹理对象。现在既然这个片断的显示过程已经结束了,因此,就需要释放前面为它所创建的纹理对象。 至此,第三个开机画面的显示过程就分析完成了。 本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/967046,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册