OH-v3.0-LTS Camera相機驅動框架(L2)解析3_創建流的準備
原創??https://harmonyos.51cto.com??
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的“生產者”在哪里?
??https://harmonyos.51cto.com??