HarmonyOS学习路之开发篇—多媒体开发(相机开发 一)

news2024/11/15 11:17:42

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

基本概念

  • 相机静态能力

    用于描述相机的固有能力的一系列参数,比如朝向、支持的分辨率等信息。

  • 物理相机

    物理相机就是独立的实体摄像头设备。物理相机ID是用于标志每个物理摄像头的唯一字串。

  • 逻辑相机

    逻辑相机是多个物理相机组合出来的抽象设备,逻辑相机通过同时控制多个物理相机设备来完成相机某些功能,如大光圈、变焦等功能。逻辑摄像机ID是一个唯一的字符串,标识多个物理摄像机的抽象能力。

  • 帧捕获

    相机启动后对帧的捕获动作统称为帧捕获。主要包含单帧捕获、多帧捕获、循环帧捕获。

  • 单帧捕获

    指的是相机启动后,在帧数据流中捕获一帧数据,常用于普通拍照。

  • 多帧捕获

    指的是相机启动后,在帧数据流中连续捕获多帧数据,常用于连拍。

  • 循环帧捕获

    指的是相机启动后,在帧数据流中一直捕获帧数据,常用于预览和录像。

约束与限制

  • 在同一时刻只能有一个相机应用在运行中。
  • 相机模块内部有状态控制,开发者必须按照指导文档中的流程进行接口的顺序调用,否则可能会出现调用失败等问题。
  • 为了开发的相机应用拥有更好的兼容性,在创建相机对象或者参数相关设置前请务必进行能力查询。

相机开发流程

相机模块主要工作是给相机应用开发者提供基本的相机API接口,用于使用相机系统的功能,进行相机硬件的访问、操作和新功能开发。相机的开发流程如图所示:

接口说明

相机模块为相机应用开发者提供了3个包的内容,包括方法、枚举、以及常量/变量,方便开发者更容易地实现相机功能。详情请查阅对应开发场景。

包名

功能

ohos.media.camera.CameraKit

相机功能入口类。获取当前支持的相机列表及其静态能力信息,创建相机对象。

ohos.media.camera.device

相机设备操作类。提供相机能力查询、相机配置、相机帧捕获、相机状态回调等功能。

ohos.media.camera.params

相机参数类。提供相机属性、参数和操作结果的定义。

相机权限申请

在使用相机之前,需要申请相机的相关权限,保证应用拥有相机硬件及其他功能权限,相机涉及权限如下表。

权限名称

权限属性值

是否必选

相机权限

ohos.permission.CAMERA

必选

录音权限

ohos.permission.MICROPHONE

可选(需要录像时申请)

存储权限

ohos.permission.WRITE_MEDIA

可选(需要保存图像及视频到设备的外部存储时申请)

位置权限

ohos.permission.MEDIA_LOCATION

可选(需要保存图像及视频位置信息时申请)

相机设备创建

CameraKit类是相机的入口API类,用于获取相机设备特性、打开相机,其接口如下表。

接口名

描述

createCamera​(String cameraId, CameraStateCallback callback, EventHandler handler)

创建相机对象。

getCameraAbility​(String cameraId)

获取指定逻辑相机或物理相机的静态能力。

getCameraIds​()

获取当前逻辑相机列表。

getCameraInfo​(String cameraId)

获取指定逻辑相机的信息。

getInstance​(Context context)

获取CameraKit实例。

registerCameraDeviceCallback​(CameraDeviceCallback callback, EventHandler handler)

注册相机使用状态回调。

unregisterCameraDeviceCallback​(CameraDeviceCallback callback)

注销相机使用状态回调。

在实现一个相机应用之前必须先创建一个独立的相机设备,然后才能继续相机的其他操作。相机设备创建的建议步骤如下:

1. 通过CameraKit.getInstance(Context context)方法获取唯一的CameraKit对象

private void openCamera(){
    // 获取CameraKit对象
    CameraKit cameraKit = CameraKit.getInstance(getApplicationContext());
    if (cameraKit == null) {
        // 处理cameraKit获取失败的情况 
    }
}

如果此步骤操作失败,相机可能被占用或无法使用。如果被占用,必须等到相机释放后才能重新获取CameraKit对象。

