Camera3BufferManager::getBufferForStream这个Camera3BufferManager的核心函数是 Client 的 buf 的获取。
加入知识星球与更多Camera同学交流
– 星球名称:深入浅出Android Camera
– 星球ID: 17296815
- 需要理解图1Camera3BufferManager中几个数据结构的深层含义:
- 一个StreamSetMap含有多个StreamSet,根据StreamSetId来区分。
- 一个StreamSet含有一个handoutBufferCountMap,一个attachedBufferCountMap,一个freeBuffers,一个handoutBufferCountMap含有多个count, 以Stream区分, attchedBufferCountMap 同理。
理清楚这些,下面的get buffer 函数就明白了。
- 首先,我们有streamId,根据这个StreamId从StreamSetMap中拿到StreamSet,一个StreamSet含有一个
StreamInfoMap
、一个HandoutCountBufferMap
、一个attachedCountBufferMap
。 - handoutCountBufferMap 记录有几个buffer分配给stream了。AttachedCountBufferMap,记录了stream中含有多少个attached状态的buf。这个所谓的attached buf是client release 的个数和 handout 给 client buffer 的个数之和。
- 我们在一个StreamSet中轮询所有的streamId,叠加其attachedCount得到一个StreamSet的buffer总和,记为count3,如果count3大于MAX WATERMARK,意味着此时需要free掉一些buffer,由于 StreamSet 是一组streamid的count的总和,我们只需要找到一个第三方(另一个streamid)的streamid,其满足其
count2(attached ones)>count1(handout ones)
,这种说明含有client release的buffers。如下公式描述,如果attached个数大于handout的个数,说明有free状态client release的buf。
- 注意区别client release的buf和处于 freeBuffers 中的buffer。 相同点是它们都是free的。
不同点是client release的buf说明client处理完了,但尚在Camera3BufferManager
的管理范围内(也就是说尚在attached buffer count记录内)。而freeBuffers处于StreamSet的,不是某个stream的,而是属于一组stream组成的streamSet的。
- 如果没有超过watermark的情况。直接从freebuffers取出描述目标streamid的buf的一个bufferEntry结构。如果这个bufferEntry描述的graphicBuffer尚未分配到,需要经
createGraphicBuffer
创建一个GraphicBuffer
,而要创建一个buf,就需要buffer的期望尺寸、以及其bpp格式、还有其用途等等。
status_t Camera3BufferManager::getBufferForStream(int streamId, int streamSetId,
sp<GraphicBuffer>* gb, int* fenceFd) {
Mutex::Autolock l(mLock);
StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);//从set中拿到handout ,attached buffer,他们是友元.
BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap;
size_t& attachedBufferCount = attachedBufferCounts.editValueFor(streamId);
if (attachedBufferCount > bufferCount/* handout buffer count*/) {
// 如果buf attached的个数超过了handout出去的个数,说明Stream本身有一些被consumer release的可用buffer,直接在此使用它们就好了.
bufferCount++;
return ALREADY_EXISTS;
}
GraphicBufferEntry buffer =
getFirstBufferFromBufferListLocked(streamSet.freeBuffers, streamId);
if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
// Allocate one if there is no free buffer available.
if (buffer.graphicBuffer == nullptr) {//如果Camera3BufferManager本身没有管理的freebuffer.重新alloc
const StreamInfo& info = streamSet.streamInfoMap.valueFor(streamId);
buffer.fenceFd = -1;
// graphicbuffer的分配,需要尺寸.
buffer.graphicBuffer = mAllocator->createGraphicBuffer(
info.width, info.height, info.format, info.combinedUsage, &res);
}
bufferCount++; // 它们都是友元,此处递增也会同步到对应的Map中,此处是递增handout
attachedBufferCount++;
*gb = buffer.graphicBuffer;
*fenceFd = buffer.fenceFd;// 用于和hal层的同步.拿到fence的那一方才可以对buf读写
// 如果这个StreamSet的free状态的buf大于watermark,说明这StreamSet中有过多空闲的buf,需要回收.
if (streamSet.streamInfoMap.size() > 1) { // 还有多个stream
bool freeBufferIsAttached = false;
for (size_t i = 0; i < streamSet.streamInfoMap.size(); i++) {
firstOtherStreamId = streamSet.streamInfoMap[i].streamId;
if (firstOtherStreamId != streamId) {
// 找到同个streamSet里的其他的stream,看它的attached状态的buf是不是比handout的buffer多.多意味着stream上被attached的buf有一部分是空闲的.
size_t otherBufferCount =
streamSet.handoutBufferCountMap.valueFor(firstOtherStreamId);
size_t otherAttachedBufferCount =
streamSet.attachedBufferCountMap.valueFor(firstOtherStreamId);
if (otherAttachedBufferCount > otherBufferCount) {
freeBufferIsAttached = true; // 找到了,attached比handout的个数多的StreamId,说明有多个空闲的buf.
break; //找到一个Stream就可以了,我们不需要释放太多,找到一个释放一个就能满足目前需求.因为我们本来也是只是申请一个buf的,所以释放一个,再申请一个应该不会差太多.这里先不考虑尺寸等信息.
}
if (hasBufferForStreamLocked(streamSet.freeBuffers, firstOtherStreamId)) {
freeBufferIsAttached = false;
break;
}
}
firstOtherStreamId = CAMERA3_STREAM_ID_INVALID;
}
if (firstOtherStreamId == CAMERA3_STREAM_ID_INVALID) {
return OK;
}
size_t totalAllocatedBufferCount = streamSet.freeBuffers.size();
for (size_t I = 0; I < streamSet.attachedBufferCountMap.size(); i++) {//每个streamSet含有free的buffer以及attached状态的buffer.他们的和是Camera3BufferManage分配给streamSet的所有buffer的个数和
totalAllocatedBufferCount += streamSet.attachedBufferCountMap[i];
}
if (totalAllocatedBufferCount > streamSet.allocatedBufferWaterMark) {//大于watermark就de-alloc一部分.
if (freeBufferIsAttached) {
ALOGV("Stream %d: Freeing buffer: detach", firstOtherStreamId);
sp<Camera3OutputStream> stream =
mStreamMap.valueFor(firstOtherStreamId).promote();//de-alloc的是”其他”的stream的buffer,也因为是他们的attachedbuf超过了handout的buf.
// Detach and then drop the buffer.
{
mLock.unlock();
sp<GraphicBuffer> buffer;
stream->detachBuffer(&buffer, /*fenceFd*/ nullptr);
mLock.lock();
}
size_t& otherAttachedBufferCount =
streamSet.attachedBufferCountMap.editValueFor(firstOtherStreamId);
otherAttachedBufferCount--;
} else {
// Droppable buffer is in the free buffer list, grab and drop
getFirstBufferFromBufferListLocked(streamSet.freeBuffers, firstOtherStreamId);
}
}
}
} else {
// TODO: implement this.
return BAD_VALUE;
}
return OK;
}
getFreeBufferForStream的用法
下面的代码会逐渐解释mConsumer
对象的attached buffer的逻辑实现。
status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
if ((res = getBufferPreconditionCheckLocked()) != OK) {
return res;
}
ANativeWindowBuffer* anb;
int fenceFd = -1;
bool gotBufferFromManager = false;
if (mUseBufferManager) {
sp<GraphicBuffer> gb;
// 使用Camera3BufferManager管理buffer.并从中拿到GraphicBuffer.这里作为gb.
res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, &fenceFd);
if (res == OK) {
// 把gb转成ANativeWindowBuffer.并添加到consumer的activeBuffer中.
anb = gb.get();
res = mConsumer->attachBuffer(anb);
gotBufferFromManager = true; // 表明从Camera3BufferManager获得来的buf
} else if (res == ALREADY_EXISTS) {
// 如果这个buf是本身stream release下的,此时并没有重新create buf.说明这个buf不是由Camera3BufferManager管理的.
gotBufferFromManager = false;
} else if (res != OK) {
return res;// error
}
}
if (!gotBufferFromManager) {
/**
* 我们先unlock锁,因为会有如下的死锁场景:
* Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
* 线程1 会请求StreamingProcessor lock 并且锁住Camera3Stream lock.
*
* Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
* 线程2 会请求 Camera3Stream lock 和bufferQueue lock, 并锁住
* StreamingProcessor lock.
*
* Thread 3: Camera3Stream::getBuffer().
* 线程3 会请求Camera3Stream lock并锁住bufferQueue lock.
* 此时会有一个循环锁依赖.
*/
sp<ANativeWindow> currentConsumer = mConsumer;
mLock.unlock();
// 使用consumer自己的空闲buffer
res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
mLock.lock();
return res;
}
}
handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
/*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
return OK;
}