diff --git a/AppScope/app.json5 b/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a315d7cda24c9a9419a9c7c6b79cf1f0bd5afc4d --- /dev/null +++ b/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.sample.camera", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/AppScope/resources/base/element/string.json b/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..28a55ddb65354e29174945a7afb0339a9e119969 --- /dev/null +++ b/AppScope/resources/base/element/string.json @@ -0,0 +1,216 @@ +{ + "string": [ + { + "name": "app_name", + "value": "CameraSample" + }, + { + "name": "CONTENT_TYPE_UNKNOWN", + "value": "未知类型" + }, + { + "name": "ALLOW_WLAN", + "value": "允许“相机”使用无线数据?" + }, + { + "name": "reason", + "value": "保存图片" + }, + { + "name": "CLOSE_WLAN", + "value": "关闭无线数据时,部分功能可能无法使用。" + }, + { + "name": "WLAN_AND_CELLULAR", + "value": "无线局域网与蜂窝网络" + }, + { + "name": "ONLY_WLAN", + "value": "仅限无限局域网" + }, + { + "name": "NOT_ALLOW", + "value": "不允许" + }, + { + "name": "SETTING", + "value": "设置" + }, + { + "name": "SELFIE_IMAGE", + "value": "自拍镜像" + }, + { + "name": "STEADY_VIDEO", + "value": "视频防抖" + }, + { + "name": "EXPOSURE_MODE", + "value": "曝光模式" + }, + { + "name": "FOCUS_MODE", + "value": "对焦模式" + }, + { + "name": "CAPTURE_QUALITY", + "value": "拍摄质量" + }, + { + "name": "DISPLAY_LOCATION", + "value": "拍摄时显示地理位置" + }, + { + "name": "PHOTO_FORMAT", + "value": "照片格式" + }, + { + "name": "PHOTO_DIRECTION_CONFIGURATION", + "value": "照片方向配置" + }, + { + "name": "PHOTO_RESOLUTION", + "value": "照片分辨率" + }, + { + "name": "VIDEO_RESOLUTION", + "value": "视频分辨率" + }, + { + "name": "VIDEO_RATE", + "value": "录像帧率" + }, + { + "name": "REFERENCE_LINE", + "value": "参考线" + }, + { + "name": "CLOSE_STEADY_VIDEO", + "value": "关闭视频防抖" + }, + { + "name": "BASIC_ANTI_SHAKE_ALGORITHM", + "value": "基础防抖算法" + }, + { + "name": "GENERAL_ANTI_SHAKE_ALGORITHM", + "value": "一般防抖算法" + }, + { + "name": "BEST_ANTI_SHAKE_ALGORITHM", + "value": "最好防抖算法" + }, + { + "name": "AUTO_SELECT", + "value": "自动进行选择" + }, + { + "name": "LOCK_EXPOSURE_MODE", + "value": "锁定曝光模式" + }, + { + "name": "AUTO_EXPOSURE_MODE", + "value": "自动曝光模式" + }, + { + "name": "CONTINUE_AUTO_EXPOSURE", + "value": "连续自动曝光" + }, + { + "name": "MANUAL_FOCUS", + "value": "手动对焦" + }, + { + "name": "CONTINUE_AUTO_FOCUS", + "value": "连续自动对焦" + }, + { + "name": "AUTO_ZOOM", + "value": "自动变焦" + }, + { + "name": "LOCK_FOCUS", + "value": "对焦锁定" + }, + { + "name": "HIGH", + "value": "高" + }, + { + "name": "MIDDLE", + "value": "中" + }, + { + "name": "BAD", + "value": "差" + }, + { + "name": "SELF_IMAGE_FUNC_ONLY_FRONT_CAMERA_OPEN_USE", + "value": "自拍镜像功能只能在前置摄像头打开时可使用。" + }, + { + "name": "DISPLAY_LOCATION_RECORD_PHOTO_OR_VIDEO_INFO", + "value": "显示地理位置,用于记录照片或视频拍摄地理位置信息。" + }, + { + "name": "OPEN_CAMERA_REFERENCE_LINE_CREATE_BETTER_FRAME", + "value": "打开相机参考线,可以帮你创造出构图更出色的画面。" + }, + { + "name": "PHOTO_FORMAT_PNG", + "value": "PNG" + }, + { + "name": "PHOTO_FORMAT_JPG", + "value": "JPG" + }, + { + "name": "PHOTO_FORMAT_BMP", + "value": "BMP" + }, + { + "name": "PHOTO_FORMAT_WEBP", + "value": "WEBP" + }, + { + "name": "PHOTO_FORMAT_JPEG", + "value": "JPEG" + }, + { + "name": "SRC", + "value": "0" + }, + { + "name": "OVERTURN90", + "value": "90" + }, + { + "name": "OVERTURN180", + "value": "180" + }, + { + "name": "OVERTURN270", + "value": "270" + }, + { + "name": "RESOLUTION1", + "value": "1920*1080" + }, + { + "name": "RESOLUTION2", + "value": "1280*720" + }, + { + "name": "RESOLUTION3", + "value": "640*480" + }, + { + "name": "VIDEO_RATE_15", + "value": "15" + }, + { + "name": "VIDEO_RATE_30", + "value": "30" + } + ] +} \ No newline at end of file diff --git a/AppScope/resources/base/media/app_icon.png b/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/AppScope/resources/base/media/app_icon.png differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..338e5b0bc22082e0ffcc7121c2ed3897a3ddccb0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.en.md b/README.en.md deleted file mode 100644 index bdbae740ca7bf32a375d7c506cb75bd8c94f38e1..0000000000000000000000000000000000000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# CameraDataCollection - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index 5e5c67b68826f927009a5e8b268877cdec3ee00e..042e6056077d98dfac92552ac8ca4f220db4a159 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,104 @@ -# CameraDataCollection +# 相机数据采集保存 -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +### 介绍 -#### 软件架构 -软件架构说明 +本示例主要展示了相机的相关功能,使用libohcamera.so +接口实现相机的预览、拍照、录像、前后置摄像头切换进行拍照、录像,以及对焦、曝光等控制类功能。 +### 效果预览 -#### 安装教程 +| 效果展示 | +|-------------------------------------------| +| ![auth](screenshot/device/ndk_camera.gif) | -1. xxxx -2. xxxx -3. xxxx +使用说明 +1. 弹出是否允许“CameraSample”使用相机?点击“允许” +2. 弹出是否允许“CameraSample”使用麦克风?点击“允许” +3. 弹出是否允许“CameraSample”访问文件?点击“允许” +4. 弹出是否允许“CameraSample”访问图片和视频?点击“允许” +5. 进入预览界面,预览正常,点击画面模糊处,画面会变得清晰,对焦效果明显 +6. 进入预览界面,预览正常,上下滑动屏幕,屏幕场景亮度发生变化,曝光效果明显 +7. 进入预览界面,预览正常,进入拍照模式,点击拍照按钮,拍照正常,左下角会生成照片缩略图,点击左下角缩略图,能够跳转到图库,图片保存正常,打开图片显示正常 +8. 进入预览界面,预览正常,切换到前置摄像头,点击拍照按钮,拍照正常,左下角生成照片缩略图,点击左下角缩略图,能够跳转到图库,图片保存正常,打开图片显示正常 +9. 进入预览界面,预览正常,切换到录像模式,点击录像,开始录像,再点击停止录像按钮,录像成功,左下角会生成视频缩略图,点击左下角缩略图,能够跳转到图库,录像文件保存正常,播放录像文件正常 +10. 进入预览界面,预览正常,切换到后置摄像头,点击录像,开始录像,再点击停止录像按钮,录像成功,左下角会生成视频缩略图,点击左下角缩略图,能够跳转到图库,录像文件保存正常,播放录像文件正常 -#### 使用说明 +### 工程目录 -1. xxxx -2. xxxx -3. xxxx +``` +├──entry/src/main/cpp +│ ├──types +│ │ └──libentry +│ │ ├──index.d.ts // 导入NAPI接口供JS调用 +│ │ └──oh-package.json5 // 接口注册配置文件 +│ ├──camera_manager.cpp // 相机基本功能接口定义cpp实现侧 +│ ├──camera_manager.h // 相机基本功能接口定义 +│ ├──CMakeLists.txt // Cmake打包配置文件,编译工程动态库脚本,依赖头文件、cpp以及相关依赖 +│ └──main.cpp // NAPI实现JS与C++通信的接口 +├──entry/src/main/ets +│ ├──common +│ │ ├──utils +│ │ │ ├──Logger.ets // 日志工具 +│ │ │ └──MediaUtils.ets // 媒体工具 +│ │ ├──Constants.ets // 基本参数枚举:纵横比、设备类型、视频帧数... +│ │ └──DisplayCalculator.ets // 计算界面宽高显示数值 +│ ├──entryability +│ │ └──EntryAbility.ets // Ability的生命周期回调内容 +│ ├──pages +│ │ └──Index.ets // Ability实现的应用的入口页面,相机APP首页 +│ └──views +│ ├──DividerPage.ets // 分割线UI布局 +│ ├──FocusAreaPage.ets // 对焦区域设置(焦点、侧光点)、单指竖直方向拖动触发曝光补偿设置 +│ ├──FocusPage.ets // 对焦、曝光、刻度的图标设置、值的设置 +│ └──ModeSwitchPage.ets // 相机功能模式切换,开启预览、拍照、录像 +└──entry/src/main/resources // 应用资源目录 -#### 参与贡献 +``` -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +### 具体实现 +* 相机功能接口实现在CameraManager.cpp中,源码参考:[CameraManager.cpp](entry/src/main/cpp/CameraManager.cpp) + * 在NDKCamera构造函数里完成一个相机生命周期初始化的过程,包括调用OH_Camera_GetCameraMananger获取CameraMananger,调用OH_CameraManager_CreateCaptureSession创建CaptureSession,调用CaptureSessionRegisterCallback创建CaptureSession注册回调,调用GetSupportedCameras获取支持的camera设备,调用GetSupportedOutputCapability获取支持的camera设备能力集,调用CreatePreviewOutput创建预览输出,调用CreateCameraInput创建相机输入,调用CameraInputOpen打开相机输入,调用CameraManagerRegisterCallback创建CameraManager注册回调,最后调用SessionFlowFn开启Session。 + * 其中SessionFlowFn是一个开启预览的动作,主要流程包括:调用OH_CaptureSession_BeginConfig开始配置会话,调用OH_CaptureSession_AddInput把CameraInput加入到会话,调用OH_CaptureSession_AddPreviewOutput把previewOutput加入到会话,调用OH_CaptureSession_CommitConfig提交配置信息,调用OH_CaptureSession_Start开始会话工作,还有一步是在开启预览的同时调用IsFocusMode启动对焦功能,这边后面会涉及到。 + * 在NDKCamera析构函数里完成对相机生命周期释放的过程,调用OH_CameraManager_DeleteSupportedCameras删除支持的camera设备,调用OH_CameraManager_DeleteSupportedCameraOutputCapability删除支持的camera设备能力集,调用OH_Camera_DeleteCameraManager删除camera manager。 + * 拍照功能相关接口封装在StartPhoto接口中,主要包含以下流程:调用SessionStop关闭session,调用SessionBegin做session的一个预置动作,调用CreatePhotoOutput创建相机输出,调用OH_CaptureSession_AddPhotoOutput将hotoOutput添加至session中,调用SessionCommitConfig提交session,在调用SessionStart开启session,最后调用TakePicture接口开启拍照动作。 + * 录像功能相关接口封装在StartVideo接口中,主要包含以下流程:调用SessionStop关闭session,调用SessionBegin做session的一个预置动作,调用OH_CaptureSession_RemovePhotoOutput移除相机拍照输出,再调用CreatePhotoOutput创建相机输出,调用AddPhotoOutput将相机输出添加至session中,调用CreateVideoOutput创建录像输出,调用AddVideoOutput将录像输出添加至session中,然后再调用SessionCommitConfig、SessionStart对session进行提交和开启,最后调用VideoOutputRegisterCallback对VideoOutput注册回调。 + * 曝光功能相关接口封装在IsExposureModeSupportedFn接口中,主要包含以下流程:调用OH_CaptureSession_IsExposureModeSupported判断是否支持曝光模式,然后调用OH_CaptureSession_SetExposureMode设置曝光模式,调用OH_CaptureSession_GetExposureMode获取设置后的曝光模式。调用IsExposureBiasRange接口获取曝光补偿,其中包含调用OH_CaptureSession_GetExposureBiasRange获取曝光补偿的范围,调用OH_CaptureSession_SetExposureBias设置曝光点,调用OH_CaptureSession_GetExposureBias获取曝光点。 + * 对焦功能相关接口封装在IsFocusMode接口中,主要包含以下流程:调用OH_CaptureSession_IsFocusModeSupported判断是否支持对焦模式,调用OH_CaptureSession_SetFocusMode设置对焦模式,调用OH_CaptureSession_GetFocusMode获取设置后的对焦模式。 + * 调用IsFocusPoint接口获取对焦点,其中包括调用OH_CaptureSession_SetFocusPoint获取JS侧下发来的对焦点位,然后调用OH_CaptureSession_GetFocusPoint获取设置后的对焦点位。 + * 视频防抖功能相关接口封装在IsVideoStabilizationModeSupportedFn接口中,主要包含以下流程:调用OH_CaptureSession_IsVideoStabilizationModeSupported接口查询是否支持指定的视频防抖模式,调用OH_CaptureSession_SetVideoStabilizationMode设置视频防抖,调用OH_CaptureSession_GetVideoStabilizationMode获取设置后的视频防抖模式。 + * 回调接口设置: + * CameraManagerRegisterCallback:监听相机状态回调,在打开、退出相机,相机摄像头切换时会触发 + * CameraInputRegisterCallback:相机输入发生错误时触发回调 + * PhotoOutputRegisterCallback:开启拍照时触发回调 + * VideoOutputRegisterCallback:开启录像模式时触发回调 + * CaptureSessionRegisterCallback:session出现异常时以及开启对焦模式时触发回调 -#### 特技 +* 相机预览、拍照、录像功能、前后置切换功能实现调用侧位于tableIndex.ets,modeSwitchPage.ets,main.cpp中,源码参考:[Index.ets](entry/src/main/ets/pages/Index.ets),[ModeSwitchPage.ets](entry/src/main/ets/views/ModeSwitchPage.ets),[main.cpp](entry/src/main/cpp/main.cpp) + * 预览:开启预览位于Index.ets下的onPageShow接口,其中调用cameraDemo.initCamera接口,将预览的surfaceId,对焦模式的值,以及是前置还是后置摄像头设备作为入参啊传下去,实际调用的是main.cpp下的InitCamera接口,InitCamera接口将JS侧拿到的参数进行转换再传入cameraManager.cpp中的构造函数里去,完成开启相机的操作,开启预览并设置好对焦模式。 + * 拍照和录像:开启拍照位于ModeSwitchPage.ets下的isVideoPhotoFn接口,通过判断modelBagCol的值是photo还是video,将modelBagCol的值,videoId,拍照的surfaceID或者录像的surfaceId传入接口startPhotoOrVideo。如果是拍照模式,则通过modeSwitchPage.ets下的getPhotoSurfaceID接口获取photo surfaceId,跳转到main.cpp中的StartPhotoOrVideo接口,将传下来的参数进行格式转换,再调用CameraManager对象下的StartPhoto接口开启拍照操作;如果是录像模式,则通过modeSwitchPage.ets下的getVideoSurfaceID接口获取video surfaceId,跳转到main.cpp中的StartPhotoOrVideo接口,将传下来的参数进行格式转换,再调用CameraManager对象下的StartVideo接口开启录像操作 + * 前后置切换:前后置摄像头切换接口位于ModeSwitchPage.ets,切换cameraDeviceIndex,将先前的session配置释放,调用cameraDemo.releaseSession接口,实际上是main.cpp下的ReleaseSession接口,最终调用到CameraMangaer.cpp下的ReleaseSession接口。然后将预览的surfaceId,对焦模式的值以及cameraDeviceIndex传入cameraDemo.initCamera接口中,逻辑和预览一致。 -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +* 相机对焦、曝光功能实现调用侧位于FocusAreaPage.ets中,源码参考:[FocusAreaPage.ets](entry/src/main/ets/views/FocusAreaPage.ets) + * 对焦:对焦功能位于FocusAreaPage.ets,通过在build中将对焦焦点下发到cpp侧,在CameraManager.cpp文件中的SessionFlowFn函数中,会调用IsFocusMode接口来判断是否支持对焦模式,然后通过onTouch的方式将对焦点位通过cameraDemo.isFocusPoint接口下发到main.cpp侧的IsFocusPoint接口,最终调到CameraManager.cpp中的IsFocusPoint接口。以及调用OH_CaptureSession_SetFocusMode拿到对焦点位来设置对焦模式,最后调用OH_CaptureSession_GetFocusMode来获取对焦模式,完成对焦功能实现。 + * 曝光:曝光功能位于FocusAreaPage.ets,通过在build中将侧光点位下发到cpp侧,然后通过onTouch的方式将对焦点位以及侧光点位通过cameraDemo.isFocusPoint接口下发到main.cpp侧的isMeteringPoint接口,最终调到CameraManager.cpp中的IsMeteringPoint接口。然后设置曝光补偿,单指竖直方向拖动触发该手势事件,调用gesture中的cameraDemo.isExposureBiasRange接口将曝光值下发到main.cpp中的IsExposureBiasRange,然后经过napi转换后将值传到CameraManager.cpp中的IsExposureBiasRange接口,之后从native侧发到曝光补偿的范围,再调用OH_CaptureSession_SetExposureBias设置曝光值,最后调用OH_CaptureSession_GetExposureBias接口获取曝光值,完成曝光功能。 + +### 相关权限 + +* ohos.permission.CAMERA +* ohos.permission.MICROPHONE +* ohos.permission.READ_MEDIA +* ohos.permission.WRITE_MEDIA +* ohos.permission.READ_IMAGEVIDEO +* ohos.permission.WRITE_IMAGEVIDEO + +### 依赖 + +不涉及 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 +2. HarmonyOS系统:HarmonyOS NEXT Developer Beta1及以上。 +3. DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。 +4. HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。 \ No newline at end of file diff --git a/build-profile.json5 b/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c033ce4278fb0641d84107c3c134047ac487368e --- /dev/null +++ b/build-profile.json5 @@ -0,0 +1,35 @@ +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.0(12)", + "runtimeOS": "HarmonyOS", + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/entry/build-profile.json5 b/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..646c44cda3f4e80a63c9a89281325965080b2cf9 --- /dev/null +++ b/entry/build-profile.json5 @@ -0,0 +1,39 @@ +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + "nativeLib": { + "debugSymbol": { + "strip": true, + "exclude": [] + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/entry/hvigorfile.ts b/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6edcd90486dd5a853cf7d34c8647f08414ca7a3 --- /dev/null +++ b/entry/hvigorfile.ts @@ -0,0 +1,6 @@ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/entry/obfuscation-rules.txt b/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..985b2aeb7658286b17bd26eab8f217c3fe75ea8b --- /dev/null +++ b/entry/obfuscation-rules.txt @@ -0,0 +1,18 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope \ No newline at end of file diff --git a/entry/oh-package.json5 b/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..54cb066266f9993f5a023f2ac5a8dfc5d2574643 --- /dev/null +++ b/entry/oh-package.json5 @@ -0,0 +1,11 @@ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "libentry.so": "file:./src/main/cpp/types/libentry" + } +} \ No newline at end of file diff --git a/entry/src/main/cpp/CMakeLists.txt b/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1428e71d44400c759d88172d0f5fb850fcb9806 --- /dev/null +++ b/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,16 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.4.1) +project(CameraSample) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +if(DEFINED PACKAGE_FIND_FILE) + include(${PACKAGE_FIND_FILE}) +endif() + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include) + + +add_library(entry SHARED main.cpp camera_manager.cpp) +target_link_libraries(entry PUBLIC libohcamera.so libace_napi.z.so libnative_buffer.so libhilog_ndk.z.so librawfile.z.so) \ No newline at end of file diff --git a/entry/src/main/cpp/camera_manager.cpp b/entry/src/main/cpp/camera_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd4f4d2f6253f226f502cfc9ea615519da822f87 --- /dev/null +++ b/entry/src/main/cpp/camera_manager.cpp @@ -0,0 +1,873 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hilog/log.h" +#include "camera_manager.h" + +namespace OHOS_CAMERA_SAMPLE { +std::mutex NDKCamera::mtx_; + +NDKCamera::NDKCamera(char *str, uint32_t focusMode, uint32_t cameraDeviceIndex) + : previewSurfaceId_(str), cameras_(nullptr), focusMode_(focusMode), cameraDeviceIndex_(cameraDeviceIndex), + cameraOutputCapability_(nullptr), cameraInput_(nullptr), captureSession_(nullptr), size_(0), + isCameraMuted_(nullptr), profile_(nullptr), photoSurfaceId_(nullptr), previewOutput_(nullptr), + photoOutput_(nullptr), metaDataObjectType_(nullptr), metadataOutput_(nullptr), isExposureModeSupported_(false), + isFocusModeSupported_(false), exposureMode_(EXPOSURE_MODE_LOCKED), minExposureBias_(0), maxExposureBias_(0), + step_(0), ret_(CAMERA_OK) { + valid_ = false; + ReleaseCamera(); + Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager_); + if (cameraManager_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Get CameraManager failed."); + } + + ret = OH_CameraManager_CreateCaptureSession(cameraManager_, &captureSession_); + if (captureSession_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Create captureSession failed."); + } + CaptureSessionRegisterCallback(); + GetSupportedCameras(); + GetSupportedOutputCapability(); + CreatePreviewOutput(); + CreateCameraInput(); + CameraInputOpen(); + CameraManagerRegisterCallback(); + SessionFlowFn(); + valid_ = true; +} + +NDKCamera::~NDKCamera() { + valid_ = false; + OH_LOG_INFO(LOG_APP, "~NDKCamera"); + Camera_ErrorCode ret = CAMERA_OK; + + if (cameraManager_) { + OH_LOG_INFO(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameraOutputCapability. enter"); + ret = OH_CameraManager_DeleteSupportedCameraOutputCapability(cameraManager_, cameraOutputCapability_); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Delete CameraOutputCapability failed."); + } else { + OH_LOG_INFO(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameraOutputCapability. ok"); + } + + OH_LOG_INFO(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameras. enter"); + ret = OH_CameraManager_DeleteSupportedCameras(cameraManager_, cameras_, size_); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); + } else { + OH_LOG_INFO(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameras. ok"); + } + + ret = OH_Camera_DeleteCameraManager(cameraManager_); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Delete CameraManager failed."); + } else { + OH_LOG_INFO(LOG_APP, "Release OH_Camera_DeleteCameraManager. ok"); + } + cameraManager_ = nullptr; + } + OH_LOG_INFO(LOG_APP, "~NDKCamera exit"); +} + +Camera_ErrorCode NDKCamera::ReleaseCamera(void) { + OH_LOG_INFO(LOG_APP, " enter ReleaseCamera"); + if (previewOutput_) { + PreviewOutputStop(); + PreviewOutputRelease(); + OH_CaptureSession_RemovePreviewOutput(captureSession_, previewOutput_); + } + if (photoOutput_) { + PhotoOutputRelease(); + } + if (captureSession_) { + SessionRelease(); + } + if (cameraInput_) { + CameraInputClose(); + } + OH_LOG_INFO(LOG_APP, " exit ReleaseCamera"); + return ret_; +} + +Camera_ErrorCode NDKCamera::ReleaseSession(void) { + OH_LOG_INFO(LOG_APP, " enter ReleaseSession"); + PreviewOutputStop(); + PhotoOutputRelease(); + SessionRelease(); + OH_LOG_INFO(LOG_APP, " exit ReleaseSession"); + return ret_; +} + +Camera_ErrorCode NDKCamera::SessionRelease(void) { + OH_LOG_INFO(LOG_APP, " enter SessionRelease"); + Camera_ErrorCode ret = OH_CaptureSession_Release(captureSession_); + captureSession_ = nullptr; + OH_LOG_INFO(LOG_APP, " exit SessionRelease"); + return ret; +} + +Camera_ErrorCode NDKCamera::HasFlashFn(uint32_t mode) { + Camera_FlashMode flashMode = static_cast(mode); + // Check for flashing lights + bool hasFlash = false; + Camera_ErrorCode ret = OH_CaptureSession_HasFlash(captureSession_, &hasFlash); + if (captureSession_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed."); + } + if (hasFlash) { + OH_LOG_INFO(LOG_APP, "hasFlash success-----"); + } else { + OH_LOG_ERROR(LOG_APP, "hasFlash fail-----"); + } + + // Check if the flash mode is supported + bool isSupported = false; + ret = OH_CaptureSession_IsFlashModeSupported(captureSession_, flashMode, &isSupported); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed."); + } + if (isSupported) { + OH_LOG_INFO(LOG_APP, "isFlashModeSupported success-----"); + } else { + OH_LOG_ERROR(LOG_APP, "isFlashModeSupported fail-----"); + } + + // Set flash mode + ret = OH_CaptureSession_SetFlashMode(captureSession_, flashMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret); + } + + // Obtain the flash mode of the current device + ret = OH_CaptureSession_GetFlashMode(captureSession_, &flashMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFlashMode success. flashMode:%{public}d ", flashMode); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFlashMode failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::IsVideoStabilizationModeSupportedFn(uint32_t mode) { + Camera_VideoStabilizationMode videoMode = static_cast(mode); + // Check if the specified video anti shake mode is supported + bool isSupported = false; + Camera_ErrorCode ret = + OH_CaptureSession_IsVideoStabilizationModeSupported(captureSession_, videoMode, &isSupported); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsVideoStabilizationModeSupported failed."); + } + if (isSupported) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_IsVideoStabilizationModeSupported success-----"); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsVideoStabilizationModeSupported fail-----"); + } + + // Set video stabilization + ret = OH_CaptureSession_SetVideoStabilizationMode(captureSession_, videoMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetVideoStabilizationMode success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetVideoStabilizationMode failed. %{public}d ", ret); + } + + ret = OH_CaptureSession_GetVideoStabilizationMode(captureSession_, &videoMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetVideoStabilizationMode success. videoMode:%u ", videoMode); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetVideoStabilizationMode failed. %{public}d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::setZoomRatioFn(uint32_t zoomRatio) { + float zoom = float(zoomRatio); + // Obtain supported zoom range + float minZoom; + float maxZoom; + Camera_ErrorCode ret = OH_CaptureSession_GetZoomRatioRange(captureSession_, &minZoom, &maxZoom); + if (captureSession_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed."); + } else { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f", + minZoom, maxZoom); + } + + // Set Zoom + ret = OH_CaptureSession_SetZoomRatio(captureSession_, zoom); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret); + } + + // Obtain the zoom value of the current device + ret = OH_CaptureSession_GetZoomRatio(captureSession_, &zoom); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatio success. zoom:%{public}f ", zoom); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatio failed. %{public}d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionBegin(void) { + Camera_ErrorCode ret = OH_CaptureSession_BeginConfig(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_BeginConfig success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionCommitConfig(void) { + Camera_ErrorCode ret = OH_CaptureSession_CommitConfig(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_CommitConfig success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionStart(void) { + Camera_ErrorCode ret = OH_CaptureSession_Start(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Start success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionStop(void) { + Camera_ErrorCode ret = OH_CaptureSession_Stop(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Stop success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Stop failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionFlowFn(void) { + OH_LOG_INFO(LOG_APP, "Start SessionFlowFn IN."); + // Start configuring session + OH_LOG_INFO(LOG_APP, "session beginConfig."); + Camera_ErrorCode ret = OH_CaptureSession_BeginConfig(captureSession_); + + // Add CameraInput to the session + OH_LOG_INFO(LOG_APP, "session addInput."); + ret = OH_CaptureSession_AddInput(captureSession_, cameraInput_); + + // Add previewOutput to the session + OH_LOG_INFO(LOG_APP, "session add Preview Output."); + ret = OH_CaptureSession_AddPreviewOutput(captureSession_, previewOutput_); + + // Adding PhotoOutput to the Session + OH_LOG_INFO(LOG_APP, "session add Photo Output."); + + // Submit configuration information + OH_LOG_INFO(LOG_APP, "session commitConfig"); + ret = OH_CaptureSession_CommitConfig(captureSession_); + + // Start Session Work + OH_LOG_INFO(LOG_APP, "session start"); + ret = OH_CaptureSession_Start(captureSession_); + OH_LOG_INFO(LOG_APP, "session success"); + + // Start focusing + OH_LOG_INFO(LOG_APP, "IsFocusMode start"); + ret = IsFocusMode(focusMode_); + OH_LOG_INFO(LOG_APP, "IsFocusMode success"); + return ret; +} + +Camera_ErrorCode NDKCamera::CreateCameraInput(void) { + OH_LOG_INFO(LOG_APP, "enter CreateCameraInput."); + ret_ = OH_CameraManager_CreateCameraInput(cameraManager_, &cameras_[cameraDeviceIndex_], &cameraInput_); + if (cameraInput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreateCameraInput failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "exit CreateCameraInput."); + CameraInputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputOpen(void) { + OH_LOG_INFO(LOG_APP, "enter CameraInputOpen."); + ret_ = OH_CameraInput_Open(cameraInput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CameraInput_Open failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "exit CameraInputOpen."); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputClose(void) { + OH_LOG_INFO(LOG_APP, "enter CameraInput_Close."); + ret_ = OH_CameraInput_Close(cameraInput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CameraInput_Close failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "exit CameraInput_Close."); + return ret_; +} + +Camera_ErrorCode NDKCamera::GetSupportedCameras(void) { + ret_ = OH_CameraManager_GetSupportedCameras(cameraManager_, &cameras_, &size_); + if (cameras_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Get supported cameras failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::GetSupportedOutputCapability(void) { + ret_ = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager_, &cameras_[cameraDeviceIndex_], + &cameraOutputCapability_); + if (cameraOutputCapability_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetSupportedCameraOutputCapability failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::CreatePreviewOutput(void) { + profile_ = cameraOutputCapability_->previewProfiles[0]; + if (profile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get previewProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CameraManager_CreatePreviewOutput(cameraManager_, profile_, previewSurfaceId_, &previewOutput_); + if (previewSurfaceId_ == nullptr || previewOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreatePreviewOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::CreatePhotoOutput(char *photoSurfaceId) { + profile_ = cameraOutputCapability_->photoProfiles[0]; + if (profile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get photoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + + if (photoSurfaceId == nullptr) { + OH_LOG_ERROR(LOG_APP, "CreatePhotoOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + ret_ = OH_CameraManager_CreatePhotoOutput(cameraManager_, profile_, photoSurfaceId, &photoOutput_); + PhotoOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CreateVideoOutput(char *videoId) { + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CameraManager_CreateVideoOutput(cameraManager_, videoProfile_, videoId, &videoOutput_); + if (videoId == nullptr || videoOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + return ret_; +} + +Camera_ErrorCode NDKCamera::AddVideoOutput(void) { + Camera_ErrorCode ret = OH_CaptureSession_AddVideoOutput(captureSession_, videoOutput_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_AddVideoOutput success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddVideoOutput failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::AddPhotoOutput() { + Camera_ErrorCode ret = OH_CaptureSession_AddPhotoOutput(captureSession_, photoOutput_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_AddPhotoOutput success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPhotoOutput failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::PreviewOutputStop(void) { + OH_LOG_INFO(LOG_APP, "enter PreviewOutputStop."); + ret_ = OH_PreviewOutput_Stop(previewOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PreviewOutputStop failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::PreviewOutputRelease(void) { + OH_LOG_INFO(LOG_APP, "enter PreviewOutputRelease."); + ret_ = OH_PreviewOutput_Release(previewOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PreviewOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::PhotoOutputRelease(void) { + OH_LOG_INFO(LOG_APP, "enter PhotoOutputRelease."); + ret_ = OH_PhotoOutput_Release(photoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PhotoOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::StartVideo(char *videoId, char *photoId) { + OH_LOG_INFO(LOG_APP, "StartVideo begin."); + Camera_ErrorCode ret = SessionStop(); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "SessionStop success."); + } else { + OH_LOG_ERROR(LOG_APP, "SessionStop failed. %d ", ret); + } + ret = SessionBegin(); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "SessionBegin success."); + } else { + OH_LOG_ERROR(LOG_APP, "SessionBegin failed. %d ", ret); + } + OH_CaptureSession_RemovePhotoOutput(captureSession_, photoOutput_); + CreatePhotoOutput(photoId); + AddPhotoOutput(); + CreateVideoOutput(videoId); + AddVideoOutput(); + SessionCommitConfig(); + SessionStart(); + VideoOutputRegisterCallback(); + return ret; +} + +Camera_ErrorCode NDKCamera::VideoOutputStart(void) { + OH_LOG_INFO(LOG_APP, "VideoOutputStart begin."); + Camera_ErrorCode ret = OH_VideoOutput_Start(videoOutput_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_VideoOutput_Start success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_Start failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::StartPhoto(char *mSurfaceId) { + Camera_ErrorCode ret = CAMERA_OK; + if (takePictureTimes == 0) { + ret = SessionStop(); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "SessionStop success."); + } else { + OH_LOG_ERROR(LOG_APP, "SessionStop failed. %d ", ret); + } + ret = SessionBegin(); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "SessionBegin success."); + } else { + OH_LOG_ERROR(LOG_APP, "SessionBegin failed. %d ", ret); + } + OH_LOG_INFO(LOG_APP, "startPhoto begin."); + ret = CreatePhotoOutput(mSurfaceId); + + OH_LOG_INFO(LOG_APP, "startPhoto CreatePhotoOutput ret = %{public}d.", ret); + ret = OH_CaptureSession_AddPhotoOutput(captureSession_, photoOutput_); + OH_LOG_INFO(LOG_APP, "startPhoto AddPhotoOutput ret = %{public}d.", ret); + ret = SessionCommitConfig(); + + OH_LOG_INFO(LOG_APP, "startPhoto SessionCommitConfig ret = %{public}d.", ret); + ret = SessionStart(); + OH_LOG_INFO(LOG_APP, "startPhoto SessionStart ret = %{public}d.", ret); + } + ret = TakePicture(); + OH_LOG_INFO(LOG_APP, "startPhoto OH_PhotoOutput_Capture ret = %{public}d.", ret); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "startPhoto failed."); + return CAMERA_INVALID_ARGUMENT; + } + takePictureTimes++; + return ret_; +} + +// exposure mode +Camera_ErrorCode NDKCamera::IsExposureModeSupportedFn(uint32_t mode) { + OH_LOG_INFO(LOG_APP, "IsExposureModeSupportedFn start."); + exposureMode_ = static_cast(mode); + ret_ = OH_CaptureSession_IsExposureModeSupported(captureSession_, exposureMode_, &isExposureModeSupported_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsExposureModeSupported failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_SetExposureMode(captureSession_, exposureMode_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetExposureMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetExposureMode(captureSession_, &exposureMode_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsExposureModeSupportedFn end."); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsMeteringPoint(int x, int y) { + OH_LOG_INFO(LOG_APP, "IsMeteringPoint start."); + ret_ = OH_CaptureSession_GetExposureMode(captureSession_, &exposureMode_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + Camera_Point exposurePoint; + exposurePoint.x = x; + exposurePoint.y = y; + ret_ = OH_CaptureSession_SetMeteringPoint(captureSession_, exposurePoint); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetMeteringPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetMeteringPoint(captureSession_, &exposurePoint); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetMeteringPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsMeteringPoint end."); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsExposureBiasRange(int exposureBias) { + OH_LOG_INFO(LOG_APP, "IsExposureBiasRange end."); + float exposureBiasValue = (float)exposureBias; + ret_ = OH_CaptureSession_GetExposureBiasRange(captureSession_, &minExposureBias_, &maxExposureBias_, &step_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureBiasRange failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_SetExposureBias(captureSession_, exposureBiasValue); + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetExposureBias end."); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetExposureBias failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetExposureBias(captureSession_, &exposureBiasValue); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureBias failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsExposureBiasRange end."); + return ret_; +} + +// focus mode +Camera_ErrorCode NDKCamera::IsFocusModeSupported(uint32_t mode) { + Camera_FocusMode focusMode = static_cast(mode); + ret_ = OH_CaptureSession_IsFocusModeSupported(captureSession_, focusMode, &isFocusModeSupported_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsFocusModeSupported failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::IsFocusMode(uint32_t mode) { + OH_LOG_INFO(LOG_APP, "IsFocusMode start."); + Camera_FocusMode focusMode = static_cast(mode); + ret_ = OH_CaptureSession_IsFocusModeSupported(captureSession_, focusMode, &isFocusModeSupported_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsFocusModeSupported failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_SetFocusMode(captureSession_, focusMode); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetFocusMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetFocusMode(captureSession_, &focusMode); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetFocusMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsFocusMode end."); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsFocusPoint(float x, float y) { + OH_LOG_INFO(LOG_APP, "IsFocusPoint start."); + Camera_Point focusPoint; + focusPoint.x = x; + focusPoint.y = y; + ret_ = OH_CaptureSession_SetFocusPoint(captureSession_, focusPoint); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetFocusPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetFocusPoint(captureSession_, &focusPoint); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetFocusPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsFocusPoint end."); + return ret_; +} + +int32_t NDKCamera::GetVideoFrameWidth(void) { + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + return videoProfile_->size.width; +} + +int32_t NDKCamera::GetVideoFrameHeight(void) { + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + return videoProfile_->size.height; +} + +int32_t NDKCamera::GetVideoFrameRate(void) { + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + return videoProfile_->range.min; +} + +Camera_ErrorCode NDKCamera::VideoOutputStop(void) { + OH_LOG_INFO(LOG_APP, "enter VideoOutputStop."); + ret_ = OH_VideoOutput_Stop(videoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "VideoOutputStop failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::VideoOutputRelease(void) { + OH_LOG_INFO(LOG_APP, "enter VideoOutputRelease."); + ret_ = OH_VideoOutput_Release(videoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "VideoOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::TakePicture(void) { + Camera_ErrorCode ret = CAMERA_OK; + ret = OH_PhotoOutput_Capture(photoOutput_); + OH_LOG_INFO(LOG_APP, "takePicture OH_PhotoOutput_Capture ret = %{public}d.", ret); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "startPhoto failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret; +} + +Camera_ErrorCode NDKCamera::TakePictureWithPhotoSettings(Camera_PhotoCaptureSetting photoSetting) { + Camera_ErrorCode ret = CAMERA_OK; + ret = OH_PhotoOutput_Capture_WithCaptureSetting(photoOutput_, photoSetting); + + OH_LOG_INFO(LOG_APP, + "TakePictureWithPhotoSettings get quality %{public}d, rotation %{public}d, mirror %{public}d, " + "latitude, %f, longitude %f, altitude %f", + photoSetting.quality, photoSetting.rotation, photoSetting.mirror, photoSetting.location->latitude, + photoSetting.location->longitude, photoSetting.location->altitude); + + OH_LOG_INFO(LOG_APP, "takePicture TakePictureWithPhotoSettings ret = %{public}d.", ret); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "startPhoto failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret; +} + +// CameraManager Callback +void CameraManagerStatusCallback(Camera_Manager *cameraManager, Camera_StatusInfo *status) { + if (cameraManager == nullptr || status == nullptr) { + OH_LOG_ERROR(LOG_APP, "CameraManager or status is nullptr."); + } + OH_LOG_INFO(LOG_APP, "CameraManagerStatusCallback"); +} + +CameraManager_Callbacks *NDKCamera::GetCameraManagerListener(void) { + static CameraManager_Callbacks cameraManagerListener = {.onCameraStatus = CameraManagerStatusCallback}; + return &cameraManagerListener; +} + +Camera_ErrorCode NDKCamera::CameraManagerRegisterCallback(void) { + ret_ = OH_CameraManager_RegisterCallback(cameraManager_, GetCameraManagerListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CameraManager_RegisterCallback failed."); + } + return ret_; +} + +// CameraInput Callback +void OnCameraInputError(const Camera_Input *cameraInput, Camera_ErrorCode errorCode) { + if (cameraInput == nullptr) { + OH_LOG_ERROR(LOG_APP, "CameraInput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "OnCameraInput errorCode = %{public}d", errorCode); +} + +CameraInput_Callbacks *NDKCamera::GetCameraInputListener(void) { + static CameraInput_Callbacks cameraInputCallbacks = {.onError = OnCameraInputError}; + return &cameraInputCallbacks; +} + +Camera_ErrorCode NDKCamera::CameraInputRegisterCallback(void) { + ret_ = OH_CameraInput_RegisterCallback(cameraInput_, GetCameraInputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CameraInput_RegisterCallback failed."); + } + return ret_; +} + +// PhotoOutput Callback +void PhotoOutputOnFrameStart(Camera_PhotoOutput *photoOutput) { + if (photoOutput == nullptr) { + OH_LOG_ERROR(LOG_APP, "PhotoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameStart"); +} + +void PhotoOutputOnFrameShutter(Camera_PhotoOutput *photoOutput, Camera_FrameShutterInfo *info) { + if (photoOutput == nullptr || info == nullptr) { + OH_LOG_ERROR(LOG_APP, "PhotoOutput or info is nullptr."); + } + OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameShutter"); +} + +void PhotoOutputOnFrameEnd(Camera_PhotoOutput *photoOutput, int32_t frameCount) { + if (photoOutput == nullptr) { + OH_LOG_ERROR(LOG_APP, "PhotoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "PhotoOutput frameCount = %{public}d", frameCount); +} + +void PhotoOutputOnError(Camera_PhotoOutput *photoOutput, Camera_ErrorCode errorCode) { + if (photoOutput == nullptr) { + OH_LOG_ERROR(LOG_APP, "PhotoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "PhotoOutput errorCode = %{public}d", errorCode); +} + +PhotoOutput_Callbacks *NDKCamera::GetPhotoOutputListener(void) { + static PhotoOutput_Callbacks photoOutputListener = {.onFrameStart = PhotoOutputOnFrameStart, + .onFrameShutter = PhotoOutputOnFrameShutter, + .onFrameEnd = PhotoOutputOnFrameEnd, + .onError = PhotoOutputOnError}; + return &photoOutputListener; +} + +Camera_ErrorCode NDKCamera::PhotoOutputRegisterCallback(void) { + ret_ = OH_PhotoOutput_RegisterCallback(photoOutput_, GetPhotoOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_RegisterCallback failed."); + } + return ret_; +} + +// VideoOutput Callback +void VideoOutputOnFrameStart(Camera_VideoOutput *videoOutput) { + if (videoOutput == nullptr) { + OH_LOG_ERROR(LOG_APP, "VideoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "VideoOutputOnFrameStart"); +} + +void VideoOutputOnFrameEnd(Camera_VideoOutput *videoOutput, int32_t frameCount) { + if (videoOutput == nullptr) { + OH_LOG_ERROR(LOG_APP, "VideoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "VideoOutput frameCount = %{public}d", frameCount); +} + +void VideoOutputOnError(Camera_VideoOutput *videoOutput, Camera_ErrorCode errorCode) { + if (videoOutput == nullptr) { + OH_LOG_ERROR(LOG_APP, "VideoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "VideoOutput errorCode = %{public}d", errorCode); +} + +VideoOutput_Callbacks *NDKCamera::GetVideoOutputListener(void) { + static VideoOutput_Callbacks videoOutputListener = { + .onFrameStart = VideoOutputOnFrameStart, .onFrameEnd = VideoOutputOnFrameEnd, .onError = VideoOutputOnError}; + return &videoOutputListener; +} + +Camera_ErrorCode NDKCamera::VideoOutputRegisterCallback(void) { + ret_ = OH_VideoOutput_RegisterCallback(videoOutput_, GetVideoOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_RegisterCallback failed."); + } + return ret_; +} + +// Session Callback +void CaptureSessionOnFocusStateChange(Camera_CaptureSession *session, Camera_FocusState focusState) { + if (session == nullptr) { + OH_LOG_ERROR(LOG_APP, "VideoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "CaptureSessionOnFocusStateChange focusState = %{public}d", focusState); +} + +void CaptureSessionOnError(Camera_CaptureSession *session, Camera_ErrorCode errorCode) { + if (session == nullptr) { + OH_LOG_ERROR(LOG_APP, "VideoOutput is nullptr."); + } + OH_LOG_INFO(LOG_APP, "CaptureSession errorCode = %{public}d", errorCode); +} + +CaptureSession_Callbacks *NDKCamera::GetCaptureSessionRegister(void) { + static CaptureSession_Callbacks captureSessionCallbacks = {.onFocusStateChange = CaptureSessionOnFocusStateChange, + .onError = CaptureSessionOnError}; + return &captureSessionCallbacks; +} + +Camera_ErrorCode NDKCamera::CaptureSessionRegisterCallback(void) { + ret_ = OH_CaptureSession_RegisterCallback(captureSession_, GetCaptureSessionRegister()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_RegisterCallback failed."); + } + return ret_; +} +} // namespace OHOS_CAMERA_SAMPLE \ No newline at end of file diff --git a/entry/src/main/cpp/camera_manager.h b/entry/src/main/cpp/camera_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..39be7260f0ff297745b433e673eb6bc1da6ced42 --- /dev/null +++ b/entry/src/main/cpp/camera_manager.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CAMERA_NDK_CAMERA_H +#define CAMERA_NDK_CAMERA_H + +#include +#include "mutex" +#include "ohcamera/camera.h" +#include "ohcamera/camera_input.h" +#include "ohcamera/capture_session.h" +#include "ohcamera/photo_output.h" +#include "ohcamera/preview_output.h" +#include "ohcamera/video_output.h" +#include "ohcamera/camera_manager.h" + +namespace OHOS_CAMERA_SAMPLE { +class NDKCamera { +public: + ~NDKCamera(); + NDKCamera(char *str, uint32_t focusMode, uint32_t cameraDeviceIndex); + + Camera_ErrorCode CreateCameraInput(void); + Camera_ErrorCode CameraInputOpen(void); + Camera_ErrorCode CameraInputClose(void); + Camera_ErrorCode GetSupportedCameras(void); + Camera_ErrorCode GetSupportedOutputCapability(void); + Camera_ErrorCode CreatePreviewOutput(void); + Camera_ErrorCode CreatePhotoOutput(char *photoId); + Camera_ErrorCode CreateVideoOutput(char *videoId); + Camera_ErrorCode PreviewOutputStop(void); + Camera_ErrorCode PreviewOutputRelease(void); + Camera_ErrorCode PhotoOutputRelease(void); + Camera_ErrorCode HasFlashFn(uint32_t mode); + Camera_ErrorCode IsVideoStabilizationModeSupportedFn(uint32_t mode); + Camera_ErrorCode setZoomRatioFn(uint32_t zoomRatio); + Camera_ErrorCode SessionFlowFn(void); + Camera_ErrorCode SessionBegin(void); + Camera_ErrorCode SessionCommitConfig(void); + Camera_ErrorCode SessionStart(void); + Camera_ErrorCode SessionStop(void); + Camera_ErrorCode StartVideo(char *videoId, char *photoId); + Camera_ErrorCode AddVideoOutput(void); + Camera_ErrorCode AddPhotoOutput(); + Camera_ErrorCode VideoOutputStart(void); + Camera_ErrorCode StartPhoto(char *mSurfaceId); + Camera_ErrorCode IsExposureModeSupportedFn(uint32_t mode); + Camera_ErrorCode IsMeteringPoint(int x, int y); + Camera_ErrorCode IsExposureBiasRange(int exposureBias); + Camera_ErrorCode IsFocusMode(uint32_t mode); + Camera_ErrorCode IsFocusPoint(float x, float y); + Camera_ErrorCode IsFocusModeSupported(uint32_t mode); + Camera_ErrorCode ReleaseCamera(void); + Camera_ErrorCode SessionRelease(void); + Camera_ErrorCode ReleaseSession(void); + int32_t GetVideoFrameWidth(void); + int32_t GetVideoFrameHeight(void); + int32_t GetVideoFrameRate(void); + Camera_ErrorCode VideoOutputStop(void); + Camera_ErrorCode VideoOutputRelease(void); + Camera_ErrorCode TakePicture(void); + Camera_ErrorCode TakePictureWithPhotoSettings(Camera_PhotoCaptureSetting photoSetting); + // callback + Camera_ErrorCode CameraManagerRegisterCallback(void); + Camera_ErrorCode CameraInputRegisterCallback(void); + Camera_ErrorCode PhotoOutputRegisterCallback(void); + Camera_ErrorCode VideoOutputRegisterCallback(void); + Camera_ErrorCode CaptureSessionRegisterCallback(void); + + // Get callback + CameraManager_Callbacks *GetCameraManagerListener(void); + CameraInput_Callbacks *GetCameraInputListener(void); + PhotoOutput_Callbacks *GetPhotoOutputListener(void); + VideoOutput_Callbacks *GetVideoOutputListener(void); + CaptureSession_Callbacks *GetCaptureSessionRegister(void); + +private: + NDKCamera(const NDKCamera &) = delete; + NDKCamera &operator=(const NDKCamera &) = delete; + uint32_t cameraDeviceIndex_; + Camera_Manager *cameraManager_; + Camera_CaptureSession *captureSession_; + Camera_Device *cameras_; + uint32_t size_; + Camera_OutputCapability *cameraOutputCapability_; + const Camera_Profile *profile_; + const Camera_VideoProfile *videoProfile_; + Camera_PreviewOutput *previewOutput_; + Camera_PhotoOutput *photoOutput_; + Camera_VideoOutput *videoOutput_; + const Camera_MetadataObjectType *metaDataObjectType_; + Camera_MetadataOutput *metadataOutput_; + Camera_Input *cameraInput_; + bool *isCameraMuted_; + Camera_Position position_; + Camera_Type type_; + char *previewSurfaceId_; + char *photoSurfaceId_; + Camera_ErrorCode ret_; + uint32_t takePictureTimes = 0; + Camera_ExposureMode exposureMode_; + bool isExposureModeSupported_; + bool isFocusModeSupported_; + float minExposureBias_; + float maxExposureBias_; + float step_; + uint32_t focusMode_; + + static std::mutex mtx_; + volatile bool valid_; +}; +} // namespace OHOS_CAMERA_SAMPLE +#endif // CAMERA_NDK_CAMERA_H diff --git a/entry/src/main/cpp/main.cpp b/entry/src/main/cpp/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e54a883f0ce6cd1f174ca0bad4b32e271dac2ff1 --- /dev/null +++ b/entry/src/main/cpp/main.cpp @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "camera_manager.h" + +using namespace OHOS_CAMERA_SAMPLE; +static NDKCamera *ndkCamera_ = nullptr; +const int32_t ARGS_TWO = 2; +struct Capture_Setting { + int32_t quality; + int32_t rotation; + int32_t location; + bool mirror; + int32_t latitude; + int32_t longitude; + int32_t altitude; +}; + +static napi_value SetZoomRatio(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + int32_t zoomRatio; + napi_get_value_int32(env, args[0], &zoomRatio); + + OH_LOG_INFO(LOG_APP, "SetZoomRatio : %{public}d", zoomRatio); + + ndkCamera_->setZoomRatioFn(zoomRatio); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value HasFlash(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "HasFlash"); + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + int32_t flashMode; + napi_get_value_int32(env, args[0], &flashMode); + + OH_LOG_INFO(LOG_APP, "HasFlash flashMode : %{public}d", flashMode); + + ndkCamera_->HasFlashFn(flashMode); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value IsVideoStabilizationModeSupported(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "IsVideoStabilizationModeSupportedFn"); + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + int32_t videoMode; + napi_get_value_int32(env, args[0], &videoMode); + + OH_LOG_INFO(LOG_APP, "IsVideoStabilizationModeSupportedFn videoMode : %{public}d", videoMode); + + ndkCamera_->IsVideoStabilizationModeSupportedFn(videoMode); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value InitCamera(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "InitCamera Start"); + size_t argc = 3; + napi_value args[3] = {nullptr}; + napi_value result; + size_t typeLen = 0; + char *surfaceId = nullptr; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_get_value_string_utf8(env, args[0], nullptr, 0, &typeLen); + surfaceId = new char[typeLen + 1]; + napi_get_value_string_utf8(env, args[0], surfaceId, typeLen + 1, &typeLen); + + napi_valuetype valuetype1; + napi_typeof(env, args[1], &valuetype1); + + int32_t focusMode; + napi_get_value_int32(env, args[1], &focusMode); + + uint32_t cameraDeviceIndex; + napi_get_value_uint32(env, args[ARGS_TWO], &cameraDeviceIndex); + + OH_LOG_INFO(LOG_APP, "InitCamera focusMode : %{public}d", focusMode); + OH_LOG_INFO(LOG_APP, "InitCamera surfaceId : %{public}s", surfaceId); + OH_LOG_INFO(LOG_APP, "InitCamera cameraDeviceIndex : %{public}d", cameraDeviceIndex); + + if (ndkCamera_) { + OH_LOG_INFO(LOG_APP, "ndkCamera_ is not null"); + delete ndkCamera_; + ndkCamera_ = nullptr; + } + ndkCamera_ = new NDKCamera(surfaceId, focusMode, cameraDeviceIndex); + OH_LOG_INFO(LOG_APP, "InitCamera End"); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value ReleaseCamera(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "ReleaseCamera Start"); + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ndkCamera_->ReleaseCamera(); + if (ndkCamera_) { + OH_LOG_INFO(LOG_APP, "ndkCamera_ is not null"); + delete ndkCamera_; + ndkCamera_ = nullptr; + } + OH_LOG_INFO(LOG_APP, "ReleaseCamera End"); + napi_create_int32(env, argc, &result); + return result; +} +static napi_value ReleaseSession(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "ReleaseCamera Start"); + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ndkCamera_->ReleaseSession(); + + OH_LOG_INFO(LOG_APP, "ReleaseCamera End"); + napi_create_int32(env, argc, &result); + return result; +} +static napi_value StartPhotoOrVideo(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "StartPhotoOrVideo Start"); + Camera_ErrorCode ret = CAMERA_OK; + size_t argc = 3; + napi_value args[3] = {nullptr}; + napi_value result; + size_t typeLen = 0; + size_t videoIdLen = 0; + size_t photoIdLen = 0; + char *modeFlag = nullptr; + char *videoId = nullptr; + char *photoId = nullptr; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_get_value_string_utf8(env, args[0], nullptr, 0, &typeLen); + modeFlag = new char[typeLen + 1]; + napi_get_value_string_utf8(env, args[0], modeFlag, typeLen + 1, &typeLen); + + napi_get_value_string_utf8(env, args[1], nullptr, 0, &videoIdLen); + videoId = new char[videoIdLen + 1]; + napi_get_value_string_utf8(env, args[1], videoId, videoIdLen + 1, &videoIdLen); + + napi_get_value_string_utf8(env, args[ARGS_TWO], nullptr, 0, &photoIdLen); + photoId = new char[photoIdLen + 1]; + napi_get_value_string_utf8(env, args[ARGS_TWO], photoId, photoIdLen + 1, &photoIdLen); + + if (!strcmp(modeFlag, "photo")) { + OH_LOG_INFO(LOG_APP, "StartPhoto surfaceId %{public}s", photoId); + ret = ndkCamera_->StartPhoto(photoId); + } else if (!strcmp(modeFlag, "video")) { + ret = ndkCamera_->StartVideo(videoId, photoId); + OH_LOG_INFO(LOG_APP, "StartPhotoOrVideo %{public}s, %{public}s", videoId, photoId); + } + napi_create_int32(env, ret, &result); + return result; +} + +static napi_value VideoOutputStart(napi_env env, napi_callback_info info) { + if (info == nullptr) { + OH_LOG_ERROR(LOG_APP, "Info is nullptr."); + } + OH_LOG_INFO(LOG_APP, "VideoOutputStart Start"); + napi_value result; + Camera_ErrorCode ret = ndkCamera_->VideoOutputStart(); + napi_create_int32(env, ret, &result); + return result; +} + +static napi_value IsExposureModeSupported(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "IsExposureModeSupported exposureMode start."); + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + int32_t exposureMode; + napi_get_value_int32(env, args[0], &exposureMode); + + OH_LOG_INFO(LOG_APP, "IsExposureModeSupported exposureMode : %{public}d", exposureMode); + + ndkCamera_->IsExposureModeSupportedFn(exposureMode); + OH_LOG_INFO(LOG_APP, "IsExposureModeSupported exposureMode end."); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value IsMeteringPoint(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + int x; + napi_get_value_int32(env, args[0], &x); + + napi_typeof(env, args[0], &valuetype0); + int y; + napi_get_value_int32(env, args[1], &y); + ndkCamera_->IsMeteringPoint(x, y); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value IsExposureBiasRange(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "IsExposureBiasRange start."); + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + int exposureBiasValue; + napi_get_value_int32(env, args[0], &exposureBiasValue); + ndkCamera_->IsExposureBiasRange(exposureBiasValue); + OH_LOG_INFO(LOG_APP, "IsExposureBiasRange end."); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value IsFocusModeSupported(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "IsFocusModeSupported start."); + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + int32_t focusMode; + napi_get_value_int32(env, args[0], &focusMode); + + OH_LOG_INFO(LOG_APP, "IsFocusModeSupportedFn videoMode : %{public}d", focusMode); + + ndkCamera_->IsFocusModeSupported(focusMode); + OH_LOG_INFO(LOG_APP, "IsFocusModeSupported end."); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value IsFocusPoint(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_value result; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + double x; + napi_get_value_double(env, args[0], &x); + + napi_valuetype valuetype1; + napi_typeof(env, args[1], &valuetype1); + double y; + napi_get_value_double(env, args[1], &y); + + float focusPointX = static_cast(x); + float focusPointY = static_cast(y); + ndkCamera_->IsFocusPoint(focusPointX, focusPointY); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value GetVideoFrameWidth(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "GetVideoFrameWidth Start"); + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_value result = nullptr; + napi_create_int32(env, ndkCamera_->GetVideoFrameWidth(), &result); + + OH_LOG_INFO(LOG_APP, "GetVideoFrameWidth End"); + return result; +} + +static napi_value GetVideoFrameHeight(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "GetVideoFrameHeight Start"); + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_value result = nullptr; + napi_create_int32(env, ndkCamera_->GetVideoFrameHeight(), &result); + + OH_LOG_INFO(LOG_APP, "GetVideoFrameHeight End"); + return result; +} + +static napi_value GetVideoFrameRate(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "GetVideoFrameRate Start"); + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_value result = nullptr; + napi_create_int32(env, ndkCamera_->GetVideoFrameRate(), &result); + + OH_LOG_INFO(LOG_APP, "GetVideoFrameRate End"); + return result; +} + +static napi_value VideoOutputStopAndRelease(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "VideoOutputStopAndRelease Start"); + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_value result = nullptr; + ndkCamera_->VideoOutputStop(); + ndkCamera_->VideoOutputRelease(); + + OH_LOG_INFO(LOG_APP, "VideoOutputStopAndRelease End"); + napi_create_int32(env, argc, &result); + return result; +} + +static napi_value TakePicture(napi_env env, napi_callback_info info) { + if (info == nullptr) { + OH_LOG_ERROR(LOG_APP, "Info is nullptr."); + } + OH_LOG_INFO(LOG_APP, "TakePicture Start"); + napi_value result; + Camera_ErrorCode ret = ndkCamera_->TakePicture(); + OH_LOG_INFO(LOG_APP, "TakePicture result is %{public}d", ret); + napi_create_int32(env, ret, &result); + return result; +} + +static napi_value GetCaptureParam(napi_env env, napi_value captureConfigValue, Capture_Setting *config) { + napi_value value = nullptr; + napi_get_named_property(env, captureConfigValue, "quality", &value); + napi_get_value_int32(env, value, &config->quality); + + napi_get_named_property(env, captureConfigValue, "rotation", &value); + napi_get_value_int32(env, value, &config->rotation); + + napi_get_named_property(env, captureConfigValue, "mirror", &value); + napi_get_value_bool(env, value, &config->mirror); + + napi_get_named_property(env, captureConfigValue, "latitude", &value); + napi_get_value_int32(env, value, &config->latitude); + + napi_get_named_property(env, captureConfigValue, "longitude", &value); + napi_get_value_int32(env, value, &config->longitude); + + napi_get_named_property(env, captureConfigValue, "altitude", &value); + napi_get_value_int32(env, value, &config->altitude); + + OH_LOG_INFO(LOG_APP, + "get quality %{public}d, rotation %{public}d, mirror %{public}d, latitude " + "%{public}d, longitude %{public}d, altitude %{public}d", + config->quality, config->rotation, config->mirror, config->latitude, config->longitude, + config->altitude); + return 0; +} +static void SetConfig(Capture_Setting settings, Camera_PhotoCaptureSetting *photoSetting, Camera_Location *location) { + if (photoSetting == nullptr || location == nullptr) { + OH_LOG_INFO(LOG_APP, "photoSetting is null"); + } + photoSetting->quality = static_cast(settings.quality); + photoSetting->rotation = static_cast(settings.rotation); + photoSetting->mirror = settings.mirror; + location->altitude = settings.altitude; + location->latitude = settings.latitude; + location->longitude = settings.longitude; + photoSetting->location = location; +} + +static napi_value TakePictureWithSettings(napi_env env, napi_callback_info info) { + OH_LOG_INFO(LOG_APP, "TakePictureWithSettings Start"); + size_t argc = 1; + napi_value args[1] = {nullptr}; + Camera_PhotoCaptureSetting photoSetting; + Capture_Setting setting_inner; + Camera_Location *location = new Camera_Location; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + GetCaptureParam(env, args[0], &setting_inner); + SetConfig(setting_inner, &photoSetting, location); + + napi_value result; + Camera_ErrorCode ret = ndkCamera_->TakePictureWithPhotoSettings(photoSetting); + OH_LOG_INFO(LOG_APP, "TakePictureWithSettings result is %{public}d", ret); + napi_create_int32(env, ret, &result); + return result; +} + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor desc[] = { + {"initCamera", nullptr, InitCamera, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"startPhotoOrVideo", nullptr, StartPhotoOrVideo, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"videoOutputStart", nullptr, VideoOutputStart, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"setZoomRatio", nullptr, SetZoomRatio, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"hasFlash", nullptr, HasFlash, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"isVideoStabilizationModeSupported", nullptr, IsVideoStabilizationModeSupported, nullptr, nullptr, nullptr, + napi_default, nullptr}, + {"isExposureModeSupported", nullptr, IsExposureModeSupported, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"isMeteringPoint", nullptr, IsMeteringPoint, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"isExposureBiasRange", nullptr, IsExposureBiasRange, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"IsFocusModeSupported", nullptr, IsFocusModeSupported, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"isFocusPoint", nullptr, IsFocusPoint, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getVideoFrameWidth", nullptr, GetVideoFrameWidth, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getVideoFrameHeight", nullptr, GetVideoFrameHeight, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getVideoFrameRate", nullptr, GetVideoFrameRate, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"videoOutputStopAndRelease", nullptr, VideoOutputStopAndRelease, nullptr, nullptr, nullptr, napi_default, + nullptr}, + {"takePicture", nullptr, TakePicture, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"takePictureWithSettings", nullptr, TakePictureWithSettings, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"releaseSession", nullptr, ReleaseSession, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"releaseCamera", nullptr, ReleaseCamera, nullptr, nullptr, nullptr, napi_default, nullptr}}; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } \ No newline at end of file diff --git a/entry/src/main/cpp/types/libentry/Index.d.ts b/entry/src/main/cpp/types/libentry/Index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8b100707262ebab892fed8ed0f0959efb1f3d6f --- /dev/null +++ b/entry/src/main/cpp/types/libentry/Index.d.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const initCamera:(surfaceId: string, focusMode: number, cameraDeviceIndex: number) => number; +export const startPhotoOrVideo: (modeFlag: string, videoId: string, photoId: string) => number; +export const videoOutputStart: () => number; +export const setZoomRatio: (a: number) => number; +export const takePicture: () => number; +export const takePictureWithSettings: (setting: Capture_Setting) => number; +export const hasFlash: (a: number) => number; +export const isVideoStabilizationModeSupported: (a: number) => number; +export const isExposureModeSupported:(a: number) => number; +export const isMeteringPoint: (a: number, b: number) => number; +export const isExposureBiasRange: (a: number) => number; +export const isFocusModeSupported: (a: number) => number; +export const isFocusPoint: (a: number, b: number) => number; +export const getVideoFrameWidth: () => number; +export const getVideoFrameHeight: () => number; +export const getVideoFrameRate: () => number; +export const videoOutputStopAndRelease: () => number; +export const releaseCamera: () => number; +export const releaseSession: () => number; + + +interface Capture_Setting { + quality: number; + rotation: number; + mirror: boolean; + latitude: number; + longitude: number; + altitude: number; +} \ No newline at end of file diff --git a/entry/src/main/cpp/types/libentry/oh-package.json5 b/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..46e87242753bdab5d3168b49863ed63c19b8172d --- /dev/null +++ b/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,6 @@ +{ + "name": "libentry.so", + "types": "./Index.d.ts", + "version": "", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/entry/src/main/ets/common/Constants.ets b/entry/src/main/ets/common/Constants.ets new file mode 100644 index 0000000000000000000000000000000000000000..3cb267e4d4e3c7781967263fd561ba00afc07f62 --- /dev/null +++ b/entry/src/main/ets/common/Constants.ets @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class Constants { + // aspect ratio: width/height + static readonly MIN_ASPECT_RATIO = 4 / 3; // 4:MIN_ASPECT_RATIO, 3:MIN_ASPECT_RATIO + + // device type + static readonly TABLET = 'tablet'; + static readonly DEFAULT = 'default'; + static readonly PHONE = 'phone'; + + /** + * The full percentage of component. + */ + static readonly FULL_PERCENT: string = '100%'; + + /** + * The seventy percent of the components. + */ + static readonly SEVENTY_PERCENT: string = '70%'; + + /** + * The fifteen percent of the bottom of the margin. + */ + static readonly FIFTEEN_PERCENT: string = '15%'; + + /** + * X-axis offset position. + */ + static readonly PHOTO_X_POSITION: string = '39%'; + + /** + * X-axis offset position. + */ + static readonly VIDEO_X_POSITION: string = '53%'; + + /** + * Y-axis offset position. + */ + static readonly Y_POSITION: string = '77%'; + + /** + * Album X-axis offset position. + */ + static readonly ALBUM_X_POSITION: string = '10%'; + + /** + * Album, photo, video, and camera switch icons Y-axis offset position. + */ + static readonly ICON_Y_POSITION: string = '85%'; + + /** + * Capture video icon X-axis offset position. + */ + static readonly CAPTURE_X_POSITION: string = '42%'; + + /** + * Front and rear camera switching X-axis offset position. + */ + static readonly SWITCH_X_POSITION: string = '73%'; + + /** + * Shooting mode. + */ + static readonly PHOTO: string = 'photo'; + + /** + * Recording Mode. + */ + static readonly VIDEO: string = 'video'; + + /** + * Album, photo, video, and camera switch icons size. + */ + static readonly ICON_SIZE: number = 200; + + /** + * Event offsetY. + */ + static readonly EVENT_Y_OFFSET: number = 200; + + /** + * Event offsetY. + */ + static readonly EVENT_Y_OFFSET1: number = -200; + + /** + * FontWeight 400. + */ + static readonly FONT_WEIGHT_400: number = 400; + + /** + * Position ± 25. + */ + static readonly POSITION_25: number = 25; + + /** + * Position ± 58. + */ + static readonly POSITION_58: number = 58; + + /** + * Position ± 30. + */ + static readonly POSITION_30: number = 30; + + /** + * Position ± 95. + */ + static readonly POSITION_95: number = 95; + + /** + * Position ± 73. + */ + static readonly POSITION_73: number = 73; + + /** + * Position ± 40. + */ + static readonly POSITION_40: number = 40; + + /** + * Position ± 10. + */ + static readonly POSITION_10: number = 10; + + /** + * Audio bit rate and sample rate. + */ + static readonly AUDIO_BITRATE_SAMPLE_RATE: number = 48000; + + /** + * Number of audio collection channels. + */ + static readonly AUDIO_CHANNELS: number = 2; + + /** + * Video bit rate. + */ + static readonly VIDEO_BITRATE: number = 512000; + + /** + * Width of the video frame. + */ + static readonly VIDEO_FRAME_WIDTH: number = 640; + + /** + * Height of the video frame. + */ + static readonly VIDEO_FRAME_HEIGHT: number = 480; + + /** + *Video frame rate. + */ + static readonly VIDEO_FRAME_RATE: number = 30; + + /** + *Geographical longitude. + */ + static readonly LONGITUDE: number = 77.7500; + + /** + *Geographical latitude. + */ + static readonly LATITUDE: number = 12.9698; + + /** + *Geographical altitude. + */ + static readonly ALTITUDE: number = 1000; +}; + +export class SettingDataObj { + mirrorBol = false; // Mirror Enable -> Off + videoStabilizationMode = 0; // Video Anti Shake -> Off + exposureMode = 1; // Exposure mode -> Automatic + focusMode = 2; // 2:Focus mode -> Automatic + photoQuality = 1; // Photo quality -> medium + locationBol = false; // Show Geographic Location -> Off + photoFormat = 1; // Photo Format -> JPG + photoOrientation = 0; // Photo direction -> 0 + photoResolution = 0; // Photo resolution -> 1920 * 1080 + videoResolution = 0; // Photo resolution -> 1920 * 1080 + videoFrame = 0; // Recording frame rate -> 15 + referenceLineBol = false; // Divider -> Off +}; \ No newline at end of file diff --git a/entry/src/main/ets/common/DisplayCalculator.ets b/entry/src/main/ets/common/DisplayCalculator.ets new file mode 100644 index 0000000000000000000000000000000000000000..a7ee966422e4039fee6e9f77935227f49bed133d --- /dev/null +++ b/entry/src/main/ets/common/DisplayCalculator.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Constants } from './Constants'; + +interface Size { + width: number, + height: number +} + +export default class DisplayCalculator { + public static calcSurfaceDisplaySize(screenWidth: number, screenHeight: number, defaultAspectRatio: number): Size { + const displaySize: Size = { + width: 1920, + height: 1080 + }; + if (AppStorage.get('deviceType') === Constants.TABLET || screenWidth > screenHeight) { + if (screenWidth / screenHeight > defaultAspectRatio) { + displaySize.width = Math.floor(screenHeight * defaultAspectRatio); + displaySize.height = Math.floor(screenHeight); + } else { + displaySize.width = Math.floor(screenWidth); + displaySize.height = Math.floor(screenWidth / defaultAspectRatio); + } + } else { + if (screenWidth / screenHeight > defaultAspectRatio) { + displaySize.width = Math.floor(screenHeight / defaultAspectRatio); + displaySize.height = Math.floor(screenHeight); + } else { + displaySize.width = Math.floor(screenWidth); + displaySize.height = Math.floor(screenWidth * defaultAspectRatio); + } + } + return displaySize; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/common/utils/Logger.ets b/entry/src/main/ets/common/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..a537bb46aebcef3da8bda8415e9e897476dcc8f7 --- /dev/null +++ b/entry/src/main/ets/common/utils/Logger.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xFF00; + } + + debug(...args: string[]) { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]) { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]) { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]) { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_Camera]'); \ No newline at end of file diff --git a/entry/src/main/ets/common/utils/MediaUtils.ets b/entry/src/main/ets/common/utils/MediaUtils.ets new file mode 100644 index 0000000000000000000000000000000000000000..4e9b3bdc395b8d3d064d716019b5f0dc718c3b0d --- /dev/null +++ b/entry/src/main/ets/common/utils/MediaUtils.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { common } from '@kit.AbilityKit'; +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import { fileIo } from '@kit.CoreFileKit'; +import Logger from './Logger'; + +let context = getContext(this) as common.Context; + +interface Result { + prefix: string, + suffix: string +} + +export default class MediaUtils { + private tag: string = 'MediaUtils'; + + public static getInstance() { + let instance: MediaUtils = new MediaUtils() + if (instance === undefined) { + instance = new MediaUtils(); + } + return instance; + } + + async createAndGetUri(mediaType: number) { + let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); + Logger.info(this.tag, `createAndGetUri`); + let photoType: photoAccessHelper.PhotoType = mediaType; + let info = this.getInfoFromType(mediaType) + let extension: string = info.suffix; + // Return the created media resource. + return await phAccessHelper.createAsset(photoType, extension) + } + + async getFdPath(uri: string) { + let file = fileIo.openSync(uri, fileIo.OpenMode.READ_WRITE); + let fd = file.fd; + Logger.info(this.tag, `fd = ${fd}`); + return fd; + } + + getInfoFromType(mediaType: number) { + let result: Result = { + prefix: '', + suffix: '' + }; + switch (mediaType) { + case photoAccessHelper.PhotoType.IMAGE: + result.prefix = 'IMG_'; + result.suffix = 'jpg'; + break; + case photoAccessHelper.PhotoType.VIDEO: + result.prefix = 'VID_'; + result.suffix = 'mp4'; + break; + } + return result; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..8b1b5b5c5fd75e9c4aa90374b454618720f567ca --- /dev/null +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +const TAG: string = 'EntryAbility'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.isLoggable(0x0000, TAG, hilog.LogLevel.INFO); + hilog.info(0x0000, TAG, '%{public}s', 'Ability onCreate'); + hilog.info(0x0000, TAG, '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); + hilog.info(0x0000, TAG, '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); + } + + onDestroy() { + hilog.isLoggable(0x0000, TAG, hilog.LogLevel.INFO); + hilog.info(0x0000, TAG, '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage) { + // Main window is created, set main page for this ability + hilog.info(0x0000, TAG, '%{public}s', 'Ability onWindowStageCreate'); + windowStage.loadContent('pages/Index', (err, data) => { + if (err.code) { + hilog.error(0x0000, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); + let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口 + // Set the window to full screen + let isLayoutFullScreen = true; + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen) + .then(() => { + hilog.info(0x0000, TAG, 'Succeeded in setting the window layout to full-screen mode. Data: %{public}s', + JSON.stringify(data) ?? ''); + }) + .catch((err: BusinessError) => { + hilog.error(0x0000, TAG, 'Failed to set the window layout to full-screen mode. Cause: %{public}s', + JSON.stringify(err) ?? ''); + }); + // Set the font color of the status bar. + let SystemBarProperties: window.SystemBarProperties = { + statusBarContentColor: '#FFFFFF' + }; + windowStage.getMainWindowSync().setWindowSystemBarProperties(SystemBarProperties); + }); + } +} diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..777d0f71456a5d0f9751ec239d408892e10fc943 --- /dev/null +++ b/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { abilityAccessCtrl } from '@kit.AbilityKit'; +import { common } from '@kit.AbilityKit'; +import { display } from '@kit.ArkUI'; +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import { dataSharePredicates } from '@kit.ArkData'; +import { image } from '@kit.ImageKit'; +import cameraDemo from 'libentry.so'; +import Logger from '../common/utils/Logger'; +import { DividerPage } from '../views/DividerPage'; +import { ModeSwitchPage } from '../views/ModeSwitchPage'; +import { FocusPage } from '../views/FocusPage'; +import { FocusAreaPage } from '../views/FocusAreaPage'; +import { Constants } from '../common/Constants'; +import { SettingDataObj } from '../common/Constants'; +import DisplayCalculator from '../common/DisplayCalculator'; + +const TAG: string = 'UI indexPage'; +let context = getContext(this) as common.UIAbilityContext; + +@Entry +@Component +struct Index { + // surfaceID value. + @State surfaceId: string = ''; + // Select mode. + @State modelBagCol: string = 'photo'; + // Exposure area. + @State focusPointBol: boolean = false; + // Finger click coordinates in the exposure area. + @State focusPointVal: Array = [0, 0]; + // Display where scale, focal length value, and focus box cannot coexist. + @State exposureBol: boolean = true; + // Exposure value. + @State exposureNum: number = 0; + // Countdown, photography, and video recording. + @State countdownNum: number = 0; + // Front and rear cameras. + @State cameraDeviceIndex: number = 0; + @State xComponentWidth: number = 384; + @State xComponentHeight: number = 450; + // Reference line. + @State referenceLineBol: boolean = false; + @StorageLink('defaultAspectRatio') @Watch('initXComponentSize') defaultAspectRatio: number + = Constants.MIN_ASPECT_RATIO; + @State onShow: boolean = false; + // Thumbnails + @StorageLink('thumbnail') thumbnail: image.PixelMap | undefined | string = ''; + // XComponentController. + private mXComponentController: XComponentController = new XComponentController(); + private screenHeight: number = 0; + private screenWidth: number = 0; + private settingDataObj: SettingDataObj = { + mirrorBol: false, + videoStabilizationMode: 0, + exposureMode: 1, + focusMode: 2, + photoQuality: 1, + locationBol: false, + photoFormat: 1, + photoOrientation: 0, + photoResolution: 0, + videoResolution: 0, + videoFrame: 0, + referenceLineBol: false + }; + private appContext: common.Context = getContext(this); + atManager = abilityAccessCtrl.createAtManager(); + + // Entry initialization function. + async aboutToAppear() { + await this.requestPermissionsFn(); + let mDisplay = display.getDefaultDisplaySync(); + this.screenWidth = px2vp(mDisplay.width); + this.screenHeight = px2vp(mDisplay.height); + this.initXComponentSize(); + } + + initXComponentSize(): void { + let defaultSize = + DisplayCalculator.calcSurfaceDisplaySize(this.screenWidth, this.screenHeight, this.defaultAspectRatio); + this.xComponentWidth = defaultSize.width; + this.xComponentHeight = defaultSize.height; + } + + async aboutToDisAppear() { + cameraDemo.releaseCamera(); + } + + // Obtain permissions. + async requestPermissionsFn() { + Logger.info(TAG, `requestPermissionsFn entry`); + try { + this.atManager.requestPermissionsFromUser(this.appContext, [ + 'ohos.permission.CAMERA', + 'ohos.permission.MICROPHONE', + 'ohos.permission.READ_MEDIA', + 'ohos.permission.WRITE_MEDIA', + 'ohos.permission.WRITE_IMAGEVIDEO', + 'ohos.permission.READ_IMAGEVIDEO' + ]).then(() => { + Logger.info(TAG, `request Permissions success!`); + this.onShow = true; + this.getThumbnail(); + }); + } catch (err) { + Logger.error(TAG, `requestPermissionsFromUser call Failed! error: ${err.code}`); + } + } + + async getThumbnail() { + let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); + let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); + let fetchOptions: photoAccessHelper.FetchOptions = { + fetchColumns: [], + predicates: predicates + }; + let fetchResult: photoAccessHelper.FetchResult = + await phAccessHelper.getAssets(fetchOptions); + let asset: photoAccessHelper.PhotoAsset = await fetchResult.getLastObject(); + console.info('asset displayName = ', asset.displayName); + asset.getThumbnail((err, pixelMap) => { + if (err === undefined) { + this.thumbnail = pixelMap; + console.info('getThumbnail successful ' + pixelMap); + } else { + console.error(`getThumbnail fail with error: ${err.code}, ${err.message}`); + } + }); + } + + async onPageShow() { + Logger.info(TAG, `onPageShow App`); + if (this.surfaceId && this.onShow) { + Logger.error(TAG, `initCamera start`); + cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex); + Logger.error(TAG, `initCamera end`); + } + this.getThumbnail(); + } + + onPageHide() { + Logger.info(TAG, `onPageHide App`); + this.thumbnail = '' + cameraDemo.releaseCamera(); + } + + build() { + Stack() { + if (this.onShow) { + // General appearance of a picture. + XComponent({ + id: 'componentId', + type: 'surface', + controller: this.mXComponentController + }) + .onLoad(async () => { + Logger.info(TAG, 'onLoad is called'); + this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); + Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`); + Logger.info(TAG, `initCamera start`); + cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex); + Logger.info(TAG, `initCamera end`); + }) + .backgroundColor(Color.Black) + .width(Constants.FULL_PERCENT) + .height(Constants.SEVENTY_PERCENT) + .margin({ + bottom: Constants.FIFTEEN_PERCENT + }) + + // Reference line. + DividerPage({ referenceLineBol: this.referenceLineBol }); + // Exposure frame and focus frame. + FocusPage({ + focusPointBol: $focusPointBol, + focusPointVal: $focusPointVal, + exposureBol: $exposureBol, + exposureNum: $exposureNum + }); + // Exposure focusing finger click area. + FocusAreaPage({ + focusPointBol: $focusPointBol, + focusPointVal: $focusPointVal, + exposureBol: $exposureBol, + exposureNum: $exposureNum, + xComponentWidth: this.xComponentWidth, + xComponentHeight: this.xComponentHeight + }); + // Reverse camera_Multiple workstations_Take photos_Video. + ModeSwitchPage({ + surfaceId: this.surfaceId, + cameraDeviceIndex: $cameraDeviceIndex, + countdownNum: $countdownNum + }); + } + } + .height(Constants.FULL_PERCENT) + .width(Constants.FULL_PERCENT) + .backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/views/DividerPage.ets b/entry/src/main/ets/views/DividerPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..5e2395a292a841ef5206373b502319bd5f3e5722 --- /dev/null +++ b/entry/src/main/ets/views/DividerPage.ets @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Constants } from '../common/Constants'; + +@Component +export struct DividerPage { + @Prop referenceLineBol: boolean + + build() { + if (this.referenceLineBol) { + Stack() { + Column() { + Divider() + .color(Color.White); + Divider() + .color(Color.White); + } + .justifyContent(FlexAlign.SpaceEvenly) + .height(Constants.FULL_PERCENT); + + Row() { + Divider() + .vertical(true) + .color(Color.White); + Divider() + .vertical(true) + .color(Color.White); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width(Constants.FULL_PERCENT); + } + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/views/FocusAreaPage.ets b/entry/src/main/ets/views/FocusAreaPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..55c5f2d3b40bc3a7a13325841208458e0bbe6280 --- /dev/null +++ b/entry/src/main/ets/views/FocusAreaPage.ets @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import cameraDemo from 'libentry.so'; +import Logger from '../common/utils/Logger'; +import { Constants } from '../common/Constants' + +const TAG: string = 'FocusAreaPage'; + +// Focus Area. +@Component +export struct FocusAreaPage { + @Link focusPointBol: boolean; + @Link focusPointVal: Array; + // Display where scale, focal length value, and focus box cannot coexist. + @Link exposureBol: boolean; + // Exposure value. + @Link exposureNum: number; + @Prop xComponentWidth: number; + @Prop xComponentHeight: number; + // Focusing area display box timer. + private areaTimer: number = -1; + // Sliding Exposure Up and Down. + private panOption: PanGestureOptions = new PanGestureOptions({ + direction: PanDirection.Up | PanDirection.Down, + fingers: 1 + }); + + build() { + Row() { + } + .width(Constants.FULL_PERCENT) + .height(Constants.SEVENTY_PERCENT) + .margin({ + bottom: Constants.FIFTEEN_PERCENT + }) + .opacity(1) + .id('FocusArea') + .onTouch((e: TouchEvent) => { + if (e.type === TouchType.Down) { + this.focusPointBol = true; + this.focusPointVal[0] = e.touches[0].windowX; + this.focusPointVal[1] = e.touches[0].windowY; + // Focus point. + cameraDemo.isFocusPoint( + e.touches[0].windowX / this.xComponentWidth, + e.touches[0].windowY / this.xComponentHeight + ); + cameraDemo.isMeteringPoint( + e.touches[0].windowX / this.xComponentWidth, + e.touches[0].windowY / this.xComponentHeight + 50 + ); + } + if (e.type === TouchType.Up) { + if (this.areaTimer) { + clearTimeout(this.areaTimer); + } + this.areaTimer = setTimeout(() => { + this.focusPointBol = false; + }, 3500); + } + }) + // Trigger this gesture event by dragging vertically with one finger. + .gesture( + PanGesture(this.panOption) + .onActionStart(() => { + Logger.info(TAG, 'PanGesture onActionStart'); + this.exposureBol = false; + }) + .onActionUpdate((event: GestureEvent) => { + let offset = -event.offsetY; + if (offset > Constants.EVENT_Y_OFFSET) { + this.exposureNum = 4; + } + if (offset < Constants.EVENT_Y_OFFSET1) { + this.exposureNum = -4; + } + if (offset > Constants.EVENT_Y_OFFSET1 && offset < Constants.EVENT_Y_OFFSET) { + this.exposureNum = Number((offset / 50).toFixed(1)); + } + // Exposure Compensation -4 +4. + cameraDemo.isExposureBiasRange(this.exposureNum); + Logger.info(TAG, `PanGesture onActionUpdate offset: ${offset}, exposureNum: ${this.exposureNum}`); + }) + .onActionEnd(() => { + this.exposureNum = 0; + this.exposureBol = true; + Logger.info(TAG, 'PanGesture onActionEnd end'); + }) + ) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/views/FocusPage.ets b/entry/src/main/ets/views/FocusPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..8815e515a9b5cdf3af44add8eca218882fc8d76e --- /dev/null +++ b/entry/src/main/ets/views/FocusPage.ets @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Constants } from '../common/Constants' + +// Exposure selection. +@Component +export struct FocusPage { + @Link focusPointBol: boolean; + @Link focusPointVal: Array; + // Display where scale, focal length value, and focus box cannot coexist. + @Link exposureBol: boolean; + // Exposure value. + @Link exposureNum: number; + + @Builder + BorderBuilder(width: EdgeWidths | Length, radius: Length | BorderRadiuses) { + Row() { + } + .border({ + width: width, + color: Color.White, + radius: radius + }) + .size({ + width: $r('app.float.focus_frame_size'), + height: $r('app.float.focus_frame_size') + }); + } + + build() { + Row() { + if (this.focusPointBol) { + if (this.exposureBol) { + // Focus frame. + Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) { + Flex({ justifyContent: FlexAlign.SpaceBetween }) { + this.BorderBuilder({ + left: $r('app.float.focus_frame_width'), + top: $r('app.float.focus_frame_width') + }, { + topLeft: $r('app.float.focus_frame_radius') + }); + this.BorderBuilder({ + right: $r('app.float.focus_frame_width'), + top: $r('app.float.focus_frame_width') + }, { + topRight: $r('app.float.focus_frame_radius') + }); + } + + Flex({ justifyContent: FlexAlign.SpaceBetween }) { + this.BorderBuilder({ + left: $r('app.float.focus_frame_width'), + bottom: $r('app.float.focus_frame_width') + }, { + bottomLeft: $r('app.float.focus_frame_radius') + }); + this.BorderBuilder({ + right: $r('app.float.focus_frame_width'), + bottom: $r('app.float.focus_frame_width') + }, { + bottomRight: $r('app.float.focus_frame_radius') + }); + } + } + .width($r('app.float.common_50')) + .height($r('app.float.common_50')) + .position({ + x: this.focusPointVal[0] - Constants.POSITION_25, + y: this.focusPointVal[1] - Constants.POSITION_25 + }); + + } else { + // Focus value. + Text(this.exposureNum + '') + .fontSize($r('app.float.focus_value_font_size')) + .fontColor(Color.White) + .fontWeight(Constants.FONT_WEIGHT_400) + .position({ + x: this.focusPointVal[0] - Constants.POSITION_58, + y: this.focusPointVal[1] - Constants.POSITION_30 + }); + // Scale value. + Flex() { + Column() { + Text('+4') + .fontColor(Color.White); + Text('0') + .margin({ + top: $r('app.float.common_50'), + bottom: $r('app.float.common_50') + }) + .fontColor(Color.White); + Text('-4') + .fontColor(Color.White); + } + .margin({ + right: $r('app.float.scale_value_margin_right') + }); + // Scale. + Column() { + Text('') + .height($r('app.float.scale_height_67')) + .border({ + width: { right: $r('app.float.scale_width_4') }, + color: Color.White, + radius: $r('app.float.scale_radius_2'), + style: BorderStyle.Dotted + }); + Text('') + .height($r('app.float.scale_height_8')) + .border({ + width: { right: $r('app.float.scale_width_8') }, + color: Color.White, + radius: $r('app.float.scale_radius_4'), + style: BorderStyle.Solid + }) + .margin({ top: $r('app.float.scale_width_4') }) + Text('') + .height($r('app.float.scale_height_67')) + .border({ + width: { right: $r('app.float.scale_width_4') }, + color: Color.White, + radius: $r('app.float.scale_radius_2'), + style: BorderStyle.Dotted + }) + .margin({ top: $r('app.float.scale_width_4') }); + } + }.position({ + x: this.focusPointVal[0] + Constants.POSITION_95, + y: this.focusPointVal[1] - Constants.POSITION_73 + }); + } + // Exposure icon. + Image($r('app.media.ic_public_brightness')) + .size({ + width: $r('app.float.exposure_icon_size'), + height: $r('app.float.exposure_icon_size') + }) + .position({ + x: this.focusPointVal[0] + Constants.POSITION_40, + y: this.focusPointVal[1] - Constants.POSITION_10 + }); + } + } + .height(Constants.FULL_PERCENT) + .width(Constants.FULL_PERCENT) + .id('FocusPage') + } +} \ No newline at end of file diff --git a/entry/src/main/ets/views/ModeSwitchPage.ets b/entry/src/main/ets/views/ModeSwitchPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..1d7bc72bb5f9467f18ca517aded2e596392c83e7 --- /dev/null +++ b/entry/src/main/ets/views/ModeSwitchPage.ets @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Reverse camera_ Multiple workstations_ Take photos Video. +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import { dataSharePredicates } from '@kit.ArkData'; +import { fileIo } from '@kit.CoreFileKit'; +import { BusinessError, deviceInfo } from '@kit.BasicServicesKit'; +import { common } from '@kit.AbilityKit'; +import { image } from '@kit.ImageKit'; +import { media } from '@kit.MediaKit'; +import cameraDemo from 'libentry.so'; +import Logger from '../common/utils/Logger'; +import MediaUtils from '../common/utils/MediaUtils'; +import { SettingDataObj } from '../common/Constants' +import { Constants } from '../common/Constants' + +let context = getContext(this) as common.UIAbilityContext; + +interface PhotoSettings { + quality: number, // Photo quality + rotation: number, // Photo direction + mirror: boolean, // Mirror Enable + latitude: number, // geographic location + longitude: number, // geographic location + altitude: number // geographic location +}; + +interface PhotoRotationMap { + rotation0: number, + rotation90: number, + rotation180: number, + rotation270: number, +}; + +@Component +export struct ModeSwitchPage { + @State videoId: string = ''; + @State mSurfaceId: string = ''; + // Front and rear cameras + @Link cameraDeviceIndex: number; + // SurfaceID + @Prop surfaceId: string; + // Countdown value + @Link countdownNum: number; + // Countdown timer + @State countTimerInt: number = -1; + @State countTimerOut: number = -1; + // Recording time + @State videoRecodeTime: number = 0; + // Recording time timer + @State timer: number = -1; + // Select mode + @State modelBagCol: string = Constants.PHOTO; + // Choose camera or capture + @State @Watch('onChangeIsModeBol') isModeBol: boolean = true; + // Thumbnails + @StorageLink('thumbnail') thumbnail: image.PixelMap | undefined | string = ''; + private tag: string = 'sample modeSwitchPage:'; + private mediaUtil = MediaUtils.getInstance(); + private photoAsset?: string; + private fd: number = -1; + private cameraSize: image.Size = { + width: 1280, + height: 720 + }; + private photoSettings: PhotoSettings = { + quality: 0, + rotation: 0, + mirror: false, + latitude: Constants.LATITUDE, + longitude: Constants.LONGITUDE, + altitude: Constants.ALTITUDE + }; + private mReceiver?: image.ImageReceiver; + private videoRecorder?: media.AVRecorder; + private videoConfig: media.AVRecorderConfig = { + audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, + videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, + profile: { + audioBitrate: Constants.AUDIO_BITRATE_SAMPLE_RATE, + audioChannels: Constants.AUDIO_CHANNELS, + audioCodec: media.CodecMimeType.AUDIO_AAC, + audioSampleRate: Constants.AUDIO_BITRATE_SAMPLE_RATE, + fileFormat: media.ContainerFormatType.CFT_MPEG_4, + videoBitrate: Constants.VIDEO_BITRATE, + videoCodec: media.CodecMimeType.VIDEO_AVC, + videoFrameWidth: Constants.VIDEO_FRAME_WIDTH, + videoFrameHeight: Constants.VIDEO_FRAME_HEIGHT, + videoFrameRate: Constants.VIDEO_FRAME_RATE + }, + url: '', + metadata: { + videoOrientation: '' + } + }; + private photoRotationMap: PhotoRotationMap = { + rotation0: 0, + rotation90: 90, + rotation180: 180, + rotation270: 270, + }; + private settingDataObj: SettingDataObj = { + mirrorBol: false, + videoStabilizationMode: 0, + exposureMode: 1, + focusMode: 2, + photoQuality: 1, + locationBol: false, + photoFormat: 1, + photoOrientation: 0, + photoResolution: 0, + videoResolution: 0, + videoFrame: 0, + referenceLineBol: false + }; + + // After pausing, click 'stop' to reset the pause to default. + onChangeIsModeBol() { + } + + // Countdown capture and video. + countTakeVideoFn() { + if (this.countdownNum) { + // Clear Countdown. + if (this.countTimerOut) { + clearTimeout(this.countTimerOut); + } + if (this.countTimerInt) { + clearInterval(this.countTimerInt); + } + // Turn on timer. + this.countTimerOut = setTimeout(() => { + // Determine whether it is in video or photo mode. + this.isVideoPhotoFn(); + }, this.countdownNum * 1000) + // Turn on timer. + this.countTimerInt = setInterval(() => { + this.countdownNum--; + if (this.countdownNum === 0) { + clearInterval(this.countTimerInt); + } + }, 1000) + } else { + this.isVideoPhotoFn(); + } + } + + async getVideoSurfaceID() { + Logger.info(this.tag, `getVideoSurfaceID`); + this.videoRecorder = await media.createAVRecorder(); + Logger.info(this.tag, `getVideoSurfaceID videoRecorder: ${this.videoRecorder}`); + + this.photoAsset = await this.mediaUtil.createAndGetUri(photoAccessHelper.PhotoType.VIDEO); + Logger.info(this.tag, `getVideoSurfaceID photoAsset: ${this.photoAsset}`); + + this.fd = await this.mediaUtil.getFdPath(this.photoAsset); + Logger.info(this.tag, `getVideoSurfaceID fd: ${this.fd}`); + + this.videoConfig.url = `fd://${this.fd}`; + Logger.info(this.tag, `getVideoSurfaceID videoConfig.url : ${this.videoConfig.url}`); + + if (deviceInfo.deviceType === Constants.DEFAULT) { + Logger.info(this.tag, `deviceType = default`); + this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_ES; + } + if (deviceInfo.deviceType === Constants.PHONE) { + Logger.info(this.tag, `deviceType = phone`) + this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV; + this.videoConfig.profile.videoCodec = media.CodecMimeType.VIDEO_AVC; + if (this.cameraDeviceIndex === 1) { + this.videoConfig.metadata = { + videoOrientation: '270' + }; + } else { + this.videoConfig.metadata = { + videoOrientation: '90' + }; + } + } + if (deviceInfo.deviceType === 'tablet') { + Logger.info(this.tag, `deviceType = tablet`); + this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV; + } + + this.videoConfig.profile.videoFrameWidth = cameraDemo.getVideoFrameWidth(); + this.videoConfig.profile.videoFrameHeight = cameraDemo.getVideoFrameHeight(); + this.videoConfig.profile.videoFrameRate = cameraDemo.getVideoFrameRate(); + + await this.videoRecorder.prepare(this.videoConfig); + this.videoId = await this.videoRecorder.getInputSurface(); + Logger.info(this.tag, `getVideoSurfaceID videoId: ${this.videoId}`); + } + + createImageReceiver() { + try { + this.mReceiver = image.createImageReceiver(this.cameraSize, 2000, 8); + Logger.info(this.tag, `createImageReceiver value: ${this.mReceiver} `); + this.mReceiver.on('imageArrival', () => { + Logger.info(this.tag, 'imageArrival start'); + if (this.mReceiver) { + this.mReceiver.readNextImage((err, image) => { + Logger.info(this.tag, 'readNextImage start'); + if (err || image === undefined) { + Logger.error(this.tag, 'readNextImage failed '); + return; + } + image.getComponent(4, (errMsg, img) => { + Logger.info(this.tag, 'getComponent start'); + if (errMsg || img === undefined) { + Logger.info(this.tag, 'getComponent failed '); + return; + } + let buffer = new ArrayBuffer(2048); + if (img.byteBuffer) { + buffer = img.byteBuffer; + } else { + Logger.error(this.tag, 'img.byteBuffer is undefined'); + } + this.savePicture(buffer, image); + }) + }) + } + }) + } catch { + Logger.info(this.tag, 'savePicture err'); + } + } + + // Read Image. + async savePicture(buffer: ArrayBuffer, img: image.Image) { + try { + Logger.info(this.tag, 'savePicture start'); + let photoAssetUri: string = await this.mediaUtil.createAndGetUri(photoAccessHelper.PhotoType.IMAGE); + let imgPhotoUri: string = photoAssetUri; + Logger.info(this.tag, `photoUri = ${imgPhotoUri}`); + let imgFd = await this.mediaUtil.getFdPath(imgPhotoUri); + Logger.info(this.tag, `fd = ${imgFd}`); + fileIo.writeSync(imgFd, buffer); + fileIo.closeSync(imgFd); + await img.release(); + Logger.info(this.tag, 'save image End'); + setTimeout(() => { + if (this.handleTakePicture) { + this.handleTakePicture(imgPhotoUri); + } + }, 10) + } catch (err) { + Logger.info(this.tag, 'savePicture err' + JSON.stringify(err.message)); + } + } + + async getPhotoSurfaceID() { + if (this.mReceiver) { + Logger.info(this.tag, 'imageReceiver has been created'); + } else { + this.createImageReceiver(); + } + if (this.mReceiver) { + this.mSurfaceId = await this.mReceiver.getReceivingSurfaceId(); + } + if (this.mSurfaceId) { + Logger.info(this.tag, `createImageReceiver mSurfaceId: ${this.mSurfaceId} `); + } else { + Logger.info(this.tag, `Get mSurfaceId failed `); + } + } + + // Determine the video or photo mode. + async isVideoPhotoFn() { + await this.getPhotoSurfaceID(); + + if (this.modelBagCol === Constants.PHOTO) { + cameraDemo.startPhotoOrVideo(this.modelBagCol, this.videoId, this.mSurfaceId); + } else if (this.modelBagCol === Constants.VIDEO) { + this.isModeBol = false; + if (this.timer) { + clearInterval(this.timer); + } + // Start record. + await this.getVideoSurfaceID(); + cameraDemo.startPhotoOrVideo(this.modelBagCol, this.videoId, this.mSurfaceId); + cameraDemo.videoOutputStart(); + if (this.videoRecorder) { + this.videoRecorder.start(); + } + } + } + + async handleTakePicture(thumbnail: string) { + this.thumbnail = thumbnail + Logger.info(this.tag, `takePicture end , thumbnail: ${this.thumbnail}`); + } + + aboutToDisappear() { + if (this.mReceiver) { + this.mReceiver.release().then(() => { + Logger.info(this.tag, 'release succeeded.'); + }).catch((error: BusinessError) => { + Logger.error(this.tag, `release failed, error: ${error}`); + }) + } + } + + build() { + if (this.isModeBol) { + Column() { + Text($r('app.string.photo')) + .size({ width: $r('app.float.model_size_width'), height: $r('app.float.model_size_height') }) + .borderRadius($r('app.float.border_radius')) + .fontSize($r('app.float.photo_video_font_size')) + .fontColor(Color.White) + .onClick(() => { + cameraDemo.releaseSession() + cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex) + this.modelBagCol = Constants.PHOTO + }) + }.position({ x: Constants.PHOTO_X_POSITION, y: Constants.Y_POSITION }) + + Column() { + Text($r('app.string.video')) + .size({ width: $r('app.float.model_size_width'), height: $r('app.float.model_size_height') }) + .borderRadius($r('app.float.border_radius')) + .fontSize($r('app.float.photo_video_font_size')) + .fontColor(Color.White) + .onClick(() => { + cameraDemo.releaseSession() + cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex) + this.modelBagCol = Constants.VIDEO + }) + }.position({ x: Constants.VIDEO_X_POSITION, y: Constants.Y_POSITION }) + + // Album. + Column() { + Row() { + if (this.modelBagCol === Constants.PHOTO) { + Image(this.thumbnail || $r('app.media.camera_thumbnail_4x')) + .borderRadius(px2vp(Constants.ICON_SIZE / 2)) + .syncLoad(true) + .objectFit(ImageFit.Fill) + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + } else { + Image(this.thumbnail || $r('app.media.camera_thumbnail_4x')) + .borderRadius(px2vp(Constants.ICON_SIZE / 2)) + .objectFit(ImageFit.Fill) + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + } + } + .onClick(() => { + if (deviceInfo.deviceType === Constants.DEFAULT) { + context.startAbility({ + bundleName: 'com.ohos.photos', + abilityName: 'com.ohos.photos.MainAbility' + }) + } else if (deviceInfo.deviceType === Constants.PHONE) { + context.startAbility({ + bundleName: 'com.huawei.hmos.photos', + abilityName: 'com.huawei.hmos.photos.MainAbility' + }) + } + }) + } + .position({ x: Constants.ALBUM_X_POSITION, y: Constants.ICON_Y_POSITION }) + .id('Thumbnail') + + // Capture video icon. + Column() { + Row() { + if (this.modelBagCol === Constants.PHOTO) { + Image($r('app.media.camera_take_photo_4x')) + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + .onClick(() => { + // Countdown camera recording - default camera recording. + this.countTakeVideoFn(); + }) + } else { + Image($r('app.media.camera_take_video_4x')) + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + .onClick(() => { + // Countdown camera recording - default camera recording. + this.countTakeVideoFn(); + }) + } + } + }.position({ x: Constants.CAPTURE_X_POSITION, y: Constants.ICON_Y_POSITION }) + .id('CaptureOrVideoButton') + + // Front and rear camera switching. + Column() { + Row() { + Image($r('app.media.camera_switch_4x')) + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + .onClick(async () => { + // Switching cameras. + this.cameraDeviceIndex ? this.cameraDeviceIndex = 0 : this.cameraDeviceIndex = 1; + // Clear configuration. + cameraDemo.releaseSession(); + // Start preview. + cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex); + }) + } + }.position({ x: Constants.SWITCH_X_POSITION, y: Constants.ICON_Y_POSITION }) + .id('SwitchCameraButton') + } else { + Column() { + // Video capture button. + Image($r('app.media.camera_take_photo_4x')) + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + .onClick(() => { + cameraDemo.takePictureWithSettings(this.photoSettings); + }) + }.position({ x: Constants.ALBUM_X_POSITION, y: Constants.ICON_Y_POSITION }) + .id('VideoCaptureButton') + + Column() { + Row() { + Column() { + // video stop button. + Image($r('app.media.camera_pause_video_4x')) + .size({ width: $r('app.float.video_stop_size'), height: $r('app.float.video_stop_size') }) + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + .id('StopVideo') + .onClick(() => { + if (this.timer) { + clearInterval(this.timer); + } + // Stop video. + this.stopVideo().then(() => { + this.videoRecodeTime = 0; + this.isModeBol = true; + }) + }) + } + } + .width(px2vp(Constants.ICON_SIZE)) + .height(px2vp(Constants.ICON_SIZE)) + }.position({ x: Constants.CAPTURE_X_POSITION, y: Constants.ICON_Y_POSITION }) + } + } + + async stopVideo() { + try { + if (this.videoRecorder) { + await this.videoRecorder.stop(); + await this.videoRecorder.release(); + } + cameraDemo.videoOutputStopAndRelease(); + let result: photoAccessHelper.PhotoAsset | undefined = undefined; + if (this.photoAsset) { + await fileIo.close(this.fd); + setTimeout(async () => { + let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); + let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); + let fetchOptions: photoAccessHelper.FetchOptions = { + fetchColumns: [], + predicates: predicates + }; + let fetchResult: photoAccessHelper.FetchResult = + await phAccessHelper.getAssets(fetchOptions); + let photoAssetList: Array = await fetchResult.getAllObjects(); + photoAssetList.forEach((item: photoAccessHelper.PhotoAsset) => { + if (item.uri === this.photoAsset) { + Logger.info(this.tag, `item.uri = ${item.uri}`) + result = item + } + }) + try { + // Get video thumbnail. + this.thumbnail = await result?.getThumbnail(); + Logger.info(this.tag, 'videoThumbnail = ' + JSON.stringify(this.thumbnail)); + } catch (err) { + Logger.error(this.tag, 'videoThumbnail err----------:' + JSON.stringify(err.message)); + } + }, 1000) + } + Logger.info(this.tag, 'stopVideo end'); + } catch (err) { + Logger.error(this.tag, 'stopVideo err: ' + JSON.stringify(err)); + } + return; + } +} \ No newline at end of file diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9054eae6785dab8826ef975b9700193def67bbc --- /dev/null +++ b/entry/src/main/module.json5 @@ -0,0 +1,70 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.CAMERA", + "reason": "$string:ALLOW_WLAN", + "usedScene": {} + }, + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:ALLOW_WLAN", + "usedScene": {} + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:ALLOW_WLAN", + "usedScene": {} + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:ALLOW_WLAN", + "usedScene": {} + }, + { + "name": "ohos.permission.WRITE_IMAGEVIDEO", + "reason": "$string:reason", + "usedScene": {} + }, + { + "name": "ohos.permission.READ_IMAGEVIDEO", + "reason": "$string:reason", + "usedScene": {} + } + ] + } +} \ No newline at end of file diff --git a/entry/src/main/resources/base/element/color.json b/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..8b3539b68d002801b5ed92b83a2d20fa712a29b9 --- /dev/null +++ b/entry/src/main/resources/base/element/color.json @@ -0,0 +1,16 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + }, + { + "name": "white", + "value": "#FFFFFF" + }, + { + "name": "theme_color", + "value": "#FF0034" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/element/float.json b/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..4ea0f238c8ce59de5c57fedd440afa2de9cb168c --- /dev/null +++ b/entry/src/main/resources/base/element/float.json @@ -0,0 +1,76 @@ +{ + "float": [ + { + "name": "model_size_width", + "value": "64vp" + }, + { + "name": "model_size_height", + "value": "28vp" + }, + { + "name": "video_stop_size", + "value": "25vp" + }, + { + "name": "focus_frame_size", + "value": "15vp" + }, + { + "name": "exposure_icon_size", + "value": "24vp" + }, + { + "name": "focus_frame_width", + "value": "1.6vp" + }, + { + "name": "focus_frame_radius", + "value": "10vp" + }, + { + "name": "scale_width_4", + "value": "4vp" + }, + { + "name": "scale_width_8", + "value": "8vp" + }, + { + "name": "focus_value_font_size", + "value": "60fp" + }, + { + "name": "border_radius", + "value": "14vp" + }, + { + "name": "photo_video_font_size", + "value": "15fp" + }, + { + "name": "common_50", + "value": "50vp" + }, + { + "name": "scale_height_67", + "value": "67vp" + }, + { + "name": "scale_height_8", + "value": "8vp" + }, + { + "name": "scale_radius_4", + "value": "4vp" + }, + { + "name": "scale_radius_2", + "value": "2vp" + }, + { + "name": "scale_value_margin_right", + "value": "9vp" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..c2e8e96d56e48afc1284869a6f8428549161ffab --- /dev/null +++ b/entry/src/main/resources/base/element/string.json @@ -0,0 +1,24 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ndk_camera_demo" + }, + { + "name": "photo", + "value": "photo" + }, + { + "name": "video", + "value": "video" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/background.png b/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/entry/src/main/resources/base/media/background.png differ diff --git a/entry/src/main/resources/base/media/camera_pause_video_4x.png b/entry/src/main/resources/base/media/camera_pause_video_4x.png new file mode 100644 index 0000000000000000000000000000000000000000..9d7ff8649db4f9fac5a58da0a6c3f1812d9b4c68 Binary files /dev/null and b/entry/src/main/resources/base/media/camera_pause_video_4x.png differ diff --git a/entry/src/main/resources/base/media/camera_switch_4x.png b/entry/src/main/resources/base/media/camera_switch_4x.png new file mode 100644 index 0000000000000000000000000000000000000000..6cd8cb71f8c263dd222b7e03f2a844a3f500a328 Binary files /dev/null and b/entry/src/main/resources/base/media/camera_switch_4x.png differ diff --git a/entry/src/main/resources/base/media/camera_take_photo_4x.png b/entry/src/main/resources/base/media/camera_take_photo_4x.png new file mode 100644 index 0000000000000000000000000000000000000000..6811fa6c7a9cc75230c2f2f2141006246ecd41f8 Binary files /dev/null and b/entry/src/main/resources/base/media/camera_take_photo_4x.png differ diff --git a/entry/src/main/resources/base/media/camera_take_video_4x.png b/entry/src/main/resources/base/media/camera_take_video_4x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c44c6c9af9bd2b2044907876a76347d34f43635 Binary files /dev/null and b/entry/src/main/resources/base/media/camera_take_video_4x.png differ diff --git a/entry/src/main/resources/base/media/camera_thumbnail_4x.png b/entry/src/main/resources/base/media/camera_thumbnail_4x.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbeb3fb04fbc58eebed2e5a28fbb2e96b39b792 Binary files /dev/null and b/entry/src/main/resources/base/media/camera_thumbnail_4x.png differ diff --git a/entry/src/main/resources/base/media/flash_always_on.svg b/entry/src/main/resources/base/media/flash_always_on.svg new file mode 100644 index 0000000000000000000000000000000000000000..3f9f710f0d7fd21153ede07520121a328aa9bbd3 --- /dev/null +++ b/entry/src/main/resources/base/media/flash_always_on.svg @@ -0,0 +1,18 @@ + + + + ic/camera/public/flash_always_on + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/foreground.png b/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/entry/src/main/resources/base/media/foreground.png differ diff --git a/entry/src/main/resources/base/media/ic_camera_ic_camera_radio_close.svg b/entry/src/main/resources/base/media/ic_camera_ic_camera_radio_close.svg new file mode 100644 index 0000000000000000000000000000000000000000..ead57d515dd1b0c2691e5809183877e120ecfde0 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_ic_camera_radio_close.svg @@ -0,0 +1,8 @@ + + + ic_camera_ic_camera_radio_close + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_pad.svg b/entry/src/main/resources/base/media/ic_camera_pad.svg new file mode 100644 index 0000000000000000000000000000000000000000..16f06746e38339eab8cff4b22a87a186ea1c4681 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_pad.svg @@ -0,0 +1,13 @@ + + + ic_camera_pad + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_phone.svg b/entry/src/main/resources/base/media/ic_camera_phone.svg new file mode 100644 index 0000000000000000000000000000000000000000..c2cc3251e233cbd25bb4c37ea98a2e0c46616cda --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_phone.svg @@ -0,0 +1,13 @@ + + + ic_camera_phone + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_progressBar_circle.svg b/entry/src/main/resources/base/media/ic_camera_progressBar_circle.svg new file mode 100644 index 0000000000000000000000000000000000000000..10ffe5cf68f420648c089849b90120dfd4e4bcad --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_progressBar_circle.svg @@ -0,0 +1,8 @@ + + + ic_camera_progressBar_circle + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_public_flash_auto.svg b/entry/src/main/resources/base/media/ic_camera_public_flash_auto.svg new file mode 100644 index 0000000000000000000000000000000000000000..5e4b45fcd70d9ff6851ddaa2b20563182176057e --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_public_flash_auto.svg @@ -0,0 +1,13 @@ + + + ic_camera_public_flash_auto + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_public_flash_auto_white.svg b/entry/src/main/resources/base/media/ic_camera_public_flash_auto_white.svg new file mode 100644 index 0000000000000000000000000000000000000000..5e4b45fcd70d9ff6851ddaa2b20563182176057e --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_public_flash_auto_white.svg @@ -0,0 +1,13 @@ + + + ic_camera_public_flash_auto + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_public_flash_off.svg b/entry/src/main/resources/base/media/ic_camera_public_flash_off.svg new file mode 100644 index 0000000000000000000000000000000000000000..deaae7f92646fc34753fd9c3666ab7d924e68e7a --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_public_flash_off.svg @@ -0,0 +1,13 @@ + + + ic_camera_public_flash_off + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_public_flash_on.svg b/entry/src/main/resources/base/media/ic_camera_public_flash_on.svg new file mode 100644 index 0000000000000000000000000000000000000000..ebd9922b5ea9ec16c902c07ba48c07839a1913f9 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_public_flash_on.svg @@ -0,0 +1,13 @@ + + + ic_camera_public_flash_on + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_radio_open.svg b/entry/src/main/resources/base/media/ic_camera_radio_open.svg new file mode 100644 index 0000000000000000000000000000000000000000..16ef89b4eff013772321a521a3a5c96010ad7383 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_radio_open.svg @@ -0,0 +1,24 @@ + + + ic_camera_radio_open + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set__antishake.svg b/entry/src/main/resources/base/media/ic_camera_set__antishake.svg new file mode 100644 index 0000000000000000000000000000000000000000..f7c0e9f80ffe5431906862801f3cbf9c1ecc2fff --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set__antishake.svg @@ -0,0 +1,7 @@ + + + ic_camera_set__antishake + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set__mirror.svg b/entry/src/main/resources/base/media/ic_camera_set__mirror.svg new file mode 100644 index 0000000000000000000000000000000000000000..5682345edcfba2b9b50fcf99605c807b35c510a9 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set__mirror.svg @@ -0,0 +1,9 @@ + + + ic_camera_set__mirror + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_af.svg b/entry/src/main/resources/base/media/ic_camera_set_af.svg new file mode 100644 index 0000000000000000000000000000000000000000..97618096eb370f76a39a9b1d3cf09f0d3a0f688b --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_af.svg @@ -0,0 +1,7 @@ + + + ic_camera_set_focus + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_arrow.svg b/entry/src/main/resources/base/media/ic_camera_set_arrow.svg new file mode 100644 index 0000000000000000000000000000000000000000..97025a536ba73799ac3fba4710ff6f38f98a8586 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_arrow.svg @@ -0,0 +1,13 @@ + + + ic_camera_set_arrow + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_checked.svg b/entry/src/main/resources/base/media/ic_camera_set_checked.svg new file mode 100644 index 0000000000000000000000000000000000000000..3ff7d8c2683484e5211f5ead9451e33a52b11a62 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_checked.svg @@ -0,0 +1,13 @@ + + + ic_camera_set_checked + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_class.svg b/entry/src/main/resources/base/media/ic_camera_set_class.svg new file mode 100644 index 0000000000000000000000000000000000000000..c926c738af12619b9d23e7475ca290dd4f6f2900 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_class.svg @@ -0,0 +1,8 @@ + + + ic_camera_set_class + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_exposure.svg b/entry/src/main/resources/base/media/ic_camera_set_exposure.svg new file mode 100644 index 0000000000000000000000000000000000000000..0ffbb1531fd3c148ff7f8147f0754d63cf0fef13 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_exposure.svg @@ -0,0 +1,7 @@ + + + ic_camera_set_exposure + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_focus.svg b/entry/src/main/resources/base/media/ic_camera_set_focus.svg new file mode 100644 index 0000000000000000000000000000000000000000..eb597d91d1a247cbe433ac96fee8b195179c6c04 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_focus.svg @@ -0,0 +1,9 @@ + + + ic_camera_set_focus + + + AF + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_format.svg b/entry/src/main/resources/base/media/ic_camera_set_format.svg new file mode 100644 index 0000000000000000000000000000000000000000..5f89497f9f3812e230ec675bc803872987f78f36 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_format.svg @@ -0,0 +1,7 @@ + + + ic_camera_set_format + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_line.svg b/entry/src/main/resources/base/media/ic_camera_set_line.svg new file mode 100644 index 0000000000000000000000000000000000000000..b5fa81891c209f76622304c1cbe8546ec5b7ffdd --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_line.svg @@ -0,0 +1,13 @@ + + + ic_camera_set_line + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_location.svg b/entry/src/main/resources/base/media/ic_camera_set_location.svg new file mode 100644 index 0000000000000000000000000000000000000000..3ac75572c19716e11a09a3a510827aa8542316dc --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_location.svg @@ -0,0 +1,7 @@ + + + ic_camera_set_location + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_pic_resolution.svg b/entry/src/main/resources/base/media/ic_camera_set_pic_resolution.svg new file mode 100644 index 0000000000000000000000000000000000000000..ad62896cb9de210c88b32a7b788cba08956db503 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_pic_resolution.svg @@ -0,0 +1,7 @@ + + + ic_camera_set_pic_resolution + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_quality.svg b/entry/src/main/resources/base/media/ic_camera_set_quality.svg new file mode 100644 index 0000000000000000000000000000000000000000..e7b26575122dc801ef3e651a1d1d59b3afaef8a7 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_quality.svg @@ -0,0 +1,7 @@ + + + ic_camera_set_quality + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_video_rate.svg b/entry/src/main/resources/base/media/ic_camera_set_video_rate.svg new file mode 100644 index 0000000000000000000000000000000000000000..ddb1d72b12be738f34a62a3a7b2599d43a64b038 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_video_rate.svg @@ -0,0 +1,13 @@ + + + ic_camera_set_video_rate + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_set_video_resolution.svg b/entry/src/main/resources/base/media/ic_camera_set_video_resolution.svg new file mode 100644 index 0000000000000000000000000000000000000000..535625a78e5a372d9600a8a681f7c0fdd8b26325 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_set_video_resolution.svg @@ -0,0 +1,7 @@ + + + ic_camera_set_video_resolution + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_switch_off.svg b/entry/src/main/resources/base/media/ic_camera_switch_off.svg new file mode 100644 index 0000000000000000000000000000000000000000..0e4631448c6d77c116487e56da83ce44263961c9 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_switch_off.svg @@ -0,0 +1,9 @@ + + + ic_camera_switch_off + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_switch_off2.svg b/entry/src/main/resources/base/media/ic_camera_switch_off2.svg new file mode 100644 index 0000000000000000000000000000000000000000..0b4e58935df66e250a89c9dd787c08480b02a756 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_switch_off2.svg @@ -0,0 +1,14 @@ + + + ic_camera_switch_off 2 + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_video_close.svg b/entry/src/main/resources/base/media/ic_camera_video_close.svg new file mode 100644 index 0000000000000000000000000000000000000000..476634fbbfb2959b0343cbb8e55db9c1c4211cdb --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_video_close.svg @@ -0,0 +1,7 @@ + + + ic_camera_video_close + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_video_off.svg b/entry/src/main/resources/base/media/ic_camera_video_off.svg new file mode 100644 index 0000000000000000000000000000000000000000..854f409f19546cfaa313609ef3979f22fb0dddf7 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_video_off.svg @@ -0,0 +1,13 @@ + + + ic_camera_video_off + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_camera_video_on.svg b/entry/src/main/resources/base/media/ic_camera_video_on.svg new file mode 100644 index 0000000000000000000000000000000000000000..6da84352329a4c864760c5e6bb3a82f5260ff6bd --- /dev/null +++ b/entry/src/main/resources/base/media/ic_camera_video_on.svg @@ -0,0 +1,7 @@ + + + ic_camera_video_on + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_public_brightness.svg b/entry/src/main/resources/base/media/ic_public_brightness.svg new file mode 100644 index 0000000000000000000000000000000000000000..b74c726facde9fcc364fa4750161d05bd8034e53 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_public_brightness.svg @@ -0,0 +1,7 @@ + + + ic_public_brightness + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/ic_public_brightness_filled.svg b/entry/src/main/resources/base/media/ic_public_brightness_filled.svg new file mode 100644 index 0000000000000000000000000000000000000000..7c219cee8c2cb2e84e05bbf381c805b157f76dd2 --- /dev/null +++ b/entry/src/main/resources/base/media/ic_public_brightness_filled.svg @@ -0,0 +1,7 @@ + + + ic_public_brightness_filled + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/icon.png b/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/entry/src/main/resources/base/media/icon.png differ diff --git a/entry/src/main/resources/base/media/icon_camera_setting.svg b/entry/src/main/resources/base/media/icon_camera_setting.svg new file mode 100644 index 0000000000000000000000000000000000000000..60c32abaa0be5b6064ea96910f1aa0f8117a3cf0 --- /dev/null +++ b/entry/src/main/resources/base/media/icon_camera_setting.svg @@ -0,0 +1,13 @@ + + + icon_camera_setting + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/icon_camera_setting_timer.svg b/entry/src/main/resources/base/media/icon_camera_setting_timer.svg new file mode 100644 index 0000000000000000000000000000000000000000..853e04954758f26560ceb3ca1d246206dfdca3c3 --- /dev/null +++ b/entry/src/main/resources/base/media/icon_camera_setting_timer.svg @@ -0,0 +1,13 @@ + + + icon_camera_setting_timer + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/icon_camera_setting_timer_on.svg b/entry/src/main/resources/base/media/icon_camera_setting_timer_on.svg new file mode 100644 index 0000000000000000000000000000000000000000..5f8413271ee689148263d8db7dc05a54e1bc4a20 --- /dev/null +++ b/entry/src/main/resources/base/media/icon_camera_setting_timer_on.svg @@ -0,0 +1,13 @@ + + + icon_camera_setting_timer_on + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/icon_camera_setting_timer_on_balk.svg b/entry/src/main/resources/base/media/icon_camera_setting_timer_on_balk.svg new file mode 100644 index 0000000000000000000000000000000000000000..875ecca5f058f9800a092b9d4f31be06fc662593 --- /dev/null +++ b/entry/src/main/resources/base/media/icon_camera_setting_timer_on_balk.svg @@ -0,0 +1,13 @@ + + + icon_camera_setting_timer_on + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/layered_image.json b/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/pic_avatar_radio01.png b/entry/src/main/resources/base/media/pic_avatar_radio01.png new file mode 100644 index 0000000000000000000000000000000000000000..ce06ac8d459c38abc90be16a3ba7366f0ab0f179 Binary files /dev/null and b/entry/src/main/resources/base/media/pic_avatar_radio01.png differ diff --git a/entry/src/main/resources/base/media/pic_avatar_radio02.png b/entry/src/main/resources/base/media/pic_avatar_radio02.png new file mode 100644 index 0000000000000000000000000000000000000000..706e376770f4dec127614af1c866aa3fc00c8557 Binary files /dev/null and b/entry/src/main/resources/base/media/pic_avatar_radio02.png differ diff --git a/entry/src/main/resources/base/media/pic_avatar_regular.png b/entry/src/main/resources/base/media/pic_avatar_regular.png new file mode 100644 index 0000000000000000000000000000000000000000..27209339d1e0ce6e815ab1a63e077efb2b9fdb2c Binary files /dev/null and b/entry/src/main/resources/base/media/pic_avatar_regular.png differ diff --git a/entry/src/main/resources/base/media/pic_camera_line.png b/entry/src/main/resources/base/media/pic_camera_line.png new file mode 100644 index 0000000000000000000000000000000000000000..ce54c74f2e1afb230b7344a562dc3a4e1aa47d89 Binary files /dev/null and b/entry/src/main/resources/base/media/pic_camera_line.png differ diff --git a/entry/src/main/resources/base/media/pic_camera_mirror.png b/entry/src/main/resources/base/media/pic_camera_mirror.png new file mode 100644 index 0000000000000000000000000000000000000000..be57cb99c63f9f236ee93d9239fed7d46eafb885 Binary files /dev/null and b/entry/src/main/resources/base/media/pic_camera_mirror.png differ diff --git a/entry/src/main/resources/base/media/pic_popup_left.png b/entry/src/main/resources/base/media/pic_popup_left.png new file mode 100644 index 0000000000000000000000000000000000000000..e411072ccc63e4349a8767b6b7ee3eb6229e3def Binary files /dev/null and b/entry/src/main/resources/base/media/pic_popup_left.png differ diff --git a/entry/src/main/resources/base/media/pic_popup_right.png b/entry/src/main/resources/base/media/pic_popup_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3e0fbf06a98bb71c7d38ce5d9cae10e47d71ce78 Binary files /dev/null and b/entry/src/main/resources/base/media/pic_popup_right.png differ diff --git a/entry/src/main/resources/base/media/startIcon.png b/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/entry/src/main/resources/base/media/startIcon.png differ diff --git a/entry/src/main/resources/base/media/switch_camera.svg b/entry/src/main/resources/base/media/switch_camera.svg new file mode 100644 index 0000000000000000000000000000000000000000..43dab70a87aab51158e47ad6b57fdcee6cf71556 --- /dev/null +++ b/entry/src/main/resources/base/media/switch_camera.svg @@ -0,0 +1,7 @@ + + + switch_camera + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/entry/src/main/resources/en_US/element/string.json b/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..c2e8e96d56e48afc1284869a6f8428549161ffab --- /dev/null +++ b/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,24 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ndk_camera_demo" + }, + { + "name": "photo", + "value": "photo" + }, + { + "name": "video", + "value": "video" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/zh_CN/element/string.json b/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..432bd4552af19d4d7753eaf62314fd6fc3090a66 --- /dev/null +++ b/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,24 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ndk_camera_demo" + }, + { + "name": "photo", + "value": "拍照" + }, + { + "name": "video", + "value": "录像" + } + ] +} \ No newline at end of file diff --git a/hvigor/hvigor-config.json5 b/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f94653eefb816c14f3d0e2f67bb3b0fa7bdf459c --- /dev/null +++ b/hvigor/hvigor-config.json5 @@ -0,0 +1,21 @@ +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */ + } +} \ No newline at end of file diff --git a/hvigorfile.ts b/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3cb9f1a87a81687554a76283af8df27d8bda775 --- /dev/null +++ b/hvigorfile.ts @@ -0,0 +1,6 @@ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/oh-package.json5 b/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c78704afa27de240fb2a3d2f1af99dab20d5c366 --- /dev/null +++ b/oh-package.json5 @@ -0,0 +1,15 @@ +{ + "modelVersion": "5.0.0", + "name": "camera", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.17", + "@ohos/hamock": "1.0.0" + } +} \ No newline at end of file diff --git a/screenshot/device/ndk_camera.gif b/screenshot/device/ndk_camera.gif new file mode 100644 index 0000000000000000000000000000000000000000..fd1718dba8574787b680aac475d8943353c64f67 Binary files /dev/null and b/screenshot/device/ndk_camera.gif differ