一、简介

当前,开源在科技进步和产业发展中发挥着越来越重要的作用,OpenAtom OpenHarmony(简称“OpenHarmony”)赋予了开发者孕育创新的种子,也为数字化产业发展开辟了一片土壤。深开鸿是开源的坚定践行者,基于OpenHarmony聚焦智能物联网操作系统(KaihongOS)技术研发与持续创新。

OpenHarmony Camera是多媒体子系统中的一个重要模块,Camera提供了OpenHarmony相机的预览、拍照和录像等功能。作为深开鸿的一名OS系统开发工程师,我长期致力于OpenHarmony框架层的研发工作,在OpenHarmony相机模块的拍照、预览和录像方面积累了一些经验,我将围绕着这三个核心功能对OpenHarmony Camera源码进行详细的分析。

二、OpenHarmony相机子系统

(1)系统简介

相机组件支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照和录像等。

架构图

相机框架中主要包含会话管理、设备输入和数据输出,设备的输入和数据的输出配置都是在采集会话中完成,会话管理模块管理相机设备输入和数据输出。应用层在调用相机功能时,首先需要创建采集会话,在配置会话的过程中会将创建的设备输入和数据输出添加到采集会话中。

相机框架中几个重要的概念

会话管理:对相机采集的生命周期、参数配置、输入和输出的管理。

设备输入:主要的输入设备是相机,对相机的输入参数进行设置,比如设置闪光灯模式等。

数据输出:相机的输出有拍照输出、预览输出和录像输出,分别对应三个不同的类,所以上层需要根据不同的场景创建出不同的数据输出。

相机底层功能图

相机驱动框架模型对上实现相机HDI接口,对下实现相机Pipeline模型,管理相机各个硬件设备。底层硬件提供了相机设备功能,比如相机的设备管理,包括相机设备枚举、相机设备能力查询、流的创建管理以及图像的捕获。

(2)功能模块

会话管理模块

会话管理模块的主要功能是配置会话的输入(设备输入)和输出(数据的输出),以及控制会话的开始和结束,主要接口有:

设备输入模块

相机输入主要是给会话设置设备的输入,设备输入模块可以设置和获取输入设备的参数,比如闪光灯模式、缩放比例、对焦模式等,主要接口有:

数据输出模块

数据输出模块根据不同的场景分为拍照输出、预览输出和录像输出。其中拍照的输出是通过PhotoOutput的Capture接口来提供拍照功能,预览和录像则是通过StreamRepeat提供的接口实现。主要接口有:

(3)功能特性或应用场景

相关功能接口:相机拍照、相机预览、相机录像。相机的主要应用场景是拍照、预览和录像,以下针对这三个场景进行流程的分析。

camera\_standard\interfaces\inner_api\native\test目录下应用文件进行拍照、预览和录像功能的使用,进行源码分析。

拍照源码分析

拍照功能根据camera\_capture.cpp文件中的main方法进行分析,以下列举了main方法中的主要调用步骤,并且在注释中介绍核心代码的功能。

在拍照过程中首先获取相机管理器实例并获得相机对象列表,然后创建并配置采集会话(其中包括配置相机输入、创建消费者Surface以及监听事件、配置拍照输出),最后拍摄照片,释放资源。

以下是拍照流程的时序图,流程只分析到CameraService,后续的操作是通过Camera的Service和HDI接口进行调用,最终调用到Camera的底层HDF实现。以下对几个核心代码进行具体分析。

① 创建采集会话

App侧先调用CameraManager的CreateCaptureSession接口。

CameraManager中有一个serviceProxy\_变量,这个变量在CameraManager初始化的时候赋值。

CameraManager中通过serviceProxy\_调用CreateCaptureSession,实际上是调用到HcameraService的CreateCaptureSession接口,新建了HCaptureSession对象,并通过CreateCaptureSession参数进行返回。

② 创建消费者Surface并注册监听器以监听缓冲区更新

调用Surface的CreateSurfaceAsConsumer接口。

创建ConsumerSurface对象,然后对该对象进行初始化操作,Init主要创建BufferQueue并初始化,使用BufferQueue作为参数创建出BufferQueue的Producer和Consumer,作为数据生产者和消费者。

创建CaptureSurfaceListener对象。CaptureSurfaceListener继承IbufferConsumerListener抽象类,实现了OnBufferAvailable接口,capture成功后,在这个接口中通过surface的AcquireBuffer方法来获取帧数据,进行保存图片的处理。

接下来是注册监听器,方法是调用ConsumerSurface的RegisterConsumerListener接口。

