OpenGL—Android 开机动画源码分析一
.1 Android开机动画实现方式目前实现Android开机动画的方式主要是逐帧动画和OpenGL动画。
?逐帧动画
逐帧动画是一种常见的动画形式(Frame By Frame),其原理是在“连续的关键帧”中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画。 因为逐帧动画的帧序列内容不一样,不但给制作增加了负担而且最终输出的文件量也很大,但它的优势也很明显:逐帧动画具有非常大的灵活性,几乎可以表现任何想表现的内容,而它类似与电影的播放模式,很适合于表演细腻的动画。
逐帧动画是网上广泛流传的一种实现方法。实现原理是将一系列图片打包成bootanimation.zip放入/system/media/目录,系统将图片一帧一帧循环播放形成一个动画效果。理论上讲这种方法应该是可以实现一切动画需求的,但是实践后你会发现当bootanimation.zip大于5M的时候,动画将有明显卡顿,文件越大动画越不流畅。所以细心的同学会发现手机上的开机动画大多都是只有中间一小部分在变化,而四周全是黑色,这样做是为了使得可以采用100*50(甚至更小)分辨率的图片,这样100帧也才几M的大小。
?OpenGL动画
OpenGL(英语:Open Graphics Library)是个定义了一个跨编程语言、跨平台的应用程序接口(API)的规范,它用于生成二维、三维图像。这个接口由近三百五十个不同的函数调用组成,用来从简单的图形比特绘制复杂的三维景象。
比较两种方式我们不难发现,电视平台上和手机有所不同,特别是开机广告,1920*1080分辨率的图片一张就几百KB,由于大小的限制导致动画帧数很少,所以电视平台采用“逐帧动画”方法无法做出复杂而流畅的动画,本文将主要讨论OpenGL的实现方式。
1.2 原生开机动画的源码分析
在制作自己的开机动画之前,我们先分析一下Android原生的开机动画源码。Android系统的开机动画源码位于framework/base/cmds/bootanimation(表1)。
Bootanimation程序目录:android-x.x/framework/base/cmds/bootanimation/ |
|
Android.mk |
Android编译定义 |
bootanimation_main.cpp |
入口文件 |
BootAnimation.h |
BootAnimation类的声明 |
BootAnimation.cpp |
BootAnimation类的定义和实现 |
先来看一下bootanimation_main.cpp,这个文件定义了main函数,代码如下:
[bootanimation_main.cpp]
int main(int argc, char** argv)
{
……
sp proc(ProcessState::self());
ProcessState::self()->startThreadPool(); // create the boot animation object
sp boot = new BootAnimation(); IPCThreadState::self()->joinThreadPool();
……
}
Main函数的代码很简单,首先启动Process的线程池,然后创建一个BootAnimation对象,最后将BootAnimation对象加入到刚才的线程池中, startThreadPool()和joinThreadPool()的用法可以参考android的binder机制。
下面就一起来看一下BootAnimation类:
[BootAnimation.h]
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
……
private:
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
virtual void binderDied(const wp& who);
……
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(void* buffer, size_t len);
bool android();
bool movie(); void checkExit();
……
}
BootAnimation类继承了Thread类和IBinder::DeathRecipient类,几个override函数的作用如下:
?onFirstRef()属于其父类RefBase,该函数在强引用sp新增引用计数時调用,就是当 有sp包装的类初始化的时候调用。
?binderDied(),当对象死掉时或者其他情况导致该Binder发生结束了,就会回调binderDied()方法;
?readyToRun()定义Thread执行前的初始化工作;
?threadLoop()是每个线程类都要实现的,在这里定义thread的执行内容,这个函数如果返回true,则函数会不停地执行threadloop中的内容,如果这个函数返回false,则threadloop中的内容仅仅执行一次线程就会退出;
[BootAnimation::onFirstRef()]
onFirstRef函数中执行了run BootAnimation线程。
void BootAnimation::onFirstRef()
{
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);
}
} void BootAnimation::binderDied(const wp& who)
{
kill( getpid(), SIGKILL );
requestExit();
}
[BootAnimation::readyToRun()]
status_t BootAnimation::readyToRun() {
......
// create the native surface
......
// initialize opengl and egl
......
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
......
surface = eglCreateWindowSurface(display, config, s.get(), NULL);
......
mDisplay = display;
......
mSurface = surface;
......
}
readyToRun函数主要是为了得到EGLDisplay mDisplay和EGLDisplay mSurface对象,这两个对象后面再介绍,最后函数还会查询是否存在bootanimation.zip并初始化mAndroidAnimation的值。
#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
......
bool BootAnimation::threadLoop()
{
bool r;
if (mAndroidAnimation) {
r = android();
} else {
r = movie();
}
......
}
[BootAnimation::threadLoop()]
BootAnimation::readyToRun中会检查是否存在bootanimation.zip,如果存在bootanimation.zip这里就执行movie(),否则执行android()。movie()为逐帧动画的实现,android()为opengl动画的实现,本文只考虑无bootanimation.zip的情况。
[BootAnimation::android()]
bool BootAnimation::android()
{
initTexture(&mAndroid[], mAssets, "images/android-logo-mask.png");
initTexture(&mAndroid[], mAssets, "images/android-logo-shine.png");
......
do {
......
glBindTexture(GL_TEXTURE_2D, mAndroid[].name);
glDrawTexiOES(xc, yc, , mAndroid[].w, mAndroid[].h); EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
......
checkExit();
} while (!exitPending());
......
}
终于到了绘图的步骤了,BootAnimation::android函数包含了整个opengl绘图的过程,因为android使用的是标准opengl es api,所以opengl的初始化和绘图过程这里就不详细介绍了,
这里需要注意的是eglSwapBuffers(mDisplay, mSurface),这个方法将mSruface投递到屏幕,这里用到了两个EGLDisplay对象,是由于使用了双缓冲机制,配合sleep实现稳定的刷新率。
最后当检测到系统初始化完成时退出程序。
OpenGL—Android 开机动画源码分析一的更多相关文章
- OpenGL—Android 开机动画源码分析二
引自http://blog.csdn.net/luoshengyang/article/details/7691321/ BootAnimation类的成员函数的实现比较长,我们分段来阅读: 第三个开 ...
- Android 开机动画源码分析
Android系统在启动SystemServer进程时,通过两个阶段来启动系统所有服务,在第一阶段启动本地服务,如SurfaceFlinger,SensorService等,在第二阶段则启动一系列的J ...
- Android 属性动画 源码解析 深入了解其内部实现
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/42056859,本文出自:[张鸿洋的博客] 我参加了博客之星评选,如果你喜欢我的博 ...
- Android网络框架源码分析一---Volley
转载自 http://www.jianshu.com/p/9e17727f31a1?utm_campaign=maleskine&utm_content=note&utm_medium ...
- Android分包MultiDex源码分析
转载请标明出处:http://blog.csdn.net/shensky711/article/details/52845661 本文出自: [HansChen的博客] 概述 Android开发者应该 ...
- Android消息机制源码分析
本篇主要介绍Android中的消息机制,即Looper.Handler是如何协同工作的: Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper Handler:用来将消息(Me ...
- Android开源框架源码分析:Okhttp
一 请求与响应流程 1.1 请求的封装 1.2 请求的发送 1.3 请求的调度 二 拦截器 2.1 RetryAndFollowUpInterceptor 2.2 BridgeInterceptor ...
- android hardware.c 源码分析
android的jni通过ID来找hal模块,使用了hw_get_module()函数,本文就通过这个函数的来分析一下hal层的模块是如何匹配的. 首先要了解三个结构体hw_module_t,hw_m ...
- Android -- 消息处理机制源码分析(Looper,Handler,Message)
android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...
随机推荐
- Ubuntu安装Mysql过程及远程问题解决
ubuntu下执行 sudo apt-get instlll mysql-server sudo apt-get install mysql-client 安装过程中会有文字界面设置密码 牢记密码 M ...
- C 语言字符数组的定义与初始化
1.字符数组的定义与初始化字符数组的初始化,最容易理解的方式就是逐个字符赋给数组中各元素.char str[10]={ 'I',' ','a','m',' ',‘h’,'a','p','p','y'} ...
- hdfs zkfc –formatZK 之HadoopIllegalArgumentException: Bad argument: –formatZK
HadoopIllegalArgumentException: Bad argument: –formatZK从某文档中拷贝的命令,粘贴过来使用的,“–formatZK”有问题解决方法:手工输入此命令 ...
- Linux(power服务器)中kettle(2)
Hadoop集群硬件环境 4台机器 ip地址 172.16.1.131 172.16.1.132 172.16.1.133 172.16.1.134 每台内存16G 8核cpu 直接使用报错:
- hdu 5876 Sparse Graph icpc大连站网络赛 1009 补图最短路
BFS+链表 代码改自某博客 #include<stdio.h> #include<iostream> #include<algorithm> #include&l ...
- VC 中使用 CToolTipCtrl 消失后不再出现的Bug。。。。
最近用WTL重写CGdipButton.从ButtonST中将CtoolTipCtrl的相关代码转过来,发现一个问题: ToolTip可以显示,鼠标移开后再移动到button上也可以再次显示,但是按下 ...
- Smarty练习增删改
<?php //将题目表显示在页面 include("../init.inc.php"); include("../DBDA.php"); $db = n ...
- elicpse之tomcat配置
环境:eclipse4.5.0,tomcat7.0.57 部署描述:按照一般的部署,把tomcat部署到webapps的下面,server options 下面选的是 Modules auto rel ...
- error while loading shared libraries: libseaudit.so.4: cannot open shared object file: Error 40
安装共享库后要注意共享库路径设置问题, 如下: 1) 如果共享库文件安装到了/lib或/usr/lib目录下, 那么需执行一下ldconfig命令 ldconfig命令的用途, 主要是在默认搜寻目录( ...
- 十五、oracle 约束
一.维护数据的完整性数据的完整性用于确保数据库数据遵从一定的商业和逻辑规则,在oracle中,数据完整性可以使用约束.触发器.应用程序(过程.函数)三种方法来实现,在这三种方法中,因为约束易于维护,并 ...