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

NL_AIDC_Ryanzx
发布于 2022-1-24 17:10
浏览
2收藏

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

新大陆自动识别 郑曦

1. 简单回顾

先简单回顾总结下前面两章的内容要点

  • Camera HDI框架是通过绑定到HDF框架后在系统启动的时候完成初始化 Camera Host 实例。
  • 应用层通过获取Camera Host 实例来得到设备支持的Camera的能力属性,并Open相应的设备。
  • 应用层通过IPC通讯来调用HDI接口

补充说明

在前面CameraHostImpl::Init()创建CameraDevice实例对象的时候会实例化PipelineCore的各个子模块包括HostStreamMgrStreamPipelineCore对应的功能会在下面的文章逐一说明。

本章开始略去IPC通讯相关的代码(包括流程图),读者可以参考第一章中SetCallback流程自行梳理代码。

2. 回到代码

应用层完成CameraDevice初始化后 开始创建流 相关的上层调用代码相对简单,这里简单画个图,大家可以对着代码梳理下。我们从CreatStrem开始继续往下看。
OH-v3.0-LTS Camera相机驱动框架(L2)解析3_创建流的准备-鸿蒙开发者社区

先丢一个本章代码涉及到的流程图
OH-v3.0-LTS Camera相机驱动框架(L2)解析3_创建流的准备-鸿蒙开发者社区

2.1 Hos3516Demo::GetStreamOpt()

先为 流操作 接口创建一个上层回调,然后通过IPC调用到CameraDeviceImplGetStreamOperator接口获取流操作的实例。

//drivers\peripheral\camera\hal\init\3516_demo.cpp
void Hos3516Demo::GetStreamOpt()
{
    int rc = 0;

    if (streamOperator_ == nullptr) {
        const sptr<IStreamOperatorCallback> streamOperatorCallback = new StreamOperatorCallback();
        rc = demoCameraDevice_->GetStreamOperator(streamOperatorCallback, streamOperator_);
        if (rc != Camera::NO_ERROR) {
            CAMERA_LOGE("demo test: GetStreamOpt GetStreamOperator fail\n");
            streamOperator_ = nullptr;
        }
    }
}

CameraDeviceImpl负责实例化StreamOperator对象,并调用StreamOperator::Init() 完成初始化。

//drivers\peripheral\camera\hal\hdi_impl\src\camera_device\camera_device_impl.cpp
CamRetCode CameraDeviceImpl::GetStreamOperator(
    const OHOS::sptr<IStreamOperatorCallback> &callback,
    OHOS::sptr<IStreamOperator> &streamOperator)
{
    ...
    spCameraDeciceCallback_ = callback;
    if (spStreamOperator_ == nullptr) {
        spStreamOperator_ = new(std::nothrow) StreamOperator(spCameraDeciceCallback_, shared_from_this());
        if (spStreamOperator_ == nullptr) {
            CAMERA_LOGW("create stream operator failed.");
            return DEVICE_ERROR;
        }
        spStreamOperator_->Init();
        ismOperator_ = spStreamOperator_;
    }
    streamOperator = ismOperator_;
    ...
}

StreamOperator::Init() 会从前面实例化的CameraDevice对象中取出已经实例化好的StreamPipelineCore对象调用对应的Init初始化,同时创建一个进程接收特定的消息。

//drivers\peripheral\camera\hal\hdi_impl\src\stream_operator\stream_operator.cpp
RetCode StreamOperator::Init()
{
    ...
    pipelineCore_ = dev->GetPipelineCore();
    ...
    streamPipeline_ = pipelineCore_->GetStreamPipelineCore();
    ...
    RetCode rc = streamPipeline_->Init();
    ...
    auto cb = [this](MessageGroup& m) { HandleCallbackMessage(m); };
    messenger_ = std::make_shared<CaptureMessageOperator>(cb);
    CHECK_IF_PTR_NULL_RETURN_VALUE(messenger_, RC_ERROR);
    messenger_->StartProcess();

    return RC_OK;
}

StreamPipelineCore::Init()继续实例化StreamPipelineStrategy、StreamPipelineBuilder、StreamPipelineDispatcher 这3个类。它们是负责pipeNode的创建和控制的,现在我们只要记得代码已经把它们实例化完成并放在了StreamPipelineCore里。

RetCode StreamPipelineCore::Init()
{
    strategy_ = StreamPipelineStrategy::Create(context_->streamMgr_);
    builder_ = StreamPipelineBuilder::Create(context_->streamMgr_);
    dispatcher_ = StreamPipelineDispatcher::Create();
    return RC_OK;
}