调用BufferQueueConsumer的RegisterConsumerListener接口,最终是调用到BufferQueue的RegisterConsumerListener接口。

③ 拍摄照片

调用PhotoOutput的Capture接口实现拍照功能。

通过streamCapture\_调用到了HstreamCapture的Capture接口。

调用流程来到了StreamOperatorProxy的Capture接口,StreamOperatorProxy是HDI模块的client端,HDI模块的client通过IPC调用到HDI的server端进行具体的操作,这个属于底层调用模块,暂时不继续分析。

预览源码分析

预览功能根据camera\_capture.cpp文件中的main方法进行分析,以下列举了main方法中的主要调用步骤,并且注释中介绍核心代码的功能。

在预览过程中首先获取相机管理器实例并获得相机对象列表,然后创建并配置采集会话(其中包括配置相机输入、创建消费者Surface以及监听事件、配置预览输出),最后开始预览、停止预览、释放资源。

以下是预览流程的时序图,流程只分析到CameraService,后续的操作是通过Camera的Service和HDI接口进行调用,最终调用到Camera的底层HDF实现。由于预览和拍照流程有部分一致,我们只分析差异部分的流程。

① 创建预览输出

首先调用CameraManager的CreateCustomPreviewOutput接口。

调用HcameraService的CreateCustomPreviewOutput的接口,这个接口中会创建HStreamRepeat对象,并将对象赋值给streamRepeat的参数,后续根据streamRepeat创建PreviewOutput对象返回,PreviewOutput作为预览的输出。

②开始预览

首先调用CaptureSession的Start接口。

接着调用HCaptureSession的Start接口。

在HCaptureSession的调用中,调用HStreamRepeat的Start接口,HStreamRepeat在上述的创建预览输出时创建的对象,最终调用到HStreamRepeat的StartPreview接口。

在StartPreview方法中调用streamOperator\_的Capture接口,第三个参数传入true,表示连续抓取数据。streamOperator\_的调用是在HDI中的操作,属于底层操作,暂不进行分析。

录像源码分析

录像功能根据camera\_video.cpp文件中的main方法进行分析,以下列举了main方法中的主要调用步骤,并且注释中介绍核心代码的功能。

在录像过程中首先获取相机管理器实例并获得相机对象列表,然后创建并配置采集会话(其中包括配置相机输入、创建视频输出),最后进行视频的录制、暂停、恢复和停止。

以下是录像流程的时序图,流程只分析到了CameraService相关,后续的操作是通过Camera的Service和HDI接口进行调用,最终调用到Camera的底层HDF实现。录像流程跟上述流程基本一致,针对差异流程做相关的源码分析。

①创建录像输出

首先调用CameraManager的CreateVideoOutput接口,在CameraManager会调用serviceProxy\_变量的CreateVideoOutput.

serviceProxy\_最终会调用到HcameraService的CreateVideoOutput接口,在HcameraService中会创建HStreamRepeat对象,创建成功后会将该对象赋值给CreateVideoOutput的第二个参数streamRepeat,这个参数会在CameraManager中作为创建VideoOutput的参数。

②开始录像

首先调用VideoOutput的Start接口,接着会调用到streamRepeat\_的Start接口。

最终由StartVideo接口来实现录像的功能。

调用streamOperator的Capture接口来进行录像,其中第二个参数captureInfoVideo是video相关的信息参数。

三、总结

本文首先对相机预览、拍照和录像功能的应用层进行了代码分析,其次对框架层的流程进行了梳理,最后再对框架源码进行分析。希望通过本文能帮助开发者初步掌握OpenHarmony Camera源码工作的整个流程。关于OpenHarmony多媒体子系统方面的内容,我已经发表过《如何通过OpenHarmony的音频模块实现录音变速功能》《如何通过OpenHarmony系统中集成的ffmpeg库和NAPI机制,实现更多的多媒体功能?》两篇文章,感兴趣的朋友可以点击阅读,希望大家通过学习能够掌握更多OpenHarmony多媒体子系统的工作原理。

