8.6.3 LayerBuffer分析
最后更新于:2022-04-02 05:53:01
前面介绍了Normal属性显示层中的第一类Layer,这里将介绍其中的第二类LayerBuffer。LayerBuffer会在视频播放和摄像机预览等场景中用到,就以Camera的preView(预览)为例,来分析LayerBuffer的工作原理。
1. LayerBuffer的创建
先看LayerBuffer的创建,它通过SF的createPushBuffersSurfaceLocked得到,代码如下所示:
**SurfaceFlinger.cpp**
~~~
sp SurfaceFlinger::createPushBuffersSurfaceLocked(
const sp& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
sp 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& 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 heap; //heap指向真实的存储对象
};
~~~
从上面代码中可发现,BufferHeap基本上就是封装了一个IMemoryHeap对象,根据我们对IMemoryHeap的了解,它应该包含了真实的存储对象,这个值由CameraHardwareStub对象的getPreviewHeap得到,这个函数的代码如下所示:
**CameraHardwareStub.cpp**
~~~
spCameraHardwareStub::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 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 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 heap = mPreviewHeap;
FakeCamera* fakeCamera = mFakeCamera;//虚拟的摄像机设备
//从mBuffers中取一块内存,用于接收来自硬件的数据
spbuffer = 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& mem)
{
ssize_t offset;
size_t size;
//注意传入的mem参数,它实际上是Camera HAL创建的mBuffers数组中的一个
//offset返回的是这个数组在mPreviewHeap中的偏移量
sp 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
';