Camera3BufferManager 内部含有一组 Map,它们的关系如下:
StreamSetMap是一组StreamSet合集,StreamSet下含有一组 Map、streamInfoMap、handoutBufferCountMap 以及 attachedBufferCountMap。
加入知识星球与更多Camera同学交流
– 星球名称:深入浅出Android Camera
– 星球ID: 17296815
- 第一,handout buffer Map是给client使用的buffer的集合。
- 第二,freeBuffers 是属于特定某个buffer set的所有buffer的合集,由returnBufferForStream返回,待使用的buffer。
- 第三,attached buffer可以是handout的,也可以是free的,它实际上是这两种的合集。
registerStream就是为这个streamInfo建立一组StreamSet。
- StreamSet内部的Map也建立起来,并初始化为(key=streamId,val=0)。
- 最后把StreamSet以key是streamSetId加到mStreamSetMap中。
- 把stream以key为streamId加到mStreamMap中。
下面这段代码描述了这个逻辑:
status_t Camera3BufferManager::registerStream(wp<Camera3OutputStream>& stream,
const StreamInfo& streamInfo) {
ATRACE_CALL();
int streamId = streamInfo.streamId;
int streamSetId = streamInfo.streamSetId;
/* 分别拿到sTream的id以及setId.一个set含有三个Map,描述streamid的streamInfoMap,给stream的buf个数handoutBufferCountMap,stream attached的attachedBufferCountMap.*/
Mutex::Autolock l(mLock);// 这是个利用构造析构的mutex锁.包了pthread_mutext.
// 先尝试,一组StreamSetMap的StreamMap中找是否有streamid的stream.一个streamSetMap含有多个StreamSet.一个StreamSet含有多个Stream.
for (size_t i = 0; i < mStreamSetMap.size(); i++) {
ssize_t streamIdx = mStreamSetMap[i].streamInfoMap.indexOfKey(streamId);
}
// 根据StreamSetId在streamSetMap中找是否已经注册过了.如果找不到,我们需要new出一个StreamSet.
// 并把这个新的StreamSet和StreamSetId关联到mStreamSetMap中.
ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId);
if (setIdx == NAME_NOT_FOUND) {/*没找到,怎么办?new出一个*/
StreamSet newStreamSet;
setIdx = mStreamSetMap.add(streamSetId, newStreamSet);
}
// 拿到刚才新的StreamSet,并取出其streamid.这里需要对StreamSet的handout ,attached的Map清零.
StreamSet& currentStreamSet = mStreamSetMap.editValueAt(setIdx);//currentStreamSet是个友元
ssize_t streamIdx = currentStreamSet.streamInfoMap.indexOfKey(streamId);
currentStreamSet.streamInfoMap.add(streamId, streamInfo);
currentStreamSet.handoutBufferCountMap.add(streamId, 0);
currentStreamSet.attachedBufferCountMap.add(streamId, 0);
mStreamMap.add(streamId, stream);
return OK;
}
registerStream 的调用时机是什么?
根据 buf 的尺寸以及 buf 有何用途,针对性的生成一个 StreamInfo 结构,此时会利用 registerStream 注册进 mStreamSetMap 中。
下面这段代码体现了 registerStream 是如何使用的。
status_t Camera3OutputStream::configureQueueLocked() {// 虽然没有传参,但是内部基本上是调用成员变量的函数
// 配置consumer侧的 ANativeWidow接口.consumer一般是Surface类.此时还要把一个listener注册进consumer.以便consumer在release时候可以及时通知Camera3BufferManager做一些release的buf管理.
res = mConsumer->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/mBufferReleasedListener);
if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID) {
uint32_t consumerUsage = 0;
getEndpointUsage(&consumerUsage);
// 先生成描述这个stream的streaminfo
// stream info依赖,这个stream描述的buf的宽,高,格式(yuv与否),数据空间.以及这块buf的用途.android系统把待显示的区域用不同的属性描述.
StreamInfo streamInfo(getId(), getStreamSetId(), getWidth(), getHeight(), getFormat(), getDataSpace(),camera3_stream::usage | consumerUsage, mTotalBufferCount, /*isConfigured*/true);
wp<Camera3OutputStream> weakThis(this);
// 把streaminfo注册进去,这里的this就是Camera3OutputStream类本身.
res = mBufferManager->registerStream(weakThis,
streamInfo);
if (res == OK) {
//此时先进值GraphicBuffer的产生.因为对于创建多大的GraphicBuffer是由Camera3BufferManager负责的.
mConsumer->getIGraphicBufferProducer()->allowAllocation(false);
mUseBufferManager = true;
}
}
}