OH-v3.0-LTS Camera相机驱动框架(L2)解析3_创建流的准备 原创 精华
OpenHarmory-v3.0-LTS Camera相机驱动框架(L2)解析3_创建流的准备
新大陆自动识别 郑曦
1. 简单回顾
先简单回顾总结下前面两章的内容要点
- Camera HDI框架是通过绑定到HDF框架后在系统启动的时候完成初始化 Camera Host 实例。
- 应用层通过获取Camera Host 实例来得到设备支持的Camera的能力属性,并Open相应的设备。
- 应用层通过IPC通讯来调用HDI接口
补充说明
在前面
CameraHostImpl::Init()
创建CameraDevice
实例对象的时候会实例化PipelineCore
的各个子模块包括HostStreamMgr
、StreamPipelineCore
对应的功能会在下面的文章逐一说明。
本章开始略去IPC通讯相关的代码(包括流程图),读者可以参考第一章中
SetCallback
流程自行梳理代码。
2. 回到代码
应用层完成CameraDevice初始化后 开始创建流 相关的上层调用代码相对简单,这里简单画个图,大家可以对着代码梳理下。我们从CreatStrem开始继续往下看。
先丢一个本章代码涉及到的流程图
2.1 Hos3516Demo::GetStreamOpt()
先为 流操作 接口创建一个上层回调,然后通过IPC调用到CameraDeviceImpl
的GetStreamOperator
接口获取流操作的实例。
//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回传给上层应用。
整个的StremOperator创建涉及到比较多的类 对应的关系可以看下下面的类图(个人理解,非官方)
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的“生产者”在哪里?
流程图非常详细
好文章,很有用,学习了