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

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配置的一致。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

20分钟做一套采购审批系统

1、设计输入模板 excel画表格界面 # 公式代表新建时以默认值代替 2、设置单元格为签名控件 双击单元格后&#xff0c;会默认显示当前用户的信息,用于签名 3、设置要合计的数据 生成的合计公式会默认放到下一行 4、设置单元格的ID与标题&#xff0c;在添加或者删除行或者列时&am…

GEE:为每个对象(斑块/超像素)添加属性

作者:CSDN @ _养乐多_ 本文将介绍为每个对象(斑块/超像素)添加属性的代码。并举例将最近距离作为属性添加到每个对象(斑块/超像素)特征中。 结果如下图所示, 文章目录 一、代码二、代码链接一、代码 这段代码的目的是对动态世界土地覆盖图像进行分析,并提取出其中的目…

第九章 ShuffleNetv1网络详解

系列文章目录 第一章 AlexNet网络详解 第二章 VGG网络详解 第三章 GoogLeNet网络详解 第四章 ResNet网络详解 第五章 ResNeXt网络详解 第六章 MobileNetv1网络详解 第七章 MobileNetv2网络详解 第八章 MobileNetv3网络详解 第九章 ShuffleNetv1网络详解 第十章…

React之state详解

目录 执行过程 异步 React18与自动批处理 setState 推荐用法 ()>{return }&#xff0c;this.state. 生命周期 数据没改变时​不渲染 shouldComponentUpdate PureComponent自动&#xff08;推荐&#xff09; 你真的理解setState吗&#xff1f; - 掘金 组件的私有…

如何在Microsoft Excel中使用LEN函数

如果你曾经想尝试查找一行文本中的字符数&#xff0c;你可以使用Microsoft Excel来查找&#xff0c;这要归功于LEN函数。以下是如何使用它。 一、什么是 LEN 函数 LEN函数是一个简单的计算函数&#xff0c;用于计算给定文本字符串中的所有字符&#xff0c;包括数字、字母、特…

内网安全:内网穿透详解

目录 内网穿透技术 内网穿透原理 实验环境 内网穿透项目 内网穿透&#xff1a;Ngrok 配置服务端 客户端配置 客户端生成后门&#xff0c;等待目标上线 内网穿透&#xff1a;Frp 客户端服务端建立连接 MSF生成后门&#xff0c;等待上线 内网穿透&#xff1a;Nps 服…

三、Docker命令及基本使用

学习参考&#xff1a;尚硅谷Docker实战教程、Docker官网、其他优秀博客(参考过的在文章最后列出) 目录 前言一、帮助启动类命令1.1 启动docker1.2 停止docker1.3 重启docker1.4 查看docker状态1.5 开机启动1.6 查看docker概要信息1.7 查看docker总体帮助文档1.8 查看docker命令…

autoDL上A100运行wiki出错:NVIDIA A100-PCIE-40GB(最后安装好torch+dgl了);学校服务器加2.X版本pytorch

1、A100运行wiki出错&#xff1a;NVIDIA A100-PCIE-40GB with CUDA capability sm_80 is not compatible with the current PyTorch installation. The current PyTorch install supports CUDA capabilities sm_37 sm_50 sm_60 sm_70. If you want to use the NVIDIA A100-PCIE…

题集-栈和队列的相互转化

这里&#xff0c;队列的性质是先入先出&#xff0c;但是栈的性质是后入先出。两个队列就可以通过相互捯实现数据的后入先出。 typedef int QDataType&#xff1b; //这是一个队列结点的结构 typedef struct QueueNode { struct QueueNode* next; QDataType data; }QNode; //这是…

常见面试题之MySQL篇

1.MySQL中&#xff0c;如何定位慢查询? 我们当时做压测的时候有的接口非常的慢&#xff0c;接口的响应时间超过了2秒以上&#xff0c;因为我们当时的系统部署了运维的监控系统Skywalking&#xff0c;在展示的报表中可以看到是哪一个接口比较慢&#xff0c;并且可以分析这个接…

ChatGPT在前,华为盘古Chat在后

国产盘古Chat对话方面堪比GPT-3.5 什么是ChatGPT&#xff1f;简单来说&#xff0c;就是一个能够和人类自然对话的人工智能系统。它可以理解你的语言&#xff0c;回答你的问题&#xff0c;甚至给你提供建议和服务。它不仅可以处理文字&#xff0c;还可以处理图片、视频、音频等…

Web3 是什么?为何应该关注?

当我开始我的职业生涯时&#xff0c;“Web2.0”还是一个热门的新事物。 当我开始我的职业生涯时&#xff0c;正值互联网快速发展的时期&#xff0c;人们谈论的是“Web2.0”&#xff0c;这一概念引发了许多关于用户参与、社交媒体和在线合作的讨论。然而&#xff0c;随着时间的推…

DataStructure01|ArrayList和顺序表

ArrayList与顺序表 1.线性表 ​ 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列… ​ 线性表在逻辑上是线性结构&#xff0c;也就说…

掌握Python的X篇_4_开发工具ipython与vscode的安装使用

本篇将会介绍两个工具的安装及使用来提高Python的编程效率。 ipython&#xff1a;比python更好用的交互式开发环境vscode&#xff1a;本身是文本编辑器&#xff0c;通过安装相关的插件vscode可以作为python集中开发环境使用 掌握Python的X篇_4_开发工具ipython与vscode的安装使…

ChatGPT/GPT-4 或将从根本上改变软件工程

文章目录 一、前言二、主要内容 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 编程也可能是最容易被 AI 技术取代的工作之一&#xff0c;软件的构建方式将产生根本性的转变。 今年以来&#xff0c;相信大家都听说过 ChatGPT、New Bing 和…

Java try-catch块

Java的try块用于封装可能会抛出异常的代码。它必须在方法内部使用。 如果在try块中的特定语句处发生异常&#xff0c;后续的代码块将不会执行。因此&#xff0c;建议不要在try块中放置不会抛出异常的代码。 Java的try块必须后跟catch块或finally块。 Java try-catch语法 try…

chatgpt赋能python:Python绘制车辆轨迹图

Python绘制车辆轨迹图 在现代交通中&#xff0c;车辆轨迹图是一个广泛应用的技术&#xff0c;它可以被用于道路交通管理&#xff0c;行车安全评估等领域。Python是一种强大的编程语言&#xff0c;它提供了许多绘制数据可视化图表的库。本文将介绍如何使用Python和Matplotlib库…

Git的使用方法

文章目录 Git简介Git用法上传到gitee上 Git简介 简单来说&#xff0c;Git就像一个日志一样&#xff0c;可以帮你记录你对文本文件的修改&#xff0c;但他的功能又强于日志&#xff0c;不仅可以记录&#xff0c;还可以帮你存储那些你对文本文件的修改&#xff0c;当你想要找回之…

ArcGis系列-坐标系转换

Arcgis的工程项目可以添加各种类型的空间资源&#xff0c;比如数据库空间表、shp文件&#xff0c;每张空间表的坐标系可能都会有差异&#xff0c;把他们放到一个工程里时可以统一设置坐标系。 本文将介绍ArcGis三个需要坐标转换的场景&#xff1a; Arcgis Pro设置项目坐标GP分…

论文笔记--GPT-4 Technical Report

论文笔记--GPT-4 Technical Report 1. 报告简介2. 报告概括3 报告重点内容3.1 Predictable Scaling3.2 Capabilities3.3 limitations3.3 Risks & mitigations 4. 报告总结5. 报告传送门6. References 1. 报告简介 标题&#xff1a;GPT-4 Technical Report作者&#xff1a;…