花了不少时间在这个数据流的分析上面,自己毕竟没怎么做过android,这里记录一下自己的见解,任何理解错误还望高人指教,以后还需慢慢纠正
整个分析过程从app的onCreate开始:packages/apps/OMAPCamera/src/com/ti/omap4/android/camera/Camera.java
在onCreate中做了很多的初始化,我们真正关注的是一下几条语句:
- // don't set mSurfaceHolder
here. We have it set ONLY
within - // surfaceChanged / surfaceDestroyed, other
parts of the code - // assume
that when it is set, the
surface is also set. - SurfaceView preview = (SurfaceView) findViewById(R.id.camera_preview);
- SurfaceHolder holder = preview.getHolder();
- holder.addCallback(this);
在这里我们实例化了一个SurfaceView对象,通过这个对象获取SurfaceHolder对象,实现这个addCallback方法,
其中SurfaceView的定义在以下路径:frameworks/base/core/java/android/view/SurfaceView.java
其中SurfaceHolder的定义在以下路径:frameworks/base/core/java/android/view/SurfaceHolder.java
这里看看这个文章的解释,写的很是不错:http://blog.chinaunix.net/uid-9863638-id-1996383.html
SurfaceFlinger 是Android multimedia 的一个部分,在Android 的实现中它是一个service ,提供系统范围内的surface composer 功能,它能够将各种应用程序的2D,3D surface 进行组合。
在具体讲SurfaceFlinger 之前,我们先来看一下有关显示方面的一些基础知识 。
每个应用程序可能对应着一个或者多个图形界面,而每个界面我们就称之为一个surface ,或者说是window ,在上面的图中我们能看到4 个surface ,一个是home 界面,还有就是红、绿、蓝分别代表的3 个surface ,而两个button 实际是home surface 里面的内容。在这里我们能看到我们进行图形显示所需要解决
的问题:
a 、首先每个surface 在屏幕上有它的位置,以及大小,然后每个surface 里面还有要显示的内容,内容,大小,位置 这些元素 在我们改变应用程序的时候都可能会改变,改变时应该如何处理
b 、然后就各个surface 之间可能有重叠,比如说在上面的简略图中,绿色覆盖了蓝色,而红色又覆盖了绿色和蓝色以及下面的home ,而且还具有一定透明度。这种层之间的关系应该如何描述
我们首先来看第二个问题,我们可以想象在屏幕平面的垂直方向还有一个Z 轴,所有的surface 根据在Z 轴上的坐标来确定前后,这样就可以描述各个surface 之间的上下覆盖关系了,而这个在Z 轴上的顺序,图形上有个专业术语叫Z-order 。
对于第一个问题,我们需要一个结构来记录应用程序界面的位置,大小,以及一个buffer 来记录需要显示的内容,所以这就是我们surface 的概念,surface 实际我们可以把它理解成一个容器,这个容器记录着应用程序界面的控制信息,比如说大小啊,位置啊,而它还有buffer 来专门存储需要显示的内容。
在这里还存在一个问题,那就是当存在图形重合的时候应该如何处理呢,而且可能有些surface 还带有透明信息,这里就是我们SurfaceFlinger 需要解决问题,它要把各个surface 组合(compose/merge) 成一个main Surface ,最后将Main Surface 的内容发送给FB/V4l2
Output ,这样屏幕上就能看到我们想要的效果。
在实际中对这些Surface 进行merge 可以采用两种方式,一种就是采用软件的形式来merge ,还一种就是采用硬件的方式,软件的方式就是我们的SurfaceFlinger ,而硬件的方式就是Overlay 。
首先继承SurfaceView并实现SurfaceHolder.Callback接口
使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface—表面,基本上我们可以把它当作显存的一个映射,写入到Surface 的内容可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束。所以Callback
中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。
需要重写的方法
(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}//在surface的大小发生改变时激发
(2)public void surfaceCreated(SurfaceHolder holder){}//在创建时激发,一般在这里调用画图的线程。
(3)public void surfaceDestroyed(SurfaceHolder holder) {} //销毁时激发,一般在这里将画图的线程停止、释放。
这几个方法在在app中都已经重新实现了,重点分析surfaceChanged
- public void surfaceChanged(SurfaceHolder
holder, int format, int w, int h) { - // Make
sure we have a surface in the holder before proceeding. - if (holder.getSurface() == null) {
- Log.d(TAG, "holder.getSurface()
== null"); - return;
- }
- Log.v(TAG, "surfaceChanged.
w=" + w + ".
h=" + h); - // We
need to save the holder for later
use, even when the mCameraDevice - // is null. This
could happen if onResume() is invoked
after this - // function.
- mSurfaceHolder = holder;
- // The
mCameraDevice will be null if it
fails to connect to the
camera - // hardware. In this case we
will show a dialog and then finish
the - // activity, so
it's OK to ignore
it. - if (mCameraDevice == null) return;
- // Sometimes
surfaceChanged is called after onPause or before
onResume. - // Ignore
it. - if (mPausing || isFinishing()) return;
- setSurfaceLayout();
- // Set preview
display if the surface is being
created. Preview was - // already
started. Also restart the preview if display
rotation has - // changed. Sometimes
this happens when the device is held in portrait - // and camera
app is opened. Rotation
animation takes some time and - // display
rotation in onCreate may not be
what we want. - if (mCameraState == PREVIEW_STOPPED) {//这里check摄像头是否已经启动,第一次启动摄像头和摄像头已经打开从新进入摄像头实现方法不同
- startPreview(true);
- startFaceDetection();
- } else {
- if (Util.getDisplayRotation(this) != mDisplayRotation) {
- setDisplayOrientation();
- }
- if (holder.isCreating()) {
- // Set preview
display if the surface is being
created and preview - // was
already started. That means preview display was set to null - // and we
need to set it now. - setPreviewDisplay(holder);
- }
- }
- // If first time initialization is not finished, send
a message to do - // it
later. We want to finish
surfaceChanged as soon as possible to let - // user
see preview first. - if (!mFirstTimeInitialized) {
- mHandler.sendEmptyMessage(FIRST_TIME_INIT);
- } else {
- initializeSecondTime();
- }
- SurfaceView preview = (SurfaceView) findViewById(R.id.camera_preview);
- CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
- boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
- int displayRotation = Util.getDisplayRotation(this);
- int displayOrientation = Util.getDisplayOrientation(displayRotation, mCameraId);
- mTouchManager.initialize(preview.getHeight() / 3, preview.getHeight() / 3,
- preview, this, mirror, displayOrientation);
- }
以上标注部分是关键,现在直接分心startPreview方法,这是第一次打开摄像头的处理函数,进行了一些初始换,而已经处于摄像头打开状态时不必使用startPreview方法,而是用上面的另外一个分支,重新开始显示即可
- private void startPreview(boolean
updateAll) { - if (mPausing || isFinishing()) return;
- mFocusManager.