OH-v3.0-LTS Camera相机驱动框架(L2)解析4_创建流 原创 精华

NL_AIDC_Ryanzx
发布于 2022-2-7 16:27
浏览
2收藏

OpenHarmory-v3.0-LTS Camera相机驱动框架(L2)解析4_创建流

接着上章的代码继续往下看,将创建好的StreamInfo作为参数丢给StreamOperator进行流的创建

程序调用流程图

OH-v3.0-LTS Camera相机驱动框架(L2)解析4_创建流-鸿蒙开发者社区

1. StreamOperator::CreateStreams()

创建过程

  • 实例化一个stream对象,用stremInfos中的参数信息对相关成员进行赋值。
  • 创建一个StreamTunnel对象,把StreamTunnel和stream进行绑定。
  • 把创建好的每一个stream 对应它的stremId 放在 streamMap_里。
//drivers\peripheral\camera\hal\hdi_impl\src\stream_operator\stream_operator.cpp
CamRetCode StreamOperator::CreateStreams(const std::vector<std::shared_ptr<StreamInfo>>& streamInfos)
{
    ...
    for (auto it : streamInfos) {
        ...
        
        std::shared_ptr<IStream> stream = StreamFactory::Instance().CreateShared(
            IStream::g_avaliableStreamType[it->intent_], it->streamId_, it->intent_, pipelineCore_, messenger_);

        ...
        
        StreamConfiguration scg;
        scg.id = it->streamId_;
        scg.type = it->intent_;
        scg.width = it->width_;
        scg.height = it->height_;
        PixelFormat pf = static_cast<PixelFormat>(it->format_);
        scg.format = BufferAdapter::PixelFormatToCameraFormat(pf);
        scg.dataspace = it->datasapce_; // fix misspell
        scg.tunnelMode = it->tunneledMode_;
        scg.minFrameDuration = it->minFrameDuration_;
        scg.encodeType = it->encodeType_;

        RetCode rc = stream->ConfigStream(scg);
        
        ...
        
        if (it->bufferQueue_ != nullptr) {
            auto tunnel = std::make_shared<StreamTunnel>();
            CHECK_IF_PTR_NULL_RETURN_VALUE(tunnel, INSUFFICIENT_RESOURCES);
            RetCode rc = tunnel->AttachBufferQueue(it->bufferQueue_);
            CHECK_IF_NOT_EQUAL_RETURN_VALUE(rc, RC_OK, INVALID_ARGUMENT);
            if (stream->AttachStreamTunnel(tunnel) != RC_OK) {
                CAMERA_LOGE("attach buffer queue to stream [id = %{public}d] failed", it->streamId_);
                return INVALID_ARGUMENT;
            }
        }
        {
            std::lock_guard<std::mutex> l(streamLock_);
            streamMap_[stream->GetStreamId()] = stream;
        }
    }
    return NO_ERROR;
}

这里需要注意的一个地方RetCode rc = tunnel->AttachBufferQueue(it->bufferQueue_);单独把这个代码帖出来看下

//drivers\peripheral\camera\hal\hdi_impl\src\stream_operator\stream_tunnel.cpp
RetCode StreamTunnel::AttachBufferQueue(OHOS::sptr<OHOS::IBufferProducer>& producer)
{
    CHECK_IF_PTR_NULL_RETURN_VALUE(producer, RC_ERROR);
    bufferQueue_ = OHOS::Surface::CreateSurfaceAsProducer(producer); //Buffer的生产者使用该函数创建一个Surface,只能使用与生产相关的接口
    CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
    return RC_OK;
}

这个成员函数的作用就是把应用层中的StreamCustomer::CreateProducer()获取的producer作为参数创建与“消费者”对应的“生成型”Surface。 而StreamTunnel类就是对这个生成型Surface的一个功能封装。

2. StreamOperator::CommitStreams()

源码有点长 去掉一些参数的校验和准备相关的代码
一共调用 StreamBase::CommitStream() 、StreamPipelineCore::PreConfig()、StreamPipelineCore::CreatePipeline()三个函数
下面一个个来看

