前面介绍了Normal属性显示层中的第一类Layer,这里将介绍其中的第二类LayerBuffer。LayerBuffer会在视频播放和摄像机预览等场景中用到,就以Camera的preView(预览)为例,来分析LayerBuffer的工作原理。
1. LayerBuffer的创建
先看LayerBuffer的创建,它通过SF的createPushBuffersSurfaceLocked得到,代码如下所示:
**SurfaceFlinger.cpp**
~~~
sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked(
const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
sp<LayerBuffer> layer = new LayerBuffer(this, display, client,id);
layer->initStates(w, h, flags);
addLayer_l(layer);
returnlayer;
}
~~~
LayerBuffer的派生关系,如图8-30所示:
:-: ![](http://img.blog.csdn.net/20150802163344531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图8-30 LayerBuffer的派生关系示意图
从上图中可以发现:
- LayerBuffer定义了一个内部类Source类,它有两个派生类BufferSource和OverlaySource。根据它们的名字,可以猜测到Source代表数据的提供者。
* LayerBuffer中的mSurface其真实类型是SurfaceLayerBuffer。
LayerBuffer创建好了,不过该怎么用呢?和它相关的调用流程是怎样的呢?下面来分析Camera。
2. Camera preView的分析
Camera是一个单独的Service,全称是CameraService,先看CameraService的registerPreviewBuffers函数。这个函数会做什么呢?代码如下所示:
**CameraService.cpp**
~~~
status_tCameraService::Client::registerPreviewBuffers()
{
int w, h;
CameraParameters params(mHardware->getParameters());
params.getPreviewSize(&w, &h);
/*
①mHardware代表Camera设备的HAL对象。本书讨论CameraHardwareStub设备,它其实是
一个虚拟的设备,不过其代码却具有参考价值。
BufferHeap定义为ISurface的内部类,其实就是对IMemoryHeap的封装
*/
ISurface::BufferHeapbuffers(w, h, w, h,
HAL_PIXEL_FORMAT_YCrCb_420_SP,
mOrientation,
0,
mHardware->getPreviewHeap());
//②调用SurfaceLayerBuffer的registerBuffers函数。
status_t ret = mSurface->registerBuffers(buffers);
returnret;
}
~~~
上面代码中列出了两个关键点,逐一来分析它们。
(1)创建BufferHeap
BufferHeap是ISurface定义的一个内部类,它的声明如下所示:
**ISurface.h**
~~~
classBufferHeap {
public:
......
//使用这个构造函数
BufferHeap(uint32_t w, uint32_t h,
int32_t hor_stride, int32_t ver_stride,
PixelFormat format, const sp<IMemoryHeap>& heap);
......
~BufferHeap();
uint32_t w;
uint32_t h;
int32_t hor_stride;
int32_t ver_stride;
PixelFormat format;
uint32_t transform;
uint32_t flags;
sp<IMemoryHeap> heap; //heap指向真实的存储对象
};
~~~
从上面代码中可发现,BufferHeap基本上就是封装了一个IMemoryHeap对象,根据我们对IMemoryHeap的了解,它应该包含了真实的存储对象,这个值由CameraHardwareStub对象的getPreviewHeap得到,这个函数的代码如下所示:
**CameraHardwareStub.cpp**
~~~
sp<IMemoryHeap>CameraHardwareStub::getPreviewHeap() const
{
returnmPreviewHeap;//返回一个成员变量,它又是在哪创建的呢?
}
//上面的mPreivewHeap对象由initHeapLocked函数创建,该函数在HAL对象创建的时候被调用
void CameraHardwareStub::initHeapLocked()
{
......
/*
创建一个MemoryHeapBase对象,大小是mPreviewFrameSize * kBufferCount,其中
kBufferCount为4。注意这是一段连续的缓冲。
*/
mPreviewHeap= new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
//mBuffer为MemoryBase数组,元素为4
for (inti = 0; i < kBufferCount; i++) {
mBuffers[i] = new MemoryBase(mPreviewHeap,
i * mPreviewFrameSize, mPreviewFrameSize);
}
}
~~~
从上面这段代码中可以发现,CameraHardwareStub对象创建的用于preView的内存结构是按图8-31所示的方式来组织的:
:-: ![](http://img.blog.csdn.net/20150802163254109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图8-31 CameraHardwareStub用于preView的内存结构图
其中:
- BufferHeap的heap变量指向一块MemoryHeap,这就是mPreviewHeap。
- 在这块MemoryHeap上构建了4个MemoryBase。
(2)registerBuffers的分析
BufferHeap准备好后,要调用ISurface的registerBuffers函数,ISurface在SF端的真实类型是SurfaceLayerBuffer,所以要直接看它的实现,代码如下所示:
**LayerBuffer.cpp**
~~~
status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
const ISurface::BufferHeap& buffers)
{
sp<LayerBuffer> owner(getOwner());
if (owner != 0)
//调用外部类对象的registerBuffers,所以SurfaceLayerBuffer也是一个Proxy哦。
return owner->registerBuffers(buffers);
returnNO_INIT;
}
//外部类是LayerBuffer,调用它的registerBuffers函数
status_t LayerBuffer::registerBuffers(constISurface::BufferHeap& buffers)
{
Mutex::Autolock _l(mLock);
//创建数据的来源BufferSource,注意我们其实把MemoryHeap设置上去了
sp<BufferSource> source = new BufferSource(*this, buffers);
status_t result = source->getStatus();
if(result == NO_ERROR) {
mSource = source;//保存这个数据源为mSource。
}
returnresult;
}
~~~
BufferSource,曾在图8-30中见识过,它内部有一个成员变量mBufferHeap指向传入的buffers参数,所以registerBuffers过后,就得到了图8-32:
:-: ![](http://img.blog.csdn.net/20150802163322407?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图8-32 registerBuffers的结果示意图
请注意上图的箭头指向,不论中间有多少层封装,最终的数据存储区域还是mPreivewHeap。
2.数据的传输
至此,Buffer在SF和Camera两端都准备好了,那么数据是怎么从Camera传递到SF的呢?先来看数据源是怎么做的。
(1)数据传输的分析
CameraHardwareStub有一个preview线程,这个线程会做什么呢?代码如下所示:
**CameraHardwareStub.cpp**
~~~
//preview线程从Thread类派生,下面这个函数在threadLoop中循环调用
int CameraHardwareStub::previewThread()
{
mLock.lock();
//每次进来mCurrentPreviewFrame都会加1
ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
sp<MemoryHeapBase> heap = mPreviewHeap;
FakeCamera* fakeCamera = mFakeCamera;//虚拟的摄像机设备
//从mBuffers中取一块内存,用于接收来自硬件的数据
sp<MemoryBase>buffer = mBuffers[mCurrentPreviewFrame];
mLock.unlock();
if(buffer != 0) {
intdelay = (int)(1000000.0f / float(previewFrameRate));
void *base = heap->base();//base是mPreviewHeap的起始位置
//下面这个frame代表buffer在mPreviewHeap中的起始位置,还记得图8-31吗?
//四块MemoryBase的起始位置由下面这个代码计算得来
uint8_t *frame = ((uint8_t *)base) + offset;
//取出一帧数据,放到对应的MemoryBase中
fakeCamera->getNextFrameAsYuv422(frame);
//①把含有帧数据的buffer传递到上层
if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
//mCurrentPreviewFrame 递增,在0到3之间循环
mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
usleep(delay);//模拟真实硬件的延时
}
returnNO_ERROR;
}
~~~
读者是否明白Camera preview的工作原理了?就是从四块内存中取一块出来接收数据,然后再把这块内存传递到上层去处理。从缓冲使用的角度来看,mBuffers数组构成了一个成员个数为四的缓冲队列。preview通过mData这个回调函数,把数据传递到上层,而CameraService实现了mData这个回调函数,这个回调函数最终会调用handlePreviewData,直接看handlePreviewData即可,代码如下所示:
**CameraService.cpp**
~~~
voidCameraService::Client::handlePreviewData(const sp<IMemory>& mem)
{
ssize_t offset;
size_t size;
//注意传入的mem参数,它实际上是Camera HAL创建的mBuffers数组中的一个
//offset返回的是这个数组在mPreviewHeap中的偏移量
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
if (!mUseOverlay)
{
Mutex::Autolock surfaceLock(mSurfaceLock);
if(mSurface != NULL) {
//调用ISurface的postBuffer,注意我们传入的参数是offset。
mSurface->postBuffer(offset);
}
}
......
}
~~~
上面的代码是什么意思?我们到底给ISurface传什么了?答案很明显:
- handlePreviewData就是传递了一个偏移量,这个偏移量是mBuffers数组成员的首地址。可用图8-33来表示:
:-: ![](http://img.blog.csdn.net/20150802163453733?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图8-33 handlePreviewData示意图
有了图8-33,读者明白数据传递的工作原理了吗?
下面看SurfaceLayerBuffer的postBuffer函数,不过它只是一个小小的代理,真正的工作由外部类LayerBuffer完成,直接看它好了,代码如下所示:
**LayerBuffer.cpp**
~~~
void LayerBuffer::postBuffer(ssize_t offset)
{
sp<Source> source(getSource());//getSource返回mSource,为BufferSource类型
if(source != 0)
source->postBuffer(offset);//调用BufferSource的postBuffer函数。
}
~~~
**LayerBuffer.cpp**
~~~
voidLayerBuffer::BufferSource::postBuffer(ssize_t offset)
{
ISurface::BufferHeap buffers;
{
Mutex::Autolock _l(mBufferSourceLock);
buffers = mBufferHeap;//还记得图8-32吗?
if(buffers.heap != 0) {
//BufferHeap的heap变量指向MemoryHeap,下面取出它的大小
const size_t memorySize = buffers.heap->getSize();
//做一下检查,判断这个offset是不是有问题
if ((size_t(offset) + mBufferSize) > memorySize) {
LOGE("LayerBuffer::BufferSource::postBuffer() "
"invalid buffer(offset=%d, size=%d, heap-size=%d",
int(offset),int(mBufferSize), int(memorySize));
return;
}
}
}
sp<Buffer> buffer;
if (buffers.heap != 0) {
//创建一个LayerBuffer::Buffer
buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize);
if(buffer->getStatus() != NO_ERROR)
buffer.clear();
setBuffer(buffer);//setBuffer?我们要看看
//mLayer就是外部类LayerBuffer,调用它的invalidate函数将触发SF的重绘
mLayer.invalidate();
}
}
void LayerBuffer::BufferSource::setBuffer(
const sp<LayerBuffer::Buffer>& buffer)
{
//setBuffer函数就是简单地将new出来的Buffer设置给成员变量mBuffer,这么做会有问题吗?Mutex::Autolock_l(mBufferSourceLock);
mBuffer = buffer; //将新的buffer设置为mBuffer,mBuffer原来指向的那个被delete
}
~~~
从数据生产者角度看,postBuffer函数将不断地new一个Buffer出来,然后将它赋值给成员变量mBuffer,也就是说,mBuffer会不断变化。现在从缓冲的角度来思考一下这种情况的结果:
- 数据生产者有一个含四个成员的缓冲队列,也就是mBuffers数组。
- 而数据消费者只有一个mBuffer。
这种情况会有什么后果呢?请记住这个问题,我们到最后再来揭示。下面先看mBuffer的类型Buffer是什么。
(2)数据使用的分析
Buffer被定义成LayerBuffer的内部类,代码如下所示:
**LayerBuffer.cpp**
~~~
LayerBuffer::Buffer::Buffer(constISurface::BufferHeap& buffers,
ssize_t offset, size_t bufferSize)
:mBufferHeap(buffers), mSupportsCopybit(false)
{
//注意,这个src被定义为引用,所以修改src的信息相当于修改mNativeBuffer的信息
NativeBuffer& src(mNativeBuffer);
src.crop.l = 0;
src.crop.t = 0;
src.crop.r = buffers.w;
src.crop.b = buffers.h;
src.img.w =buffers.hor_stride ?: buffers.w;
src.img.h =buffers.ver_stride ?: buffers.h;
src.img.format = buffers.format;
//这个base将指向对应的内存起始地址
src.img.base =(void*)(intptr_t(buffers.heap->base()) + offset);
src.img.handle = 0;
gralloc_module_tconst * module = LayerBuffer::getGrallocModule();
//做一些处理,有兴趣的读者可以去看看。
if(module && module->perform) {
int err = module->perform(module,
GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
buffers.heap->heapID(), bufferSize,
offset, buffers.heap->base(),
&src.img.handle);
mSupportsCopybit = (err == NO_ERROR);
}
}
~~~
上面是Buffer的定义,其中最重要的就是这个mNativeBuffer了,它实际上保存了mBuffers数组成员的首地址。
下面看绘图函数,也就是LayerBuffer的onDraw函数,这个函数由SF的工作线程调用,代码如下所示:
**LayerBuffer.cpp**
~~~
void LayerBuffer::onDraw(const Region& clip)const
{
sp<Source> source(getSource());
if(LIKELY(source != 0)) {
source->onDraw(clip);//source实际类型是BufferSource,我们去看看。
} else{
clearWithOpenGL(clip);
}
}
void LayerBuffer::BufferSource::onDraw(constRegion& clip) const
{
sp<Buffer> ourBuffer(getBuffer());
......//使用这个Buffer,注意使用的时候没有锁控制
mLayer.drawWithOpenGL(clip, mTexture);//生成一个贴图,然后绘制它
}
~~~
其中getBuffer函数返回mBuffer,代码如下所示:
~~~
sp<LayerBuffer::Buffer>LayerBuffer::BufferSource::getBuffer() const
{
Mutex::Autolock_l(mBufferSourceLock);
returnmBuffer;
}
~~~
从上面的代码中能发现,mBuffer的使用并没有锁的控制,这会导致什么问题发生呢?请再次回到前面曾强调要记住的那个问题。此时生产者的队列有四个元素,而消费者的队列只有一个元素,它可用图8-34来表示:
:-: ![](http://img.blog.csdn.net/20150802163511080?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图8-34 数据传递的问题示意图
从上图可以知道:
- 使用者使用mBuffer,这是在SF的工作线程中做到的。假设mBuffer实际指向的内存为mBuffers[0]。
- 数据生产者循环更新mBuffers数组各个成员的数据内容,这是在另外一个线程中完成的。由于这两个线程之间没有锁同步,这就造成了当使用者还在使用mBuffers[0]时,生产者又更新了mBuffers[0]。这会在屏幕上产生混杂的图像。
经过实际测试得知,如果给数据使用端加上一定延时,屏幕就会出现不连续的画面,即前一帧和后一帧的数据混杂在一起输出。
从代码的分析来看,这种方式确实有问题。我在真实设备上测试的结果,也在一定程度上验证了这一点。通过修改LayerBuffer来解决这问题的难度比较大,是否可在读写具体缓存时加上同步控制呢(例如使用mBuffers[0]的时候调用一下lock,用完后调用unlock)?这样就不用修改LayerBuffer了。读者可再深入研究这个问题。
- 前言
- 第1章 阅读前的准备工作
- 1.1 系统架构
- 1.1.1 Android系统架构
- 1.1.2 本书的架构
- 1.2 搭建开发环境
- 1.2.1 下载源码
- 1.2.2 编译源码
- 1.3 工具介绍
- 1.3.1 Source Insight介绍
- 1.3.2 Busybox的使用
- 1.4 本章小结
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 学习JNI的实例:MediaScanner
- 2.3 Java层的MediaScanner分析
- 2.3.1 加载JNI库
- 2.3.2 Java的native函数和总结
- 2.4 JNI层MediaScanner的分析
- 2.4.1 注册JNI函数
- 2.4.2 数据类型转换
- 2.4.3 JNIEnv介绍
- 2.4.4 通过JNIEnv操作jobject
- 2.4.5 jstring介绍
- 2.4.6 JNI类型签名介绍
- 2.4.7 垃圾回收
- 2.4.8 JNI中的异常处理
- 2.5 本章小结
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 属性服务
- 3.3 本章小结
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 关于zygote的总结
- 4.3 SystemServer分析
- 4.3.1 SystemServer的诞生
- 4.3.2 SystemServer的重要使命
- 4.3.3 关于 SystemServer的总结
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService发送请求
- 4.4.2 有求必应之响应请求
- 4.4.3 关于zygote分裂的总结
- 4.5 拓展思考
- 4.5.1 虚拟机heapsize的限制
- 4.5.2 开机速度优化
- 4.5.3 Watchdog分析
- 4.6 本章小结
- 第5章 深入理解常见类
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初识影子对象
- 5.2.2 第二板斧--由弱生强
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 轻量级的引用计数控制类LightRefBase
- 5.2.5 题外话-三板斧的来历
- 5.3 Thread类及常用同步类分析
- 5.3.1 一个变量引发的思考
- 5.3.2 常用同步类
- 5.4 Looper和Handler类分析
- 5.4.1 Looper类分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步关系
- 5.4.4 HandlerThread介绍
- 5.5 本章小结
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函数
- 6.2.2 独一无二的ProcessState
- 6.2.3 时空穿越魔术-defaultServiceManager
- 6.2.4 注册MediaPlayerService
- 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析
- 6.2.6 你彻底明白了吗
- 6.3 服务总管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服务的注册
- 6.3.3 ServiceManager存在的意义
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查询ServiceManager
- 6.4.2 子承父业
- 6.5 拓展思考
- 6.5.1 Binder和线程的关系
- 6.5.2 有人情味的讣告
- 6.5.3 匿名Service
- 6.6 学以致用
- 6.6.1 纯Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小结
- 第7章 深入理解Audio系统
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介绍
- 7.2.2 AudioTrack(Java空间)分析
- 7.2.3 AudioTrack(Native空间)分析
- 7.2.4 关于AudioTrack的总结
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的诞生
- 7.3.2 通过流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 关于AudioFlinger的总结
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的创建
- 7.4.2 重回AudioTrack
- 7.4.3 声音路由切换实例分析
- 7.4.4 关于AudioPolicy的总结
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 题外话
- 7.6 本章小结
- 第8章 深入理解Surface系统
- 8.1 概述
- 8.2 一个Activity的显示
- 8.2.1 Activity的创建
- 8.2.2 Activity的UI绘制
- 8.2.3 关于Activity的总结
- 8.3 初识Surface
- 8.3.1 和Surface有关的流程总结
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI层分析
- 8.3.4 Surface和画图
- 8.3.5 初识Surface小结
- 8.4 深入分析Surface
- 8.4.1 与Surface相关的基础知识介绍
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface对象的创建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介绍
- 8.4.7 深入分析Surface的总结
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的诞生
- 8.5.2 SF工作线程分析
- 8.5.3 Transaction分析
- 8.5.4 关于SurfaceFlinger的总结
- 8.6 拓展思考
- 8.6.1 Surface系统的CB对象分析
- 8.6.2 ViewRoot的你问我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小结
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理与机制分析
- 9.2.1 Netlink和Uevent介绍
- 9.2.2 初识Vold
- 9.2.3 NetlinkManager模块分析
- 9.2.4 VolumeManager模块分析
- 9.2.5 CommandListener模块分析
- 9.2.6 Vold实例分析
- 9.2.7 关于Vold的总结
- 9.3 Rild的原理与机制分析
- 9.3.1 初识Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 关于Rild main函数的总结
- 9.3.6 Rild实例分析
- 9.3.7 关于Rild的总结
- 9.4 拓展思考
- 9.4.1 嵌入式系统的存储知识介绍
- 9.4.2 Rild和Phone的改进探讨
- 9.5 本章小结
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模块分析
- 10.2.2 MSS模块分析
- 10.2.3 android.process.media媒体扫描工作的流程总结
- 10.3 MediaScanner分析
- 10.3.1 Java层分析
- 10.3.2 JNI层分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 关于MediaScanner的总结
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介绍
- 10.4.2 我问你答
- 10.5 本章小结