2. 通过getCameraIds()方法,获取当前使用的设备支持的逻辑相机列表。逻辑相机列表中存储了当前设备拥有的所有逻辑相机ID,如果列表不为空,则列表中的每个ID都支持独立创建相机对象;否则,说明正在使用的设备无可用的相机,不能继续后续的操作。

try {
    // 获取当前设备的逻辑相机列表
    String[] cameraIds = cameraKit.getCameraIds();
    if (cameraIds.length <= 0) {
        HiLog.error(LABEL, "cameraIds size is 0");
    }
} catch (IllegalStateException e) {
    // 处理异常
}

还可以继续查询指定相机ID的静态信息:

调用getDeviceLinkType​(String physicalId)方法获取物理相机连接方式;

调用getCameraInfo(String cameraId)方法查询相机硬件朝向等信息;

调用getCameraAbility(String cameraId)方法查询相机能力信息(比如支持的分辨率列表等)。

CameraInfo的主要接口

接口名

描述

getDeviceLinkType​(String physicalId)

获取物理相机连接方式。

getFacingType​()

获取相机朝向信息。

getLogicalId​()

获取逻辑相机ID。

getPhysicalIdList​()

获取对应的物理相机ID列表。

CameraAbility的主要接口

接口名

描述

getSupportedSizes​(int format)

根据格式查询输出图像的分辨率列表。

getSupportedSizes​(Class<T> clazz)

根据Class类型查询分辨率列表。

getParameterRange​(ParameterKey.Key<T> parameter)

获取指定参数能够设置的值范围。

getPropertyValue​(PropertyKey.Key<T> property)

获取指定属性对应的值。

getSupportedAeMode​()

获取当前相机支持的自动曝光模式。

getSupportedAfMode​()

获取当前相机支持的自动对焦模式。

getSupportedFaceDetection​()

获取相机支持的人脸检测类型范围。

getSupportedFlashMode​()

当前相机支持的闪光灯取值范围。

getSupportedParameters​()

当前相机支持的参数设置。

getSupportedProperties​()

获取当前相机的属性列表。

getSupportedResults​()

获取当前相机支持的参数设置可返回的结果列表。

getSupportedZoom​()

获取相机支持的变焦范围。

3. 通过createCamera(String cameraId, CameraStateCallback callback, EventHandler handler)方法,创建相机对象,此步骤执行成功意味着相机系统的硬件已经完成了上电。

// 前置相机类型
int frontCamera = CameraInfo.FacingType.CAMERA_FACING_FRONT;
// 后置相机类型
int backCamera = CameraInfo.FacingType.CAMERA_FACING_BACK;
// 其他相机类型
int otherCamera = CameraInfo.FacingType.CAMERA_FACING_OTHERS;

// 选择想要创建的相机类型,如果不存在该类型相机,则返回false
boolean isCameraCreated = openCameraByFacingType(frontCamera);
// 根据类型创建相机的方法
private boolean openCameraByFacingType(int facingType) {
    CameraKit cameraKit = CameraKit.getInstance(getApplicationContext());
    for(String cameraId : cameraKit.getCameraIds()) {
        CameraInfo cameraInfo = cameraKit.getCameraInfo(cameraId);
        if(facingType == cameraInfo.getFacingType()) {
            cameraKit.createCamera(cameraId, cameraStateCallback, eventHandler);
            return true;
        }
    }
    return false;
}

参数cameraId可以是上一步获取的逻辑相机列表中的任何一个相机ID。

第二和第三个参数负责相机创建和相机运行时的数据和状态检测,请务必保证在整个相机运行周期内有效。

private final class CameraStateCallbackImpl extends CameraStateCallback {
    @Override
    public void onCreated(Camera camera) {
         // 创建相机设备
    }
 
    @Override
    public void onConfigured(Camera camera) {
        // 配置相机设备
    }

    @Override
    public void onPartialConfigured(Camera camera) {
        // 当使用了addDeferredSurfaceSize配置了相机,会接到此回调
    }

    @Override
    public void onReleased(Camera camera) { 
       // 释放相机设备
    }
}
 
// 相机创建和相机运行时的回调
CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl();
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
 
// 执行回调的EventHandler
EventHandler eventHandler = new EventHandler(EventRunner.create("CameraCb"));