//drivers\peripheral\camera\hal\hdi_impl\src\stream_operator\stream_operator.cpp
CamRetCode StreamOperator::CommitStreams(OperationMode mode,
                                         const std::shared_ptr<CameraStandard::CameraMetadata>& modeSetting)
{
    ...
    {
        std::lock_guard<std::mutex> l(streamLock_);
        for (auto it : streamMap_) {
            if (it.second->CommitStream() != RC_OK) {
                CAMERA_LOGE("commit stream [id = %{public}d] failed.", it.first);
                return DEVICE_ERROR;
            }
        }
    }
    RetCode rc = streamPipeline_->PreConfig(modeSetting);
    if (rc != RC_OK) {
        CAMERA_LOGE("prepare mode settings failed");
        return DEVICE_ERROR;
    }
    rc = streamPipeline_->CreatePipeline(mode);
    if (rc != RC_OK) {
        CAMERA_LOGE("create pipeline failed.");
        return INVALID_ARGUMENT;
    }

    DFX_LOCAL_HITRACE_END;
    return NO_ERROR;
}

2.1 StreamBase::CommitStream()

按照代码LOG中的说明commit a stream to pipeline。大家可以自行理解,本人的理解是

  • 通过BufferManager创建并初始化BufferPool 数据缓存池
  • 给这个Stream对应的pipeline 创建一个StreamMgr,让pipeline可以通过StreamMgr对Stream进行对应的控制。
//drivers\peripheral\camera\hal\hdi_impl\src\stream_operator\stream_base.cpp
RetCode StreamBase::CommitStream()
{
    ...
    
    HostStreamInfo info;
    info.type_ = static_cast<StreamIntent>(streamType_);
    info.streamId_ = streamId_;
    info.width_ = streamConfig_.width;
    info.height_ = streamConfig_.height;
    info.format_ = streamConfig_.format;
    info.usage_ = streamConfig_.usage;
    info.encodeType_ = streamConfig_.encodeType;

    if (streamConfig_.tunnelMode) {
        BufferManager* mgr = BufferManager::GetInstance();
        CHECK_IF_PTR_NULL_RETURN_VALUE(mgr, RC_ERROR);

        if (bufferPool_ == nullptr) {
            poolId_ = mgr->GenerateBufferPoolId();
            CHECK_IF_EQUAL_RETURN_VALUE(poolId_, 0, RC_ERROR);

            bufferPool_ = mgr->GetBufferPool(poolId_);
            if (bufferPool_ == nullptr) {
                CAMERA_LOGE("stream [id:%{public}d] get buffer pool failed.", streamId_);
                return RC_ERROR;
            }
        }

        info.bufferPoolId_ = poolId_;
        info.bufferCount_ = GetBufferCount();
        RetCode rc = bufferPool_->Init(streamConfig_.width, streamConfig_.height, streamConfig_.usage,
                                       streamConfig_.format, GetBufferCount(), CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL);
        if (rc != RC_OK) {
            CAMERA_LOGE("stream [id:%{public}d] initialize buffer pool failed.", streamId_);
            return RC_ERROR;
        }
    }

    RetCode rc = hostStreamMgr_->CreateHostStream(info, [this](std::shared_ptr<IBuffer> buffer) {
        HandleResult(buffer);
        return;
    });
    
    ...

    return RC_OK;
}

2.2 StreamPipelineCore::PreConfig()

这里的代码比较简单,根据参数信息,调用deviceManager的PreConfig接口从来配置下面的硬件设备。
deviceManager在前面PowerUp的解析已经说明了,Hi3516实际上是将硬件适配层相关的代码都封闭在了so里面,
所以这里实际调用就一行代码sysObject_->PreConfig(meta, settings);

