Camera3BufferManager getBufferForStream

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。

Camera3BufferManager

  • 注意区别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格式、还有其用途等等。

Camera3BufferManager's StreamSet summary

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;
}

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程