Android CCodec Codec2 (十三)CCodecBufferChannel - Ⅰ

CCodecBufferChannel是整个Codec2框架最复杂的部分,涉及到input buffer分配,input/output buffer的处理,内部封装了一些全新的机制,比如reorder、pipeline control等。本篇内容主要对CCodecBufferChannel的start流程进行了解,涉及到的C2BlockPool、C2Allocator、InputBuffers、OutputBuffers本篇不做展开。

1、CCodecBufferChannel

先来看CCodecBufferChannel的构造函数:

CCodecBufferChannel::CCodecBufferChannel(
        const std::shared_ptr<CCodecCallback> &callback)
    : mHeapSeqNum(-1),
      mCCodecCallback(callback),
      mFrameIndex(0u),
      mFirstValidFrameIndex(0u),
      mAreRenderMetricsEnabled(areRenderMetricsEnabled()),
      mIsSurfaceToDisplay(false),
      mHasPresentFenceTimes(false),
      mRenderingDepth(3u),
      mMetaMode(MODE_NONE),
      mInputMetEos(false),
      mSendEncryptedInfoBuffer(false) {
    {
        Mutexed<Input>::Locked input(mInput);
        input->buffers.reset(new DummyInputBuffers(""));
        input->extraBuffers.flush();
        input->inputDelay = 0u;
        input->pipelineDelay = 0u;
        input->numSlots = kSmoothnessFactor;
        input->numExtraSlots = 0u;
        input->lastFlushIndex = 0u;
    }
    {
        Mutexed<Output>::Locked output(mOutput);
        output->outputDelay = 0u;
        output->numSlots = kSmoothnessFactor;
        output->bounded = false;
    }
    {
        Mutexed<BlockPools>::Locked pools(mBlockPools);
        pools->outputPoolId = C2BlockPool::BASIC_LINEAR;
    }
    std::string value = GetServerConfigurableFlag("media_native", "ccodec_rendering_depth", "3");
    android::base::ParseInt(value, &mRenderingDepth);
    mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + mRenderingDepth;
}

构造函数初始化了一些成员变量,以下是部分成员的意义:

  • mFrameIndex:写入到组件的数据的序号;
  • mRenderingDepth:我的理解是surface持有的已填冲数据的output buffer的数量,默认值为3;
  • mMetaMode:记录编码数据的类型是否为ANW Meta data;

CCodecBufferChannel使用Input来存储所有与输入buffer相关的信息:

struct Input {
    Input();
    std::unique_ptr<InputBuffers> buffers;
    size_t numSlots;
    FlexBuffersImpl extraBuffers;
    size_t numExtraSlots;
    uint32_t inputDelay;
    uint32_t pipelineDelay;
    c2_cntr64_t lastFlushIndex;
    FrameReassembler frameReassembler;
};

Input的成员字段含义如下:

  • buffers:使用InputBuffers存储所有分配的输入buffer;
  • numSlots:input buffer的数量;
  • extraBuffers:从变量名来看是额外的buffer,在启动过程分配的buffer都存在buffers中,其他情况下需要再分配buffer时,分配的buffer会存到extraBuffers;
  • numExtraSlots:额外buffer的数量;
  • inputDelay:延迟输入的buffer数量;
  • pipelineDelay:组件持有的buffer数量;
  • lastFlushIndex:上次执行flush时的输入索引;
  • frameReassembler:帧重组,用于audio encoder;

CCodecBufferChannel使用Output来存储所有与输出buffer相关的信息:

struct Output {
    std::unique_ptr<OutputBuffers> buffers;
    size_t numSlots;
    uint32_t outputDelay;
    bool bounded;
};

Output的成员字段含义如下:

  • buffers:使用OutputBuffers存储所有分配的输出buffer;
  • numSlots:output buffer的数量;
  • outputDelay:输出buffer的延迟;
  • bounded:输出是否和Native Window绑定;

CCodecBufferChannel使用BlockPools来记录与input/output buffer分配的信息:

struct BlockPools {
    C2Allocator::id_t inputAllocatorId;
    std::shared_ptr<C2BlockPool> inputPool;
    C2Allocator::id_t outputAllocatorId;
    C2BlockPool::local_id_t outputPoolId;
    std::shared_ptr<Codec2Client::Configurable> outputPoolIntf;
};

BlockPools的成员字段含义如下:

  • inputAllocatorId:分配输入buffer的Allocator id;
  • inputPool:管理输入buffer的blockpool;
  • outputAllocatorId:分配输出buffer的Allocator id;
  • outputPoolId:分配输出buffer的blockpool id;
  • outputPoolIntf:output blockpool的配置接口;

mInput、mOutput和mBlockPools都是受锁保护的,它们会在CCodec和MediaCodec线程中被用到。

void CCodecBufferChannel::setComponent(
        const std::shared_ptr<Codec2Client::Component> &component) {
    mComponent = component;
    mComponentName = component->getName() + StringPrintf("#%d", int(uintptr_t(component.get()) % 997));
    mName = mComponentName.c_str();
}

组件创建后会调用setComponent方法将组件设定给CCodecBufferChannel,因此CCodecBufferChannel是可以独立操作组件的。CCodecBufferChannel的mComponentName是以组件名+一个随机数字组成的,方便我们在多实例的情况下debug。

D CCodecBufferChannel: [start 1233] [c2.xxx.video.avc.decoder#740] inputDelayValue = 6

和OMX框架相同,Codec2框架也是在start之后才会分配buffer。既然要分配buffer,就会有几个问题:

  • 分配什么类型的buffer?
  • 用什么分配buffer?
  • 分配几个buffer,buffer大小是多少?

想要搞清楚这些问题就要仔细阅读CCodecBufferChannel的start方法,方法比较长,我们分段解析。

2、buffer count calculate

status_t start(
        const sp<AMessage> &inputFormat,
        const sp<AMessage> &outputFormat,
        bool buffersBoundToCodec);

start需要传入三个参数,分别为输入格式、输出格式以及buffer是否要和Codec绑定,buffersBoundToCodec默认为true(与Codec相绑定)。

C2StreamBufferTypeSetting::input iStreamFormat(0u);
C2StreamBufferTypeSetting::output oStreamFormat(0u);
C2ComponentKindSetting kind;
C2PortReorderBufferDepthTuning::output reorderDepth;
C2PortReorderKeySetting::output reorderKey;
C2PortActualDelayTuning::input inputDelay(0);
C2PortActualDelayTuning::output outputDelay(0);
C2ActualPipelineDelayTuning pipelineDelay(0);
C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);

c2_status_t err = mComponent->query(
        {
            &iStreamFormat,
            &oStreamFormat,
            &kind,
            &reorderDepth,
            &reorderKey,
            &inputDelay,
            &pipelineDelay,
            &outputDelay,
            &secureMode,
        },
        {},
        C2_DONT_BLOCK,
        nullptr);

进入函数体首先会向组件请求一组参数,iStreamFormat和oStreamFormat存储的是输入输出buffer的类型,用枚举表示:

class C2BufferData {
public:
    enum type_t : uint32_t {
        INVALID,            ///< invalid buffer type. Do not use.
        LINEAR,             ///< the buffer contains a single linear block
        LINEAR_CHUNKS,      ///< the buffer contains one or more linear blocks
        GRAPHIC,            ///< the buffer contains a single graphic block
        GRAPHIC_CHUNKS,     ///< the buffer contains one of more graphic blocks
    };
} 

Codec2框架将数据划分为两个类型:LINEAR(1D)和GRAPHIC(2D)。一维数据被看作是线性的,1D数据包括压缩的音频和视频数据,以及解码后的音频数据;二维数据指的是图像数据,包含解码后的视频数据和需要编码的图像数据。

3、C2AllocatorStore

关注公众号《青山渺渺》订阅合集阅读完整内容

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值