OpenHarmony Camera源码分析的更多相关文章

  1. 鸿蒙内核源码分析(忍者ninja篇) | 都忍者了能不快吗 | 百篇博客分析OpenHarmony源码 | v61.02

    百篇博客系列篇.本篇为: v61.xx 鸿蒙内核源码分析(忍者ninja篇) | 都忍者了能不快吗 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙 ...

  2. 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙看这篇或许真的够了 | 百篇博客分析OpenHarmony源码 | v50.06

    百篇博客系列篇.本篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉坑指南 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉 ...

  3. 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基础 | 百篇博客分析OpenHarmony源码 | v68.01

    子曰:"质胜文则野,文胜质则史.文质彬彬,然后君子." <论语>:雍也篇 百篇博客系列篇.本篇为: v68.xx 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基 ...

  4. 鸿蒙内核源码分析(根文件系统) | 先挂到`/`上的文件系统 | 百篇博客分析OpenHarmony源码 | v66.01

    百篇博客系列篇.本篇为: v66.xx 鸿蒙内核源码分析(根文件系统) | 先挂到/上的文件系统 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  5. 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概念 | 百篇博客分析OpenHarmony源码 | v64.01

    百篇博客系列篇.本篇为: v64.xx 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概念 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么 ...

  6. 鸿蒙内核源码分析(文件概念篇) | 为什么说一切皆是文件 | 百篇博客分析OpenHarmony源码 | v62.01

    百篇博客系列篇.本篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一切皆是文件 | 51.c.h.o 本篇开始说文件系统,它是内核五大模块之一,甚至有Linux的设计哲学是" ...

  7. 鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用 | 百篇博客分析OpenHarmony源码 | v60.01

    百篇博客系列篇.本篇为: v60.xx 鸿蒙内核源码分析(gn应用篇) | gn语法及在鸿蒙的使用 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙 ...

  8. 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 百篇博客分析OpenHarmony源码 | v59.01

    百篇博客系列篇.本篇为: v59.xx 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿 ...

  9. 鸿蒙内核源码分析(编译脚本篇) | 如何防编译环境中的牛皮癣 | 百篇博客分析OpenHarmony源码 | v58.01

    百篇博客系列篇.本篇为: v58.xx 鸿蒙内核源码分析(环境脚本篇) | 编译鸿蒙原来如此简单 | 51.c.h.o 本篇用两个脚本完成鸿蒙(L1)的编译环境安装/源码下载/编译过程,让编译,调试鸿 ...

  10. 鸿蒙内核源码分析(静态站点篇) | 五一哪也没去就干了这事 | 百篇博客分析OpenHarmony源码 | v52.02

    百篇博客系列篇.本篇为: v52.xx 鸿蒙内核源码分析(静态站点篇) | 五一哪也没去就干了这事 | 51.c.h.o 前因后果相关篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 ...

随机推荐

  1. TypeScript项目开发运行(即时编译、运行,所见所得)

    1.项目*.ts自动编译 $ tsc . --watch 2.项目本地web服务运行 $ npm install --save-dev webpack-dev-server npm install - ...

  2. Kubernetes:Pod 端口映射

    本文为作者的 Kubernetes 系列电子书的一部分,电子书已经开源,欢迎关注,电子书浏览地址: https://k8s.whuanle.cn[适合国内访问] https://ek8s.whuanl ...

  3. 没想到,JDBC 驱动会偷偷修改 sql_mode 的会话值

    最近碰到一个 case,值得分享一下. 现象就是一个 update 操作,在 mysql 客户端中执行提示 warning,但在 java 程序中执行却又报错. 问题重现 mysql> crea ...

  4. C++ 多线程笔记1 线程的创建

    C++ 多线程笔记1 线程的创建 里面代码会用到的头文件 #include <iostream> #include <string> #include <memory&g ...

  5. AP渗透测试学习

    1.测试指标 2.测试环境 SDK: Java JDK  ,Android SDK 工具: 7zip    dex2jar   jd-gui     apktool  activity 劫持工具 3. ...

  6. vue和xml复习

    复习 JS知识梳理 JS定义的位置 行内js(事件名="javascript:js代码"),内部js(

  7. vid = two 切开 分开 - 两个眼睛 还有看的含义 - 词根

    vid = two 切开 分开 - 两个眼睛 还有看的含义 - 词根 vi = wo acs 构词

  8. 英语自定义标签 <i:juzi><i:zhuyu>John Smith</i:zhuyu></i:juzi> 主语谓语宾语

    效果 John Smith died in World War Two. John Smith killed three enemy soldiers. <style> i\:juzi { ...

  9. vue遇到拖拽动态生成组件怎么办?[转]

    知识点 主要是关注 动态生成 vue组件,这里是Vue2.0的demo Vue.Draggable 拖拽库 Vue.extend() 挂载 com.$mount() 生成组件 this.$refs.c ...

  10. Uni-App 实现资讯滚动

    项目需要实现资讯的滚动,使用了Swiper组件,实现了首页头部的资讯滚动,简单地做下笔记 效果 实现说明 主要是使用了Swiper可以自动滚动的特性来实现,左边是一个图片,右边则是Swpier,且姜S ...