OpenHarmony Camera 源码分析
一、简介
当前,开源在科技进步和产业发展中发挥着越来越重要的作用,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 多媒体子系统的工作原理。
评论