至此,相机设备的创建已经完成。相机设备创建成功会在CameraStateCallback中触发onCreated(Camera camera)回调。在进入相机设备配置前,请确保相机设备已经创建成功。否则会触发相机设备创建失败的回调,并返回错误码,需要进行错误处理后,重新执行相机设备的创建。

相机设备配置

创建相机设备成功后,在CameraStateCallback中会触发onCreated(Camera camera)回调,并且带回Camera对象,用于执行相机设备的操作。

当一个新的相机设备成功创建后,首先需要对相机进行配置,调用configure(CameraConfig)方法实现配置。相机配置主要是设置预览、拍照、录像用到的Surface(详见ohos.agp.graphics.Surface),没有配置过Surface,相应的功能不能使用。

为了进行相机帧捕获结果的数据和状态检测,还需要在相机配置时调用setFrameStateCallback(FrameStateCallback, EventHandler)方法设置帧回调。

// Surface提供对象
private SurfaceProvider surfaceProvider;

private void initSurface() {
    surfaceProvider = new SurfaceProvider(this);
    DirectionalLayout.LayoutConfig params = new DirectionalLayout.LayoutConfig(     
        ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
    surfaceProvider.setLayoutConfig(params);    
    surfaceProvider.pinToZTop(false);
    surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack());
    ((ComponentContainer) 
        findComponentById(ResourceTable.Id_surface_container)).addComponent(surfaceProvider);
}

private FrameStateCallback frameStateCallbackImpl = new FrameStateCallback(){
    @Override    
    public void onFrameStarted(Camera camera, FrameConfig frameConfig, long frameNumber, long timestamp) {
        ...    
    }
    @Override
    public void onFrameProgressed(Camera camera, FrameConfig frameConfig, FrameResult frameResult) {
        ...
    }
    @Override
    public void onFrameFinished(Camera camera, FrameConfig frameConfig, FrameResult frameResult) {
        ...
    }
    @Override
    public void onFrameError(Camera camera, FrameConfig frameConfig, int errorCode, FrameResult frameResult) {
        ...
    }
    @Override
    public void onCaptureTriggerStarted(Camera camera, int captureTriggerId, long firstFrameNumber) {
        ...
    }
    @Override
    public void onCaptureTriggerFinished(Camera camera, int captureTriggerId, long lastFrameNumber) {
        ...
    }
    @Override
    public void onCaptureTriggerInterrupted(Camera camera, int captureTriggerId) {
        ...
    }
};

// 相机设备
private Camera cameraDevice;
// 相机预览模板
private Surface previewSurface;
// 相机配置模板
private CameraConfig.Builder cameraConfigBuilder;
// 图像帧数据接收处理对象
private ImageReceiver imageReceiver;

private final class CameraStateCallbackImpl extends CameraStateCallback {
    @Override
    public void onCreated(Camera camera) {
        cameraDevice = camera;
        previewSurface = surfaceProvider.getSurfaceOps().get().getSurface();
        cameraConfigBuilder = camera.getCameraConfigBuilder();
        if (cameraConfigBuilder == null) {
            HiLog.error(LABEL, "onCreated cameraConfigBuilder is null");
            return;
        }
        // 配置预览的Surface
        cameraConfigBuilder.addSurface(previewSurface);
        // 配置拍照的Surface
        cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
        // 配置帧结果的回调
        cameraConfigBuilder.setFrameStateCallback(frameStateCallbackImpl, eventHandler);
        try {
            // 相机设备配置
            camera.configure(cameraConfigBuilder.build());
        } catch (IllegalArgumentException e) {
            HiLog.error(LABEL, "Argument Exception");
        } catch (IllegalStateException e) {
            HiLog.error(LABEL, "State Exception");
        }
    }
}

相机配置成功后,在CameraStateCallback中会触发onConfigured(Camera camera)回调,然后才可以执行相机帧捕获相关的操作。

 CameraConfig.Builder的主要接口

接口名

描述

addSurface​(Surface surface)

相机配置中增加Surface。

build​()

相机配置的构建类。

removeSurface​(Surface surface)

移除先前添加的Surface。

setFrameStateCallback​(FrameStateCallback callback, EventHandler handler)