//drivers\peripheral\camera\hal\pipeline_core\pipeline_impl\src\stream_pipeline_core.cpp
RetCode StreamPipelineCore::PreConfig(const ModeMeta& meta)
{
    auto deviceManager = IDeviceManager::GetInstance();
    CHECK_IF_PTR_NULL_RETURN_VALUE(deviceManager, RC_ERROR);

    std::vector<DeviceStreamSetting> settings = {};
    std::vector<int32_t> ids = {};
    context_->streamMgr_->GetStreamIds(ids);
    for (auto i : ids) {
        auto info = context_->streamMgr_->GetStreamInfo(i);
        DeviceStreamSetting setting = {info.streamId_, info.bufferCount_, info.width_, info.height_,
            info.format_, info.usage_, static_cast<CameraEncodeType>(info.encodeType_)};
        settings.emplace_back(setting);
    }
    return deviceManager->PreConfig(meta, settings);
}

2.3 StreamPipelineCore::CreatePipeline()

有关stategy、builder、dispatcher实现的函数代码比较多,大家感兴趣自行阅读。总的说一下整体功能:

  • StreamPipelineStrategy 负责根据mode从对应的配置文件中创建pipeline。
  • StreamPipelineBuilder 负责创建Node并链接
  • StreamPipelineDispatcher 负责管理创建好的pipeline
  • 最终建立的StreamPipeline是由Node(节点)组成,Node(节点)由Port(端口)组成。Port(端口)分为in端口和out端口(可以有多个)。out链接in最终构建出整个StreamPipeline

Demo案例建立了两个streamPipeline

OH-v3.0-LTS Camera相机驱动框架(L2)解析4_创建流-鸿蒙开发者社区

//drivers\peripheral\camera\hal\pipeline_core\pipeline_impl\src\stream_pipeline_core.cpp
RetCode StreamPipelineCore::CreatePipeline(const int32_t& mode)
{
    std::lock_guard<std::mutex> l(mutex_);
    std::shared_ptr<PipelineSpec> spec = strategy_->GeneratePipelineSpec(mode);
    if (spec == nullptr) {
        return RC_ERROR;
    }
    std::shared_ptr<Pipeline> pipeline = builder_->Build(spec);
    if (pipeline == nullptr) {
        return RC_ERROR;
    }
    return dispatcher_->Update(pipeline);
}

需要注意几个问题

  1. pipeline的配置文件在drivers\peripheral\camera\hal\pipeline_core\pipeline_impl\src\strategy\config目录下的config.c和params.c
  2. 这两个文件是由BUILD.gn 脚本生成的。
//drivers\peripheral\camera\hal\adapter\chipset\hispark_taurus\BUILD.gn
  source =
      "$camera_path/pipeline_core/pipeline_impl/src/strategy/config/config.c"
  exec_script(
      "//drivers/framework/tools/hc-gen/build_hcs.py",
      [
        "-o",
        rebase_path(
            "$camera_path/pipeline_core/pipeline_impl/src/strategy/config/config.c"),
        "-t",
        rebase_path(
            "//vendor/hisilicon/Hi3516DV300/hdf_config/uhdf/camera/hal/mpp/hispark_taurus/pipeline_core/config.hcs"),
      ],
      "")
}

ohos_prebuilt_etc("params.c") {
  source =
      "$camera_path/pipeline_core/pipeline_impl/src/strategy/config/params.c"
  exec_script(
      "//drivers/framework/tools/hc-gen/build_hcs.py",
      [
        "-o",
        rebase_path(
            "$camera_path/pipeline_core/pipeline_impl/src/strategy/config/params.c"),
        "-t",
        rebase_path(
            "//vendor/hisilicon/Hi3516DV300/hdf_config/uhdf/camera/hal/mpp/hispark_taurus/pipeline_core/params.hcs"),
      ],
      "")
}

3. 小结

到此流的创建也完成了,最后一章节会把图像采集的代码讲解完。
新年第一篇更的晚了点,祝大家虎年开工大吉,如虎添翼。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-2-7 16:29:10修改
3
收藏 2
回复
举报
3条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

也祝楼主在新的一年事业有成

回复
2022-2-8 10:06:17
超高校级的囧小平
超高校级的囧小平

非常好~赞一个

回复
2022-2-14 10:15:42
LoinDIci
LoinDIci

流程图清晰度不够,可以上传原图吗

回复
2022-7-29 15:49:44
回复
    相关推荐