到这里StremOperator(下面红框的部分)就创建好了,然后通过IPC回传给上层应用。
OH-v3.0-LTS Camera相机驱动框架(L2)解析3_创建流的准备-鸿蒙开发者社区
整个的StremOperator创建涉及到比较多的类 对应的关系可以看下下面的类图(个人理解,非官方)
OH-v3.0-LTS Camera相机驱动框架(L2)解析3_创建流的准备-鸿蒙开发者社区

2.2 Hos3516Demo::SetStreamInfo()

创建一个流信息 StreamInfo 这里的代码相对简单,设置这个流的分辨率、编码模式、流ID等等。
这里要注意的是bufferQueue_ 这个成员。下面会先简单讲一下,算是挖个坑。
然后tunneledMode = 5这个地方感觉是个BUG 因为在后续的HDI代码部分 实际是个bool类型。

void Hos3516Demo::SetStreamInfo(std::shared_ptr<StreamInfo>& streamInfo,
    const std::shared_ptr<StreamCustomer>& streamCustomer,
    const int streamId, const StreamIntent intent)
{
    constexpr uint32_t datasapce = 8;
    constexpr uint32_t tunneledMode = 5;

    if (intent == PREVIEW) {
        constexpr uint32_t width = 640;
        constexpr uint32_t height = 480;
        streamInfo->width_ = width;
        streamInfo->height_ = height;
    } else if (intent == STILL_CAPTURE) {
        constexpr uint32_t width = 1280;
        constexpr uint32_t height = 960;
        streamInfo->width_ = width;
        streamInfo->height_ = height;
        streamInfo->encodeType_ = ENCODE_TYPE_JPEG;
    } else {
        constexpr uint32_t width = 1280;
        constexpr uint32_t height = 960;
        streamInfo->width_ = width;
        streamInfo->height_ = height;
        streamInfo->encodeType_ = ENCODE_TYPE_H265;
    }

    streamInfo->streamId_ = streamId;
    streamInfo->format_ = PIXEL_FMT_YCRCB_420_SP;
    streamInfo->datasapce_ = datasapce;
    streamInfo->intent_ = intent;
    streamInfo->tunneledMode_ = tunneledMode;
    streamInfo->bufferQueue_ = streamCustomer->CreateProducer();
    streamInfo->bufferQueue_->SetQueueSize(8); // 8:set bufferQueue size
}

StreamCustomer::CreateProducer()

这里的OHOS::Surface 涉及到了Graphic子系统中的Surface。Surface 是图形缓冲区管理接口,负责管理图形缓冲区和高效便捷的轮转缓冲区
详细的说明可以看下源码中的Readme路径在:foundation/graphic/standard/README_zh.md
是这里按照我个人的理解先简单的说一下:
Surface分成了一个“生产者” 一个 “消费者”。应用端作为“消费者”向Surface模块申请一个Surface。当对应的“生产者”产生了数据就会通知“消费者” 对数据进行处理。
StreamCustomer::CreateProducer()做了两件事情

  • 为上层应用获取了一个“消费型”surface
  • 从获取到的surface中取出对应的“生产者”对象放在了StremInfo的信息里 丢给StreamOperator
//drivers\peripheral\camera\hal\init\stream_customer.cpp
sptr<OHOS::IBufferProducer> StreamCustomer::CreateProducer()
{
    consumer_ = OHOS::Surface::CreateSurfaceAsConsumer(); //Buffer的消费者来使用该函数创建一个Surface
    if (consumer_ == nullptr) {
        return nullptr;
    }
    sptr<IBufferConsumerListener> listener = new TestBuffersConsumerListener();
    consumer_->RegisterConsumerListener(listener);        //注册一个消费监听器,监听Buffer的Flush事件 

    auto producer = consumer_->GetProducer();             //获得一个Surface内部的IBufferProducer对象
    if (producer == nullptr) {
        return nullptr;
    }

    CAMERA_LOGI("demo test, create a buffer queue producer %{public}p", producer.GetRefPtr());
    return producer;
}

3. 小结

代码到这边 上层应用已经获取到了HDI层的StreamOperator对象实例。同时为图像数据准备了一个Surface!

同样挖了两个小坑,留待后面的代码进一步讲解

  • StreamPipelineStrategy、StreamPipelineBuilder、StreamPipelineDispatcher 这些类是怎么工作的?
  • Surface的“生产者”在哪里?

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
2
收藏 2
回复
举报
2条回复
按时间正序
/
按时间倒序
mb609898e2cfb86
mb609898e2cfb86

流程图非常详细

回复
2022-1-25 10:38:20
luxiefly2
luxiefly2

好文章,很有用,学习了

回复
2023-7-25 14:57:14
回复
    相关推荐