设置用于相机帧结果返回的FrameStateCallback和Handler。

addDeferredSurfaceSize(Size surfaceSize, Class<T> clazz)

添加延迟Surface的尺寸、类型。

addDeferredSurface(Surface surface)

设置延迟的Surface,此Surface的尺寸和类型必须和使用addDeferredSurfaceSize配置的一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/672259.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为OD机试之按单词下标区间翻转文章内容(Java源码)

文章目录 按单词下标区间翻转文章内容题目描述输入描述输出描述示例代码 按单词下标区间翻转文章内容 题目描述 给定一段英文文章片段&#xff0c;由若干单词组成&#xff0c;单词间以空格间隔&#xff0c;单词下标从0开始。 请翻转片段中指定区间的单词顺序并返回翻转后的内…

芯片工程师求职题目之设计基础篇(1)

1. 进制转换 会算数值在二进制、八进制、十进制以及十六进制之间的任意转换。 会算数值的正码、反码、补码、BCD码。 2. 什么是格雷码(Gray code)&#xff0c;它有什么优点。 在一组二进制编码中&#xff0c;若任意两个相邻的数值还有1位二进制数不同&#xff0c;则称这种编…

算法程序设计 之 最长公共子序列(4/8)

一、实验目的&#xff1a; 理解并掌握动态规划算法的基本思想和设计步骤。 实验内容若给定序列X{x1,x2,...,xm},Z{z1,z2,...,zk},若Z是X的子序列&#xff0c;当且仅当存在一个严格递增下标序列{i1,...,ik}&#xff0c;使得对于所有j1,2,...,k有&#xff1a;zjxij。例如&#x…

智能家居APP软件开发有何优势?

传统家居行业营销模式已经无法满足现代人多样化个性化的需求&#xff0c;也跟不上互联网时代的发展步伐了&#xff0c;很多传统家居行业都陷入了营销困境。通过智能家居APP软件开发&#xff0c;可以利用互联网改造传统模式&#xff0c;探索新的发展模式&#xff0c;可以说智能家…

Bootstrap 简介

文章目录 Bootstrap 简介什么是 Bootstrap&#xff1f;Bootstrap 包的内容Bootstrap 实例 Bootstrap 简介 什么是 Bootstrap&#xff1f; Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架。Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的。 历史 Bootstrap 是由 Twi…

【软件测试知识】什么是持续集成?

持续集成是一种 DevOps 软件开发实践。采用持续集成时&#xff0c;开发人员会定期将代码变更合并到一个中央存储库中&#xff0c;之后系统会自动运行构建和测试操作。持续集成通常是指软件发布流程的构建或集成阶段&#xff0c;需要用到自动化组件&#xff08;例如 CI 或构建服…

EasyUI表格增加筛选和导出的方法

一、前言 最近写前端页面&#xff0c;要从后台查询表格数据&#xff1b; 查到数据后&#xff0c;就想增加个数据筛选功能&#xff0c;如果再查后台的话会影响效率&#xff08;还得加参数、再调用后台接口、后台再执行sql&#xff09;&#xff0c;就想前端能不能自己筛选下已经…

车载以太网 - 传输层 - TCP通信过程

目录 TCP 通信阶段 1、连接建立Connection establishment 2、数据传输 Data transfer 3、连接释放 Connection release TCP通信的三个阶段: TCP连接&#xff08;三次握手&#xff09; 1、Client(ECUA) -> Server(ECU B)第一次握手 2、Server -> Client 第二次握手…

软件工程基础速通教程(北京理工大学)

文章目录 前言软工上课情况考后感题型分析概念部分大题部分数据流图和数据字典数据流图数据字典 结构化设计工具程序流程图盒图&#xff08;N-S图&#xff09;PAD图判定表和判定树PDL&#xff08;伪码&#xff09; 软件测试白盒测试法语句覆盖判定覆盖&#xff0c;条件覆盖&…

【MMDetection3.0】训练自己的数据集

本文记录下MMDetection3.0版本&#xff0c;即截至目前最新的版本&#xff0c;训练自定义数据集的过程。当前MMDetection已经封装的很好了&#xff0c;虽然易于使用&#xff0c;但其API也愈发复杂&#xff0c;对于新手不太友好&#xff0c;这里记录下自己的踩坑经历。 数据部分…

