OpenHarmony 源码解析之多媒体子系统(camera) 原创 精华
作者:郭岳峰
1 简介
媒体子系统为开发者提供一套接口,方便开发者使用系统的媒体资源,本文主要介绍多媒体下的Camera模块。
1.1 OpenHarmony 架构图
1.2 camera子系统
相关功能接口:相机拍照、相机预览、相机录像
1.3 原理图
1.4 搭建HarmonyOS环境
我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
-
安装DevEco Studio,详情请参考下载和安装软件。
-
设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
1.如果可以直接访问Internet,只需进行下载OpenHarmony SDK操作。
2.如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
-
开发者可以参考以下链接,完成设备调试的相关配置:
1.使用真机进行调试
2 基础知识
2.1 代码结构
2.2 相机模块核心类
3 源码解析
3.1 上层初始化示例
该文件的main方法执行了创建camera的整个流程,并且在创建初始化好了camera后,根据用户输入的字符,对camera进行拍照,录像,预览功能的执行。
int main()
{
cout << "Camera sample begin." << endl;
SampleHelp();
CameraKit *camKit = CameraKit::GetInstance();
if (camKit == nullptr) {
cout << "Can not get CameraKit instance" << endl;
return 0;
}
list<string> camList = camKit->GetCameraIds();
string camId;
for (auto &cam : camList) {
camId = cam;
break;
}
if (camId.empty()) {
cout << "No available camera.(1080p wanted)" << endl;
return 0;
}
EventHandler eventHdlr; // Create a thread to handle callback events
SampleCameraStateMng CamStateMng(eventHdlr);
camKit->CreateCamera(camId, CamStateMng, eventHdlr);
char input;
while (cin >> input) {
switch (input) {
case '1':
CamStateMng.Capture();
break;
case '2':
CamStateMng.StartRecord();
break;
case '3':
CamStateMng.StartPreview();
break;
case 's':
CamStateMng.Stop();
break;
case 'q':
CamStateMng.Stop();
goto EXIT;
default:
SampleHelp();
break;
}
}
EXIT:
cout << "Camera sample end." << endl;
return 0;
}
Camkit 是CameraKit类的全局的变量,这个主要提供上层的调用,这个类里面实际是通过cameraManager_对象进行调用相关的方法。图中主要的流程分为以下几个步骤:
-
获取CameraKit实例
-
调用camKit的GetCameraIds方法获取摄像头的id列表,根据id列表找到1080P分辨率的摄像头id,如果没有找到提示错误信息,直接return。
-
调用camKit的CreateCamera方法,这个方法是camera初始化的核心
根据这三个步骤,分析每一个步骤的流程,获取CameraKit实例这一步,其实一层层调用,实现camera初始化的操作,以下是相关的调用流程
(1)获取CameraKit流程
(2)GetCameraIds流程
list<string> CameraKit::GetCameraIds()
{
return cameraManager_->GetCameraIds();
}
CameraKit调用实际上是通过cameraManager_进行调用
list<string> GetCameraIds() override
{
list<string> cameraList;
for (auto &i : cameraMapCache_) {
MEDIA_DEBUG_LOG("%s", i.first.c_str());
cameraList.emplace_back(i.first);
}
return cameraList;
}
CameraService初始化完成后,通过device和ability创建的CameraImpl实例存入cameraMapCache_变量中, GetCameraIds方法通过遍历cameraMapCache_来获取可用的cameraId列表。
(3)CreateCamera流程
void CameraKit::CreateCamera(const string &cameraId, CameraStateCallback &callback, EventHandler &handler)
{
g_cameraManager->CreateCamera(cameraId, callback, handler);
}
CameraKit实际调用了CameraManagerImpl的CreateCamera方法
void CreateCamera(const string &cameraId, CameraStateCallback &callback, EventHandler &handler) override
{
auto p = cameraMapCache_.find(cameraId);
if (p == cameraMapCache_.end()) {
MEDIA_ERR_LOG("Camera impl not found.");
handler.Post([&callback, &cameraId] { callback.OnCreateFailed(cameraId, MEDIA_ERR); });
return;
}
p->second->RegistCb(callback, handler);
cameraService_->CreateCamera(cameraId);
}
首先根据cameraId在cameraMapCache_中找到CameraImpl的位置,将CameraStateCallback回调注册到CamerImpl中,CameraStateCallback是从应用层通过参数传入进来,所以后续CameraImpl中的Configure,Release,OnCreate,OnCreateFailed等方法会通过回调,调用应用层的接口。最后调用CameraService的CreateCamera方法进行创建camera。
void CameraService::CreateCamera(string cameraId)
{
if (cameraId != g_mainCamera) {
MEDIA_ERR_LOG("This camera does not exist. (cameraId=%s)", cameraId.c_str());
}
cameraServiceCb_->OnCameraStatusChange(cameraId, CameraServiceCallback::CAMERA_STATUS_CREATED, *device_);
}
CameraService中主要通过回调OnCameraStatusChange方法,这个是在CameraManagerImpl类中实现的,CameraManagerImpl通过调用CameraService的Initialize(*this)实现回调接口注册。
void CameraService::Initialize(CameraServiceCallback &callback)
{
MEDIA_DEBUG_LOG("Camera service initializing");
InitCameraDevices();
list<string> cameraList = {g_mainCamera};
cameraServiceCb_->OnCameraServiceInitialized(cameraList);
}
接下来看一下CameraManagerImpl中的回调实现
void OnCameraStatusChange(string &cameraId, CameraStauts status) override
{
auto p = cameraMapCache_.find(cameraId);
switch (status) {
case CAMERA_STATUS_UNAVAIL:
if (p != cameraMapCache_.end()) {
for (auto &i : deviceCbList_) {
i.second->Post(
[i, cameraId]() { i.first->OnCameraStatus(cameraId, CAMERA_DEVICE_STATE_UNAVAILABLE); });
}
// User may still using icamera now
delete p->second;
cameraMapCache_.erase(p);
}
break;
case CAMERA_STATUS_AVAIL:
InitCameraAbility(cameraId);
if (p == cameraMapCache_.end()) {
for (auto &i : deviceCbList_) {
i.second->Post(
[i, cameraId]() { i.first->OnCameraStatus(cameraId, CAMERA_DEVICE_STATE_AVAILABLE); });
}
}
break;
case CAMERA_STATUS_CREATED:
if (p != cameraMapCache_.end()) {
p->second->OnCreate(cameraId);
}
break;
case CAMERA_STATUS_CREATE_FAILED:
if (p != cameraMapCache_.end()) {
p->second->OnCreateFailed();
}
break;
default:
break;
}
}
调用cameraMapCache_中对应cameraId的OnCreate方法,其中device参数是CameraService中创建并传给CameraImpl的,接下来看一下CameraImpl的OnCreate方法
void CameraImpl::OnCreate(CameraDevice &device)
{
device_ = &device;
if (stateCb_ == nullptr || handler_ == nullptr) {
return;
}
handler_->Post([this] { this->stateCb->OnCreated(*this); });
}
首先在CameraImpl中保存一份device_, 其次在EventHandler中通过之前注册的CameraStateCallback回调OnCreate方法,该回调是上层应用实现的,具体如下图所示
class SampleCameraStateMng : public CameraStateCallback {
public:
SampleCameraStateMng() = delete;
SampleCameraStateMng(EventHandler &eventHdlr) : eventHdlr_(eventHdlr) {}
~SampleCameraStateMng()
{
CloseRecorder();
}
void OnCreated(Camera &c) override
{
cout << "Sample recv OnCreate camera." << endl;
auto config = CameraConfig::CreateCameraConfig();
config->SetFrameStateCallback(&fsCb_, &eventHdlr_);
c.Configure(*config);
cam_ = &c;
}
void OnCreateFailed(const std::string cameraId, int32_t errorCode) override {}
void OnReleased(Camera &c) override {}
主要配置了FrameStateCallback回调,以及设置了EventHandler,然后保存CameraImpl,应用层拿到了CameraImpl的对象,并且赋值给cam_对象,后续的camera操作都是通过cam_进行的。
3.2 上层调用相机功能
char input;
while (cin >> input) {
switch (input) {
case '1':
CamStateMng.Capture();
break;
case '2':
CamStateMng.StartRecord();
break;
case '3':
CamStateMng.StartPreview();
break;
case 's':
CamStateMng.Stop();
break;
case 'q':
CamStateMng.Stop();
goto EXIT;
default:
SampleHelp();
break;
}
}
应用层根据用户输入的字符进行拍照,开始录像,开始预览以及停止的操作,以下是拍照,录像和预览的时序图
拍照流程
录像流程
-
总结
通过本文的学习可以大致了解Camera的初始化流程,明白Camera的创建过程,并且对Camera的拍照,录像等功能有详细的了解。
更多原创内容请关注:开鸿 HarmonyOS 学院
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
楼主对Camera讲解可以说是非常详细了。
对于初学者来说这个真的太有用了
你们对鸿蒙源码都研究的这么细啊... 厉害...
对源码讲解的好详细呀,给楼主点赞
写的很详细,能快速的熟悉Camera模块,点赞~
仰望大佬~小菜鸡求带~
此文在手 玩转鸿蒙Camera不愁 棒~棒~棒~ 你真棒!
源码分析很到位,对我帮助很大,让我对多媒体子系统有更深入的了解
流程代码很细致,仰望楼主
代码分析的很透彻,层次清晰
nb了老哥
谢谢认可,可以关注专栏,下期还有更多源码解析
谢谢认可,可以关注专栏,下期还有更多源码解析
谢谢认可,可以关注专栏,下期还有更多源码解析
谢谢认可,可以关注专栏,下期还有更多源码解析
谢谢认可,可以关注专栏,下期还有更多源码解析
谢谢认可,可以关注专栏,下期还有更多源码解析
谢谢认可,可以关注专栏,下期还有更多源码解析
为什么一定找1080P的摄像头呢~ 我看openharmony3.0 没有找1080P摄像头这段代码呀
为什么openharmony3.0的demo代码中,把hevc改成h264就不行呢,代码编码没问题,但烧录之后ohos运行代码录制就出错