5.英语词性之副词

五.什么是副词 副词是修饰动词&#xff0c;形容词&#xff0c;副词的词语&#xff0c;有时也可以修饰数词&#xff0c;介词&#xff0c;连词&#xff0c;名词或全 句。副词是表示行为或状态特征的词&#xff0c;主要作状语&#xff0c;也可以作表语&#xff0c;定语&#xff0c…

音视频开发:Qt在视频剪辑3D桌面软件获胜, 嵌入式不敌安卓

1 Qt Android嵌入式应用层开发方向对比 大家都知道啊&#xff0c;做嵌入式linux设备&#xff0c;一些没有屏幕&#xff0c;比如安防摄像头&#xff0c;门铃之类的&#xff0c;另外一些嵌入式设备是有触控屏&#xff0c;在触控屏上还跑应用软件的&#xff0c;这种比如商场各种…

citywalk话题增长704.76%,小红书本地化内容营销怎么玩?

2023年初发布的《2023小红书年度生活趋势&#xff1a;投入真实生活》报告中提到&#xff0c;今后年轻人会更加意识到周围和附近的重要性&#xff0c;在十大生活趋势预测中&#xff0c;近邻升温&#xff08;2022年相关笔记数量同比上涨213%&#xff09;、野到家门口&#xff08;…

建立小型医学数据库(总结)

建立小型医学数据库 小型医学数据库可以用于存储和管理医学数据&#xff0c;如患者病历、药品信息、试验结果等。这对于医疗机构和科研机构来说非常必要&#xff0c;可以提高数据管理和共享的效率&#xff0c;进而促进医学研究和诊疗水平的提升。 建立小型医学数据库有以下基本…

转发和重定向的区别及其原理

在web应用中完成资源的跳转 在一个web应用中完成资源的跳转可以通过转发或者重定向两种方式, 跳转的资源只要是服务器内部合法的资源即可(如Servlet、JSP、HTML…) 转发机制使用场景: 某个Servlet向request域当中绑定了数据&#xff0c;希望从其他Servlet当中把request域里面…

【Python】Django 基础知识

系列文章目录 提示&#xff1a;阅读本章之前&#xff0c;请先阅读目录 文章目录 系列文章目录前言安装启动项目查看所有子命令主要文件setting 配置项URL 请求路径path 转换器HttpResponse 输出中文乱码models的objects代码自动补全views的request 代码自动补全views的request.…

沃尔玛、亚马逊跨境电商如何实现自养账号采退、海淘及测评的

今天曹哥还是针对下亚马逊、沃尔玛跨境平台如何实现自己养买家号可以给自己采购、海淘及测评等技术问题 首先你要有一个稳定的环境方案&#xff0c;这个是做自养号采购、海淘及测评的基础。环境有很多&#xff0c;从早期的虚拟机&#xff0c;模拟机&#xff0c;云手机&#xf…

[进阶]Java:IO流分类、文件字节输入流、读取字节数据、避免乱码问题

IO流概述 I表示intput&#xff0c;是数据从硬盘文件读入到内存的过程&#xff0c;称之输入&#xff0c;负责读。O表示output&#xff0c;是内存程序的数据从内存到写出到硬盘文件的过程&#xff0c;称之输出&#xff0c;负责写。 IO流的分类 按流的方向分 按流中的数据最小单…

树状数组(入门附模板)

声明&#xff1a;本篇文章图片非原创 目录 简介 lowbit函数 结构分析 单点修改,区间查询 区间修改,单点查询 区间修改,区间查询 模板题 树状数组1–单点修改,区间查询 题目描述 输入格式 输出格式 输入输出样例 输入 #1 输出 #1 说明/提示 分析 代码 树状数…

移动机器人路径优化:基于Q-learning算法的移动机器人路径优化(提供MATLAB代码)

一、Q-learning算法 Q-learning算法是强化学习算法中的一种&#xff0c;该算法主要包含&#xff1a;Agent、状态、动作、环境、回报和惩罚。Q-learning算法通过机器人与环境不断地交换信息&#xff0c;来实现自我学习。Q-learning算法中的Q表是机器人与环境交互后的结果&#…