diff --git a/code/DocsSample/Media/AVRecorder/.gitignore b/code/DocsSample/Media/AVRecorder/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/AppScope/app.json5 b/code/DocsSample/Media/AVRecorder/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7e5ebd28f973a145f925c54cfa3a2ed47549f9fc --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 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. + */ +{ + "app": { + "bundleName": "com.samples.avrecorder", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/code/DocsSample/Media/AVRecorder/AppScope/resources/base/element/string.json b/code/DocsSample/Media/AVRecorder/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..c341df60c8e042f523ff9a6d5947361e8871c623 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "AVRecorderSample" + } + ] +} diff --git a/code/DocsSample/Media/AVRecorder/AppScope/resources/base/media/app_icon.png b/code/DocsSample/Media/AVRecorder/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/code/DocsSample/Media/AVRecorder/AppScope/resources/base/media/app_icon.png differ diff --git a/code/DocsSample/Media/AVRecorder/README_zh.md b/code/DocsSample/Media/AVRecorder/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..45da4c71344708f10cafefb08c3676ed896abc34 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/README_zh.md @@ -0,0 +1,79 @@ +# AVRecorder Sample + +## 介绍 +AVRecorder Sample 调用了媒体 AVRecorder 组件提供的接口能力,提供音视频录制的功能,包含: +- 音视频录制 +- 音频录制/视频录制 +- 保存录制文件到应用沙箱/图库 + +使用说明 + +1. 启动应用,首次启动需要用户授予访问相机、麦克风、保存文件的权限。 +2. 进入Demo界面,点击 Start 按钮,开始录制。 +3. 录制过程中,可随时点击Pause、Resume进行暂停、恢复。 +4. 录制完成后,点击Stop结束录制。 +5. 录制生成的文件保存在沙箱目录或图库。 + +## 工程目录 + +仓目录结构如下: + +``` +entry/src/main # AVRecorder demo业务代码 +│ module.json5 # 编译相关文件 +├─cpp # ndk相关文件 +│ │ CMakeLists.txt +│ │ main.cpp +│ │ main.h +│ │ camera_manager.cpp +│ │ camera_manager.h +│ │ log_common.h +│ │ sample_info.h +│ │ muxer.cpp +│ │ muxer.h +│ │ video_encoder_sample.cpp +│ │ video_encoder_sample.h +│ └─types # 映射文件 +│ +├─ets # 页面相关实现 +│ ├─entryability +│ ├─entrybackupability +│ └─pages # ets 页面实现 +│ Index.ets # 首页 +│ +└─resources # 资源文件 +``` + +## 相关权限 + +ohos.permission.MICROPHONE +ohos.permission.INTERNET +ohos.permission.CAMERA +ohos.permission.MEDIA_LOCATION +ohos.permission.KEEP_BACKGROUND_RUNNING +ohos.permission.READ_MEDIA +ohos.permission.WRITE_MEDIA + +## 依赖 + +不涉及 + +## 约束和限制 + +1. 本示例支持标准系统上运行,支持设备:RK3568; + +2. 本示例支持API19版本SDK,版本号:5.1.1.62; + +3. 本示例已支持使DevEco Studio 5.0.5 Beta1(构建版本:5.0.13.100,构建于:2025年4月25日)编译运行 + +## 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/Media/AVRecorder/ > .git/info/sparse-checkout +git remote add origin https://gitee.com/openharmony/applications_app_samples.git +git pull origin master +``` \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/build-profile.json5 b/code/DocsSample/Media/AVRecorder/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b3f905f913d30542fda045d9f6d062164775a087 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/build-profile.json5 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 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. + */ + + { + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + //指定HarmonyOS应用/服务编译时的版本 + "compileSdkVersion": 19, + //指定HarmonyOS应用/服务兼容的最低版本 + "compatibleSdkVersion": 19, + //指定HarmonyOS应用/服务目标版本。若没有设置,默认为compatibleSdkVersion + "runtimeOS": "OpenHarmony", + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/.gitignore b/code/DocsSample/Media/AVRecorder/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/build-profile.json5 b/code/DocsSample/Media/AVRecorder/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d7448c43ab68b8424a2571a800a66245d348d81d --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/build-profile.json5 @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2025 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. + */ + +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + "nativeLib": { + "debugSymbol": { + "strip": true, + "exclude": [] + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/hvigorfile.ts b/code/DocsSample/Media/AVRecorder/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbe3314801c1c09764553b487e55ae5f3b201365 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2025 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 { 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/code/DocsSample/Media/AVRecorder/entry/oh-package.json5 b/code/DocsSample/Media/AVRecorder/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a91c79fda8de4c6c5d7646443c174a23ab7e70f2 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/oh-package.json5 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 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. + */ + +{ + "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/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/CMakeLists.txt b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e8821ce40b9a05c2a26a0d3f3867c42bea41df2 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,18 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.5.0) +project(AVRecorder) + +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 muxer.cpp video_encoder_sample.cpp) +target_link_libraries(entry PUBLIC libace_napi.z.so libavrecorder.so libhilog_ndk.z.so libnative_window.so + libohcamera.so libnative_buffer.so libnative_media_avdemuxer.so libnative_media_avmuxer.so + libnative_buffer.so libnative_media_core.so libnative_media_adec.so libnative_media_avsource.so + libnative_media_codecbase.so libnative_media_venc.so libmedia_asset_manager.so) \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.cpp b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76240c7dfb1ab4f2657392d10f04c8ae6cd0a984 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.cpp @@ -0,0 +1,1044 @@ +/* + * Copyright (c) 2025 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 "camera_manager.h" + +#define LOG_TAG "DEMO:" +#define LOG_DOMAIN 0x3200 + +namespace OHOS_CAMERA_SAMPLE { +NDKCamera *NDKCamera::ndkCamera_ = nullptr; +std::mutex NDKCamera::mtx_; +const std::unordered_map g_int32ToCameraSceneMode = { + {1, Camera_SceneMode::NORMAL_PHOTO}, + {2, Camera_SceneMode::NORMAL_VIDEO}, + {12, Camera_SceneMode::SECURE_PHOTO} +}; + +NDKCamera::NDKCamera(uint32_t focusMode, uint32_t cameraDeviceIndex, uint32_t sceneMode, + char *previewId, char *photoId, char *videoId) + : focusMode_(focusMode), cameraDeviceIndex_(cameraDeviceIndex), + previewSurfaceId_(previewId), photoSurfaceId_(photoId), videoSurfaceId_(videoId), + cameras_(nullptr), profile_(nullptr), cameraOutputCapability_(nullptr), captureSession_(nullptr), + cameraInput_(nullptr), previewOutput_(nullptr), photoOutput_(nullptr), videoOutput_(nullptr), + isCameraMuted_(nullptr), metaDataObjectType_(nullptr), metadataOutput_(nullptr), + isExposureModeSupported_(false), isFocusModeSupported_(false), isSuccess_(false), + sceneMode_(NORMAL_VIDEO), exposureMode_(EXPOSURE_MODE_LOCKED), ret_(CAMERA_OK), + size_(0), minExposureBias_(0), maxExposureBias_(0), step_(0) +{ + // release camera + ReleaseCamera(); + + // create camera manager + Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager_); + if (cameraManager_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Get CameraManager failed."); + } + + // create capture session + ret = OH_CameraManager_CreateCaptureSession(cameraManager_, &captureSession_); + if (captureSession_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Create captureSession failed."); + } + + // look up sceneMode + auto itr1 = g_int32ToCameraSceneMode.find(sceneMode); + if (itr1 != g_int32ToCameraSceneMode.end()) { + sceneMode_ = itr1->second; + } + + // set session mode + ret = OH_CaptureSession_SetSessionMode(captureSession_, NORMAL_VIDEO); + + // get capture session profile + GetSupportedCameras(); + GetSupportedOutputCapability(); + + // create preview output + CreatePreviewOutput(); + + // create camera input and register camera input callback + CreateCameraInput(); + CameraInputOpen(); // 设备打开 + + // config and start session + SessionFlowFn(); +} + +NDKCamera::~NDKCamera() +{ + 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_ERROR(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_DeleteCameraMananger. ok"); + } + cameraManager_ = nullptr; + } + OH_LOG_INFO(LOG_APP, "~NDKCamera exit"); +} + +Camera_ErrorCode NDKCamera::ReleaseCamera(void) +{ + OH_LOG_INFO(LOG_APP, " enter ReleaseCamera"); + if (previewOutput_ && captureSession_) { + PreviewOutputStop(); + OH_CaptureSession_RemovePreviewOutput(captureSession_, previewOutput_); + PreviewOutputRelease(); + } + if (photoOutput_) { + PhotoOutputRelease(); + } + if (videoOutput_) { + VideoOutputRelease(); + } + if (captureSession_) { + SessionRealese(); + } + 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(); + VideoOutputRelease(); + SessionRealese(); + OH_LOG_INFO(LOG_APP, " exit ReleaseSession"); + return ret_; +} + +Camera_ErrorCode NDKCamera::SessionRealese(void) +{ + OH_LOG_INFO(LOG_APP, " enter SessionRealese"); + Camera_ErrorCode ret = OH_CaptureSession_Release(captureSession_); + captureSession_ = nullptr; + OH_LOG_INFO(LOG_APP, " exit SessionRealese"); + 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: %{public}f ", + 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) +{ + bool isSupport = false; + OH_CaptureSession_IsVideoStabilizationModeSupported(captureSession_, + Camera_VideoStabilizationMode::STABILIZATION_MODE_AUTO, &isSupport); + if (isSupport) { + OH_CaptureSession_SetVideoStabilizationMode(captureSession_, + Camera_VideoStabilizationMode::STABILIZATION_MODE_AUTO); + } + + // Start focusing + OH_LOG_INFO(LOG_APP, "IsFocusMode start"); + OH_CaptureSession_SetFocusMode(captureSession_, Camera_FocusMode::FOCUS_MODE_AUTO); + OH_LOG_INFO(LOG_APP, "IsFocusMode success"); + + 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 add Input."); + 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_); + + if (sceneMode_ == Camera_SceneMode::NORMAL_VIDEO) { + // create video output and register video output callback + CreateVideoOutput(videoSurfaceId_); + + // add videoOutput to the Session + AddVideoOutput(); + } + + // 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"); + SessionStart(); + OH_LOG_INFO(LOG_APP, "session success"); + OH_VideoOutput_Start(videoOutput_); + + return ret; +} + +Camera_ErrorCode NDKCamera::CreateCameraInput(void) +{ + OH_LOG_ERROR(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_ERROR(LOG_APP, "exit CreateCameraInput."); + + // register camera input callback + CameraInputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputOpen(void) +{ + OH_LOG_ERROR(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_ERROR(LOG_APP, "exit CameraInputOpen."); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputClose(void) +{ + OH_LOG_ERROR(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_ERROR(LOG_APP, "exit CameraInput_Close."); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputRelease(void) +{ + OH_LOG_ERROR(LOG_APP, "enter CameraInputRelease."); + ret_ = OH_CameraInput_Release(cameraInput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CameraInput_Release failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_ERROR(LOG_APP, "exit CameraInputRelease."); + return ret_; +} + +Camera_ErrorCode NDKCamera::GetSupportedCameras(void) +{ + ret_ = OH_CameraManager_GetSupportedCameras(cameraManager_, &cameras_, &size_); + if (cameras_ == nullptr || &size_ == 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) +{ + DRAWING_LOGD("NDKCamera::CreatePreviewOutput start!"); + profile_ = cameraOutputCapability_->previewProfiles[0]; + + if (profile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get previewProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + + profile_->size.width = videoFrameWidth; + profile_->size.height = videoFrameHeight; + 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; + } + + // register preview output callback + PreviewOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CreatePhotoOutput(char *photoSurfaceId) +{ + DRAWING_LOGD("NDKCamera::CreatePhotoOutput start!"); + profile_ = cameraOutputCapability_->photoProfiles[0]; + + if (profile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get photoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + + profile_->size.width = videoFrameWidth; + profile_->size.height = videoFrameHeight ; + ret_ = OH_CameraManager_CreatePhotoOutput(cameraManager_, profile_, photoSurfaceId, &photoOutput_); + + if (photoSurfaceId == nullptr || photoOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreatePhotoOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + // register photo output callback + PhotoOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CreateVideoOutput(char *videoId) +{ + DRAWING_LOGD("NDKCamera::CreateVideoOutput start!"); + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput width:%{public}d", videoProfile_->size.width); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput height:%{public}d", videoProfile_->size.height); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput format:%{public}d", videoProfile_->format); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput range.min:%{public}d", videoProfile_->range.min); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput range.max:%{public}d", videoProfile_->range.max); + + videoProfile_->size.width = videoFrameWidth; + videoProfile_->size.height = videoFrameHeight; + 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; + } + + // register video output callback + VideoOutputRegisterCallback(); + 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::CreateMetadataOutput(void) +{ + metaDataObjectType_ = cameraOutputCapability_->supportedMetadataObjectTypes[0]; + if (metaDataObjectType_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get metaDataObjectType failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CameraManager_CreateMetadataOutput(cameraManager_, metaDataObjectType_, &metadataOutput_); + if (metadataOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreateMetadataOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + // register metadata output callback + MetadataOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsCameraMuted(void) +{ + ret_ = OH_CameraManager_IsCameraMuted(cameraManager_, isCameraMuted_); + if (isCameraMuted_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsCameraMuted failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::PreviewOutputStop(void) +{ + OH_LOG_ERROR(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_ERROR(LOG_APP, "enter PreviewOutputRelease."); + if (previewOutput_ != nullptr) { + ret_ = OH_PreviewOutput_Release(previewOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PreviewOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + previewOutput_ = nullptr; + } + return CAMERA_OK; +} + +Camera_ErrorCode NDKCamera::PhotoOutputRelease(void) +{ + OH_LOG_ERROR(LOG_APP, "enter PhotoOutputRelease."); + ret_ = OH_PhotoOutput_Release(photoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PhotoOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + photoOutput_ = nullptr; + 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; +} + +// 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 (&isExposureModeSupported_ == nullptr || 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 (&exposureMode_ == nullptr || 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 (&exposureMode_ == nullptr || 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 (&minExposureBias_ == nullptr || &maxExposureBias_ == nullptr || &step_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureBiasRange failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_SetExposureBias(captureSession_, exposureBiasValue); + OH_LOG_ERROR(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 (&exposureBiasValue == nullptr || 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 (&isFocusModeSupported_ == nullptr || 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 (&isFocusModeSupported_ == nullptr || 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 (&focusMode == nullptr || 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 (&focusPoint == nullptr || 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_ERROR(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_ERROR(LOG_APP, "enter VideoOutputRelease."); + if (videoOutput_ == nullptr) { + OH_LOG_DEBUG(LOG_APP, "VideoOutputRelease videoOutput_ is already null."); + return CAMERA_OK; + } + ret_ = OH_VideoOutput_Release(videoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "VideoOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + videoOutput_ = nullptr; + return ret_; +} + +Camera_ErrorCode NDKCamera::TakePicture(void) +{ + Camera_ErrorCode ret = CAMERA_OK; + ret = OH_PhotoOutput_Capture(photoOutput_); + OH_LOG_ERROR(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, %{public}d, longitude %{public}d, altitude %{public}d", + photoSetting.quality, photoSetting.rotation, photoSetting.mirror, photoSetting.location->latitude, + photoSetting.location->longitude, photoSetting.location->altitude); + + OH_LOG_ERROR(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) +{ + 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) +{ + 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_; +} + +// PreviewOutput Callback +void PreviewOutputOnFrameStart(Camera_PreviewOutput *previewOutput) +{ + OH_LOG_INFO(LOG_APP, "PreviewOutputOnFrameStart"); +} + +void PreviewOutputOnFrameEnd(Camera_PreviewOutput *previewOutput, int32_t frameCount) +{ + OH_LOG_INFO(LOG_APP, "PreviewOutput frameCount = %{public}d", frameCount); +} + +void PreviewOutputOnError(Camera_PreviewOutput *previewOutput, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "PreviewOutput errorCode = %{public}d", errorCode); +} + +PreviewOutput_Callbacks *NDKCamera::GetPreviewOutputListener(void) +{ + static PreviewOutput_Callbacks previewOutputListener = { + .onFrameStart = PreviewOutputOnFrameStart, + .onFrameEnd = PreviewOutputOnFrameEnd, + .onError = PreviewOutputOnError + }; + return &previewOutputListener; +} + +Camera_ErrorCode NDKCamera::PreviewOutputRegisterCallback(void) +{ + ret_ = OH_PreviewOutput_RegisterCallback(previewOutput_, GetPreviewOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_RegisterCallback failed."); + } + return ret_; +} + +// PhotoOutput Callback +void PhotoOutputOnFrameStart(Camera_PhotoOutput *photoOutput) +{ + DRAWING_LOGD("PhotoOutputOnFrameStart start!"); + OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameStart"); +} + +void PhotoOutputOnFrameShutter(Camera_PhotoOutput *photoOutput, Camera_FrameShutterInfo *info) +{ + DRAWING_LOGD("PhotoOutputOnFrameShutter start!"); + OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameShutter"); +} + +void PhotoOutputOnFrameEnd(Camera_PhotoOutput *photoOutput, int32_t frameCount) +{ + DRAWING_LOGD("PhotoOutputOnFrameEnd start!"); + OH_LOG_INFO(LOG_APP, "PhotoOutput frameCount = %{public}d", frameCount); +} + +void PhotoOutputOnError(Camera_PhotoOutput *photoOutput, Camera_ErrorCode errorCode) +{ + DRAWING_LOGD("PhotoOutputOnError start!"); + 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) +{ + OH_LOG_INFO(LOG_APP, "VideoOutputOnFrameStart"); +} + +void VideoOutputOnFrameEnd(Camera_VideoOutput *videoOutput, int32_t frameCount) +{ + OH_LOG_INFO(LOG_APP, "VideoOutput frameCount = %{public}d", frameCount); +} + +void VideoOutputOnError(Camera_VideoOutput *videoOutput, Camera_ErrorCode errorCode) +{ + 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_; +} + +// Metadata Callback +void OnMetadataObjectAvailable(Camera_MetadataOutput *metadataOutput, Camera_MetadataObject *metadataObject, + uint32_t size) +{ + OH_LOG_INFO(LOG_APP, "size = %{public}d", size); +} + +void OnMetadataOutputError(Camera_MetadataOutput *metadataOutput, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "OnMetadataOutput errorCode = %{public}d", errorCode); +} + +MetadataOutput_Callbacks *NDKCamera::GetMetadataOutputListener(void) +{ + static MetadataOutput_Callbacks metadataOutputListener = { + .onMetadataObjectAvailable = OnMetadataObjectAvailable, + .onError = OnMetadataOutputError + }; + return &metadataOutputListener; +} + +Camera_ErrorCode NDKCamera::MetadataOutputRegisterCallback(void) +{ + ret_ = OH_MetadataOutput_RegisterCallback(metadataOutput_, GetMetadataOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_MetadataOutput_RegisterCallback failed."); + } + return ret_; +} + +// Session Callback +void CaptureSessionOnFocusStateChange(Camera_CaptureSession *session, Camera_FocusState focusState) +{ + OH_LOG_INFO(LOG_APP, "CaptureSession_Callbacks CaptureSessionOnFocusStateChange"); + OH_LOG_INFO(LOG_APP, "CaptureSessionOnFocusStateChange"); +} + +void CaptureSessionOnError(Camera_CaptureSession *session, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "CaptureSession_Callbacks CaptureSessionOnError"); + 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/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..a4a00267b95c623f246d4561052c455afb305923 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025 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 AVRECORDER_CAMERA_MANAGER_H +#define AVRECORDER_CAMERA_MANAGER_H + +#include "napi/native_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iostream" +#include "mutex" + +#include "hilog/log.h" +#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 "napi/native_api.h" +#include "ohcamera/camera_manager.h" +#include "log_common.h" +#include "main.h" + +namespace OHOS_CAMERA_SAMPLE { +class NDKCamera { + public: + ~NDKCamera(); + NDKCamera(uint32_t focusMode, uint32_t cameraDeviceIndex, uint32_t sceneMode, + char *previewId, char *photoId, char *videoId); + + static void Destroy() + { + if (ndkCamera_ != nullptr) { + delete ndkCamera_; + ndkCamera_ = nullptr; + } + } + + Camera_ErrorCode CreateCameraInput(void); + Camera_ErrorCode CameraInputOpen(void); + Camera_ErrorCode CameraInputClose(void); + Camera_ErrorCode CameraInputRelease(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 CreateMetadataOutput(void); + Camera_ErrorCode IsCameraMuted(void); + 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 SessionRealese(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 PreviewOutputRegisterCallback(void); + Camera_ErrorCode PhotoOutputRegisterCallback(void); + Camera_ErrorCode VideoOutputRegisterCallback(void); + Camera_ErrorCode MetadataOutputRegisterCallback(void); + Camera_ErrorCode CaptureSessionRegisterCallback(void); + + // Get callback + CameraManager_Callbacks *GetCameraManagerListener(void); + CameraInput_Callbacks *GetCameraInputListener(void); + PreviewOutput_Callbacks *GetPreviewOutputListener(void); + PhotoOutput_Callbacks *GetPhotoOutputListener(void); + VideoOutput_Callbacks *GetVideoOutputListener(void); + MetadataOutput_Callbacks *GetMetadataOutputListener(void); + CaptureSession_Callbacks *GetCaptureSessionRegister(void); + + private: + NDKCamera(const NDKCamera &) = delete; + NDKCamera &operator=(const NDKCamera &) = delete; + uint32_t cameraDeviceIndex_; + Camera_Manager *cameraManager_; + Camera_CaptureSession *captureSession_ = nullptr; + Camera_Device *cameras_; + uint32_t size_; + Camera_OutputCapability *cameraOutputCapability_; + Camera_Profile *profile_; + Camera_VideoProfile *videoProfile_; + Camera_PreviewOutput *previewOutput_ = nullptr; + Camera_PhotoOutput *photoOutput_ = nullptr; + Camera_VideoOutput *videoOutput_ = nullptr; + const Camera_MetadataObjectType *metaDataObjectType_; + Camera_MetadataOutput *metadataOutput_; + Camera_Input *cameraInput_; + bool *isCameraMuted_; + Camera_Position position_; + Camera_Type type_; + char *previewSurfaceId_; + Camera_ErrorCode ret_; + uint32_t takePictureTimes = 0; + Camera_ExposureMode exposureMode_; + bool isExposureModeSupported_; + bool isFocusModeSupported_; + float minExposureBias_; + float maxExposureBias_; + float step_; + uint32_t focusMode_; + + static NDKCamera *ndkCamera_; + static std::mutex mtx_; + volatile bool valid_; + + Camera_SceneMode sceneMode_; + char *photoSurfaceId_; + char *videoSurfaceId_; + bool isSuccess_; +}; +} // namespace OHOS_CAMERA_SAMPLE +#endif //AVRECORDER_CAMERA_MANAGER_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/log_common.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/log_common.h new file mode 100644 index 0000000000000000000000000000000000000000..1440bd5059247f2c6db4e15e97c992b7cd8e08ae --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/log_common.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 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 AVRECORDER_LOG_COMMON_H +#define AVRECORDER_LOG_COMMON_H + +#ifndef LOG_COMMON_H +#define LOG_COMMON_H +#include +#define LOG_PRINT_DOMAIN 0xFF00 +#define APP_LOG_DOMAIN 0x0001 +constexpr const char *APP_LOG_TAG = "AVRecorderSample"; +#define DRAWING_LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define DRAWING_LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define DRAWING_LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define DRAWING_LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) + +#endif // LOG_COMMON_H +#endif //AVRECORDER_LOG_COMMON_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.cpp b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..050e0aeff756c3db3c5fe2df03204a7c97181eab --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.cpp @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2025 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 "main.h" +#include "napi/native_api.h" +#include "camera_manager.h" + +#define LOG_DOMAIN 0x3200 +#define LOG_TAG "MY_NDKDEMO" +#include + +using namespace std; +using namespace OHOS_CAMERA_SAMPLE; +static NDKCamera* ndkCamera_ = nullptr; + +// 设置视频分辨率 +int videoFrameWidth = 1280; +int videoFrameHeight = 720; + +// 配置参数,可选三种录制模式 +// Type 1: 音视频录制 +void SetConfig(OH_AVRecorder_Config &config) +{ + config.audioSourceType = AVRECORDER_MIC; + config.videoSourceType = AVRECORDER_SURFACE_YUV; + + config.profile.audioBitrate = 96000; + config.profile.audioChannels = 2; + config.profile.audioCodec = AVRECORDER_AUDIO_AAC; + config.profile.audioSampleRate = 48000; + + config.profile.videoBitrate = 2000000; + config.profile.videoFrameWidth = videoFrameWidth; + config.profile.videoFrameHeight = videoFrameHeight; + config.profile.videoFrameRate = 30; + config.profile.videoCodec = AVRECORDER_VIDEO_AVC; + config.profile.isHdr = false; + config.profile.enableTemporalScale = false; + + config.profile.fileFormat = AVRECORDER_CFT_MPEG_4; + config.fileGenerationMode = AVRECORDER_AUTO_CREATE_CAMERA_SCENE; + + config.metadata.videoOrientation = (char*)malloc(2); + if (config.metadata.videoOrientation != nullptr) { + strcpy(config.metadata.videoOrientation, "90"); + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== videoOrientation: %{public}s", config.metadata.videoOrientation); + + config.metadata.location.latitude = 31.791863; + config.metadata.location.longitude = 64.574687; +} + +// Type 2: 只录音频 +void SetConfigAudio(OH_AVRecorder_Config &config) +{ + config.audioSourceType = AVRECORDER_MIC; + + config.profile.audioBitrate = 32000; + config.profile.audioChannels = 2; + config.profile.audioCodec = AVRECORDER_AUDIO_AAC; + config.profile.audioSampleRate = 8000; + + config.profile.fileFormat = AVRECORDER_CFT_AAC; + config.fileGenerationMode = AVRECORDER_APP_CREATE; + + config.metadata.location.latitude = 31.791863; + config.metadata.location.longitude = 64.574687; +} + +// Type 3: 只录视频 +void SetConfigVideo(OH_AVRecorder_Config &config) +{ + config.videoSourceType = AVRECORDER_SURFACE_YUV; + + config.profile.videoBitrate = 2000000; + config.profile.videoFrameWidth = videoFrameWidth; + config.profile.videoFrameHeight = videoFrameHeight; + config.profile.videoFrameRate = 30; + config.profile.videoCodec = AVRECORDER_VIDEO_AVC; + config.profile.isHdr = false; + config.profile.enableTemporalScale = false; + + config.profile.fileFormat = AVRECORDER_CFT_MPEG_4; + config.fileGenerationMode = AVRECORDER_APP_CREATE; + + config.metadata.videoOrientation = (char*)malloc(2); + if (config.metadata.videoOrientation != nullptr) { + strcpy(config.metadata.videoOrientation, "90"); + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== videoOrientation: %{public}s", config.metadata.videoOrientation); + + config.metadata.location.latitude = 31.791863; + config.metadata.location.longitude = 64.574687; +} + +// 设置状态回调 +void OnStateChange(OH_AVRecorder *recorder, OH_AVRecorder_State state, + OH_AVRecorder_StateChangeReason reason, void *userData) { + (void)recorder; + (void)userData; + + // 将 reason 转换为字符串表示 + const char *reasonStr = (reason == AVRECORDER_USER) ? "USER" : (reason == AVRECORDER_BACKGROUND) ? "BACKGROUND" : "UNKNOWN"; + + if (state == AVRECORDER_IDLE) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange IDLE, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_PREPARED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange PREPARED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_STARTED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange STARTED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_PAUSED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange PAUSED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_STOPPED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange STOPPED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_RELEASED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange RELEASED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_ERROR) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange ERROR, reason: %{public}s", reasonStr); + // 处理状态变更 + } +} + +// 设置错误回调 +void OnError(OH_AVRecorder *recorder, int32_t errorCode, const char *errorMsg, void *userData) { + (void)recorder; + (void)userData; + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnError errorCode: %{public}d, error message: %{public}s", + errorCode, errorMsg); +} + +// 设置生成媒体文件回调 +void OnUri(OH_AVRecorder *recorder, OH_MediaAsset *asset, void *userData) { + (void)recorder; + (void)userData; + OH_LOG_INFO(LOG_APP, "==NDKDemo== OnUri in!"); + if (asset != nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_MediaAsset: %p", asset); + auto changeRequest = OH_MediaAssetChangeRequest_Create(asset); + OH_LOG_INFO(LOG_APP, "==NDKDemo== changeRequest: %p", changeRequest); + if (changeRequest == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== changeRequest is null!"); + return; + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== changeRequest is not null!"); + MediaLibrary_ImageFileType imageFileType = MEDIA_LIBRARY_FILE_VIDEO; + + uint32_t result = OH_MediaAssetChangeRequest_SaveCameraPhoto(changeRequest, imageFileType); + OH_LOG_INFO(LOG_APP, "result of OH_MediaAssetChangeRequest_SaveCameraPhoto: %d", result); + uint32_t resultChange = OH_MediaAccessHelper_ApplyChanges(changeRequest); + OH_LOG_INFO(LOG_APP, "result of OH_MediaAccessHelper_ApplyChanges: %d", resultChange); + OH_MediaAsset_Release(asset); + OH_MediaAssetChangeRequest_Release(changeRequest); + } else { + OH_LOG_ERROR(LOG_APP, "Received null media asset!"); + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== OnUri out!"); +} + +// 1.准备录制 +static napi_value PrepareAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + OH_LOG_INFO(LOG_APP, "==NDKDemo== PrepareAVRecorder in!"); + g_avRecorder = OH_AVRecorder_Create(); + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder Create OK! g_avRecorder: %{public}p", g_avRecorder); + if (g_avRecorder == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Create failed!"); + } + OH_AVRecorder_Config *config = new OH_AVRecorder_Config(); + + SetConfig(*config); + + // 1.1 设置URL + const std::string AVREORDER_ROOT = "/data/storage/el2/base/files/"; + int32_t outputFd = open((AVREORDER_ROOT + "avrecorder01.mp4").c_str(), O_RDWR | O_CREAT, 0777); // 设置文件名 + std::string fileUrl = "fd://" + std::to_string(outputFd); + config->url = const_cast(fileUrl.c_str()); + OH_LOG_INFO(LOG_APP, "config.url is: %s", const_cast(fileUrl.c_str())); + std::cout<< "config.url is:" << config->url << std::endl; + + // 1.2 回调 + // 状态回调 + OH_AVRecorder_SetStateCallback(g_avRecorder, OnStateChange, nullptr); + // 错误回调 + OH_AVRecorder_SetErrorCallback(g_avRecorder, OnError, nullptr); + // 生成媒体文件回调 + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_SetUriCallback in!"); + OH_AVErrCode ret = OH_AVRecorder_SetUriCallback(g_avRecorder, OnUri, nullptr); + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_SetUriCallback out!"); + if (ret == AV_ERR_OK) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_SetUriCallback succeed!"); + } else { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== Failed to set URI callback, error code: %d", ret); + } + + // 1.3 prepare接口 + int result = OH_AVRecorder_Prepare(g_avRecorder, config); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Prepare failed %{public}d", result); + } + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder enableTemporalScale:%{public}d", static_cast(config->profile.enableTemporalScale)); + + // 1.4 更新视频旋转角度 OH_AVRecorder_UpdateRotation + int32_t rotation = 90; + result = OH_AVRecorder_UpdateRotation(g_avRecorder, rotation); + if (result != AV_ERR_OK) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder UpdateRotation failed! ret=%{public}d", result); + } else { + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_UpdateRotation: %{public}d", rotation); + } + + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 获取实时配置参数 +static napi_value GetAVRecorderConfig(napi_env env, napi_callback_info info) +{ + (void)info; + +// OH_AVRecorder_Config *config = new OH_AVRecorder_Config(); +// SetConfig(*config); + + OH_AVRecorder_Config *config = nullptr; + + int result = OH_AVRecorder_GetAVRecorderConfig(g_avRecorder, &config); + if (result != AV_ERR_OK || config == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== Get AVRecorder Config failed %{public}d", result); + napi_value res; + napi_create_int32(env, result, &res); + return res; + } + + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoOrientation: %{public}s", config->metadata.videoOrientation); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioSourceType: %{public}d", config->audioSourceType); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoSourceType: %{public}d", config->videoSourceType); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioBitrate: %{public}d", config->profile.audioBitrate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioChannels: %{public}d", config->profile.audioChannels); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioCodec: %{public}d", config->profile.audioCodec); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioSampleRate: %{public}d", config->profile.audioSampleRate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig fileFormat: %{public}d", config->profile.fileFormat); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoBitrate: %{public}d", config->profile.videoBitrate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoCodec: %{public}d", config->profile.videoCodec); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoFrameWidth: %{public}d", config->profile.videoFrameWidth); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoFrameHeight: %{public}d", config->profile.videoFrameHeight); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoFrameRate: %{public}d", config->profile.videoFrameRate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig latitude: %{public}.6f", config->metadata.location.latitude); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig longitude: %{public}.6f", config->metadata.location.longitude); + + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 获取录制支持的编码信息 +static napi_value GetAvailableEncoder(napi_env env, napi_callback_info info) +{ + (void)info; + + OH_AVRecorder_EncoderInfo *encoderInfo = nullptr; + int32_t lengthValue = 0; // 定义一个实际的 int32_t 变量 + int32_t *length = &lengthValue; + + int result = OH_AVRecorder_GetAvailableEncoder(g_avRecorder, &encoderInfo, length); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== GetAvailableEncoder failed %{public}d", result); + } else { + // 打印 encoderInfo 的内容 + if (encoderInfo != nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Encoder Info in!"); + + // 打印 mimeType (假设是一个枚举类型或可转为字符串的类型) + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder MIME Type: %{public}d", encoderInfo->mimeType); + + // 打印 type + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Type: %{public}s", encoderInfo->type); + + // 打印 bitRate 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder BitRate Min: %{public}d, Max: %{public}d", encoderInfo->bitRate.min, encoderInfo->bitRate.max); + + // 打印 frameRate 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder FrameRate Min: %{public}d, Max: %{public}d", encoderInfo->frameRate.min, encoderInfo->frameRate.max); + + // 打印 width 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Width Min: %{public}d, Max: %{public}d", encoderInfo->width.min, encoderInfo->width.max); + + // 打印 height 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Height Min: %{public}d, Max: %{public}d", encoderInfo->height.min, encoderInfo->height.max); + + // 打印 channels 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Channels Min: %{public}d, Max: %{public}d", encoderInfo->channels.min, encoderInfo->channels.max); + + // 打印 sampleRate 列表和长度 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder SampleRate Length: %{public}d", encoderInfo->sampleRateLen); + if (encoderInfo->sampleRate != nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== SampleRates: "); + for (int i = 0; i < encoderInfo->sampleRateLen; i++) { + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder SampleRate: %{public}d", i, encoderInfo->sampleRate[i]); + } + } + } else { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== EncoderInfo is null"); + } + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 2. 启动相机 +static napi_value PrepareCamera(napi_env env, napi_callback_info info) +{ + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder PrepareCamera"); + (void)info; + + // 2.1 相机初始化(init) + + size_t argc = 6; + napi_value args[6] = {nullptr}; + size_t typeLen = 0; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + int32_t focusMode; + napi_get_value_int32(env, args[0], &focusMode); + + uint32_t cameraDeviceIndex; + napi_get_value_uint32(env, args[1], &cameraDeviceIndex); + + uint32_t sceneMode; + napi_get_value_uint32(env, args[2], &sceneMode); + + char* previewId = nullptr; + napi_get_value_string_utf8(env, args[3], nullptr, 0, &typeLen); + previewId = new char[typeLen + 1]; + napi_get_value_string_utf8(env, args[3], previewId, typeLen + 1, &typeLen); + + char* photoId = nullptr; + napi_get_value_string_utf8(env, args[4], nullptr, 0, &typeLen); + photoId = new char[typeLen + 1]; + napi_get_value_string_utf8(env, args[4], photoId, typeLen + 1, &typeLen); + + // 获取surfaceID + OHNativeWindow *window = nullptr; + + int resultCode = OH_AVRecorder_GetInputSurface(g_avRecorder, &window); + if (resultCode != AV_ERR_OK || window == nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder GetInputSurface failed! resultCode=%{public}d, window=%{public}p", resultCode, window); + napi_value errorResult; + napi_create_int32(env, -1, &errorResult); // -1 表示错误 + return errorResult; + } else { + // 打印 window 地址以确认是否分配成功 + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder GetInputSurface succeeded! window address: %{public}p", window); + } + + uint64_t surfaceId; + OH_NativeWindow_GetSurfaceId(window, &surfaceId); + char videoId[30]; + OH_LOG_ERROR(LOG_APP, "InitCamera focusMode : %{public}d", focusMode); + OH_LOG_ERROR(LOG_APP, "InitCamera cameraDeviceIndex : %{public}d", cameraDeviceIndex); + OH_LOG_ERROR(LOG_APP, "InitCamera sceneMode : %{public}d", sceneMode); + OH_LOG_ERROR(LOG_APP, "InitCamera previewId : %{public}s", previewId); + OH_LOG_ERROR(LOG_APP, "InitCamera photoId : %{public}s", photoId); + OH_LOG_ERROR(LOG_APP, "InitCamera videoId : %{public}s", videoId); + + ndkCamera_ = new NDKCamera(focusMode, cameraDeviceIndex, sceneMode, previewId, photoId, videoId); + OH_LOG_INFO(LOG_APP, "InitCamera End"); + + int result = 0; + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 3. 开始录制 +static napi_value StartAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + OH_LOG_INFO(LOG_APP, "==NDKDemo== g_avRecorder start: %{public}p", g_avRecorder); + int result = OH_AVRecorder_Start(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Start failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 4. 暂停录制 +static napi_value PauseAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + int result = OH_AVRecorder_Pause(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Pause failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 5. 恢复录制 +static napi_value ResumeAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + int result = OH_AVRecorder_Resume(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Resume failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 6. 停止录制 +static napi_value StopAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + OH_LOG_INFO(LOG_APP, "==NDKDemo== g_avRecorder stop: %{public}p", g_avRecorder); + int result = OH_AVRecorder_Stop(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Stop failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 7. 重置录制 +static napi_value ResetAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + // 检查 g_avRecorder 是否有效 + if (g_avRecorder == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== g_avRecorder is nullptr!"); + napi_value res; + napi_create_int32(env, AV_ERR_INVALID_VAL, &res); + return res; + } + + int result = OH_AVRecorder_Reset(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Reset failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 8. 释放录制资源 +static napi_value ReleaseAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + // 检查 g_avRecorder 是否有效 + if (g_avRecorder == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== g_avRecorder is nullptr!"); + napi_value res; + napi_create_int32(env, AV_ERR_INVALID_VAL, &res); + return res; + } + + int result = OH_AVRecorder_Release(g_avRecorder); + g_avRecorder = nullptr; // 释放录制资源后,需要显式地将g_avRecorder指针置空 + + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Release failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + {"prepareAVRecorder", nullptr, PrepareAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getAVRecorderConfig", nullptr, GetAVRecorderConfig, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getAvailableEncoder", nullptr, GetAvailableEncoder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"prepareCamera", nullptr, PrepareCamera, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"startAVRecorder", nullptr, StartAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"pauseAVRecorder", nullptr, PauseAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"resumeAVRecorder", nullptr, ResumeAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"stopAVRecorder", nullptr, StopAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"resetAVRecorder", nullptr, ResetAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"releaseAVRecorder", nullptr, ReleaseAVRecorder, 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/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.h new file mode 100644 index 0000000000000000000000000000000000000000..8a4605c25954ddadf0fd0e4e34587b855efaff60 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 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 AVRECORDER_MAIN_H +#define AVRECORDER_MAIN_H + +#include "napi/native_api.h" +#include "hilog/log.h" +#include "mutex" +#include "muxer.h" +#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" +#include "native_window/external_window.h" +#include "video_encoder_sample.h" +#include +#include +#include +#include +#include +#include "multimedia/player_framework/native_avcodec_videoencoder.h" +#include "multimedia/media_library/media_asset_change_request_capi.h" +#include "multimedia/media_library/media_access_helper_capi.h" +#include "multimedia/media_library/media_asset_capi.h" + +static struct OH_AVRecorder *g_avRecorder = {}; +OH_AVRecorder* InitRecorder(); +void StartRecording(OH_AVRecorder *recorder); + +extern int videoFrameWidth; +extern int videoFrameHeight; + +#endif //AVRECORDER_MAIN_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.cpp b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7aebe1b6169c77864e680e8cb7e46ef084662649 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 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 "muxer.h" +#include "hilog/log.h" + +#undef LOG_TAG +#define LOG_TAG "Muxer" + +namespace { +constexpr int32_t VERTICAL_ANGLE = 90; +constexpr int32_t HORIZONTAL_ANGLE = 0; +} + +Muxer::~Muxer() +{ + Release(); +} + +int32_t Muxer::Create(int32_t fd) +{ + muxer_ = OH_AVMuxer_Create(fd, AV_OUTPUT_FORMAT_MPEG_4); + return 0; +} + +int32_t Muxer::Config(SampleInfo &sampleInfo) +{ + OH_LOG_INFO(LOG_APP, "==DEMO== Config"); + OH_AVFormat *formatVideo = OH_AVFormat_CreateVideoFormat(sampleInfo.codecMime.data(), + sampleInfo.videoWidth, sampleInfo.videoHeight); + + OH_AVFormat_SetDoubleValue(formatVideo, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate); + OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_WIDTH, sampleInfo.videoWidth); + OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight); + OH_AVFormat_SetStringValue(formatVideo, OH_MD_KEY_CODEC_MIME, sampleInfo.codecMime.data()); + + int32_t ret = OH_AVMuxer_AddTrack(muxer_, &videoTrackId_, formatVideo); // ! + OH_AVFormat_Destroy(formatVideo); + + OH_LOG_INFO(LOG_APP, "==DEMO== Config End"); + return 0; +} + +int32_t Muxer::Start() +{ + int ret = OH_AVMuxer_Start(muxer_); + return 0; +} + +int32_t Muxer::WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) +{ + OH_LOG_INFO(LOG_APP, "==DEMO== WriteSample"); + int32_t ret = OH_AVBuffer_SetBufferAttr(buffer, &attr); + ret = OH_AVMuxer_WriteSampleBuffer(muxer_, videoTrackId_, buffer); + return 0; +} + +int32_t Muxer::WriteAudioData(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) +{ + OH_LOG_INFO(LOG_APP, "==DEMO== WriteAudioSample"); + int32_t ret = OH_AVBuffer_SetBufferAttr(buffer, &attr); + ret = OH_AVMuxer_WriteSampleBuffer(muxer_, audioTrackId_, buffer); + return 0; +} + +int32_t Muxer::Stop() +{ + int32_t ret = OH_AVMuxer_Stop(muxer_); + return 0; +} + +int32_t Muxer::Release() +{ + if (muxer_ != nullptr) { + OH_AVMuxer_Destroy(muxer_); + muxer_ = nullptr; + } + return 0; +} diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.h new file mode 100644 index 0000000000000000000000000000000000000000..603cc602a319fd0c1e12a6545f50b2d46367f653 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 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 MUXER_H +#define MUXER_H + +#define LOG_DOMAIN 0x3200 +#define LOG_TAG "MY_NDKDEMO" +#include +#include "sample_info.h" +#include "multimedia/player_framework/native_avmuxer.h" + +class Muxer { +public: + Muxer() = default; + ~Muxer(); + + int32_t Create(int32_t fd); + int32_t Config(SampleInfo &sampleInfo); + int32_t Start(); + int32_t WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + int32_t WriteAudioData(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + + int32_t Stop(); + int32_t Release(); + +private: + OH_AVMuxer *muxer_ = nullptr; + int32_t videoTrackId_ = -1; + int32_t audioTrackId_ = -1; + int32_t coverTrackId_ = -1; +}; + +#endif // MUXER_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/sample_info.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/sample_info.h new file mode 100644 index 0000000000000000000000000000000000000000..d9a20dadaf097fbcdb24ee2bb2e75cf5b8ecc447 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/sample_info.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2025 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 AVCODEC_SAMPLE_INFO_H +#define AVCODEC_SAMPLE_INFO_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANNEXB_INPUT_ONLY 1 + +const std::string_view MIME_VIDEO_AVC = "video/avc"; +const std::string_view MIME_VIDEO_HEVC = "video/hevc"; + +constexpr int32_t BITRATE_10M = 10 * 1024 * 1024; // 10Mbps +constexpr int32_t BITRATE_20M = 20 * 1024 * 1024; // 20Mbps +constexpr int32_t BITRATE_30M = 30 * 1024 * 1024; // 30Mbps + +struct SampleInfo { + int32_t sampleId = 0; + + int32_t inputFd = -1; + int32_t outFd = -1; + int64_t inputFileOffset = 0; + int64_t inputFileSize = 0; + std::string inputFilePath; + std::string outputFilePath; + std::string videoCodecMime = ""; + std::string audioCodecMime = ""; + std::string codecMime = MIME_VIDEO_AVC.data(); + int32_t videoWidth = 0; + int32_t videoHeight = 0; + double frameRate = 0.0; + int64_t bitrate = 10 * 1024 * 1024; // 10Mbps; + int64_t frameInterval = 0; + int32_t perfmode = 0; + int64_t durationTime = 0; + uint32_t maxFrames = UINT32_MAX; + int32_t isHDRVivid = 0; + uint32_t repeatTimes = 1; + OH_AVPixelFormat pixelFormat = AV_PIXEL_FORMAT_NV12; + bool needDumpOutput = false; + uint32_t bitrateMode = CBR; + int32_t hevcProfile = HEVC_PROFILE_MAIN; + int32_t rotation = 0; + OHNativeWindow *window = nullptr; + + + int32_t sampleRate = 44100; + int32_t channelCount = 2; + + uint32_t bufferSize = 0; + double readTime = 0; + double memcpyTime = 0; + double writeTime = 0; + void (*PlayDoneCallback)(void *context) = nullptr; + void *playDoneCallbackData = nullptr; +}; + +struct CodecBufferInfo { + uint32_t bufferIndex = 0; + uintptr_t *buffer = nullptr; + uint8_t *bufferAddr = nullptr; + OH_AVCodecBufferAttr attr = {0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE}; + + CodecBufferInfo(uint8_t *addr) : bufferAddr(addr){}; + CodecBufferInfo(uint8_t *addr, int32_t bufferSize) + : bufferAddr(addr), attr({0, bufferSize, 0, AVCODEC_BUFFER_FLAGS_NONE}){}; + CodecBufferInfo(uint32_t argBufferIndex, OH_AVMemory *argBuffer, OH_AVCodecBufferAttr argAttr) + : bufferIndex(argBufferIndex), buffer(reinterpret_cast(argBuffer)), attr(argAttr){}; + CodecBufferInfo(uint32_t argBufferIndex, OH_AVMemory *argBuffer) + : bufferIndex(argBufferIndex), buffer(reinterpret_cast(argBuffer)){}; + CodecBufferInfo(uint32_t argBufferIndex, OH_AVBuffer *argBuffer) + : bufferIndex(argBufferIndex), buffer(reinterpret_cast(argBuffer)) { + OH_AVBuffer_GetBufferAttr(argBuffer, &attr); + }; +}; + +class AEncBufferSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::mutex startMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::condition_variable startCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue inBufferQueue_; + std::queue outBufferQueue_; + OH_AVCodecBufferAttr audioInfo = {0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE}; +}; + +class CodecUserData { +public: + SampleInfo *sampleInfo = nullptr; + + uint32_t inputFrameCount_ = 0; + std::mutex inputMutex_; + std::condition_variable inputCond_; + std::queue inputBufferInfoQueue_; + + uint32_t outputFrameCount_ = 0; + std::mutex outputMutex_; + std::condition_variable outputCond_; + std::queue outputBufferInfoQueue_; + AEncBufferSignal *signal_; + + void ClearQueue() { + { + std::unique_lock lock(inputMutex_); + auto emptyQueue = std::queue(); + inputBufferInfoQueue_.swap(emptyQueue); + } + { + std::unique_lock lock(outputMutex_); + auto emptyQueue = std::queue(); + outputBufferInfoQueue_.swap(emptyQueue); + } + } +}; + +#endif // AVCODEC_SAMPLE_INFO_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/index.d.ts b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..58387bb6453d5720cff11035925e3779bfd04511 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/index.d.ts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 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 prepareAVRecorder: () => number; + +export const getAVRecorderConfig: () => number; + +export const getAvailableEncoder: () => number; + +export const prepareCamera: (focusMode: number, cameraDeviceIndex: number, sceneMode: number, + previewId: string, photoId: string, videoId: string) => number; + +export const startAVRecorder: () => number; + +export const pauseAVRecorder: () => number; + +export const resumeAVRecorder: () => number; + +export const stopAVRecorder: () => number; + +export const resetAVRecorder: () => number; + +export const releaseAVRecorder: () => number; + + + diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/oh-package.json5 b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ce82a4c96b8c3b2d990f1168a99d66aee05dfa32 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2025 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. + */ +{ + "name": "libavrecorderndk.so", + "types": "./index.d.ts", + "version": "", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.cpp b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aca43bbabbdcd6e1fbead9bbf96680cf5d086b50 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2025 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 "video_encoder_sample.h" +#include "hilog/log.h" + +namespace { +constexpr int LIMIT_LOGD_FREQUENCY = 50; +} + +// 设置 OnError 回调函数 +void SampleCallback::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) { + // 回调的错误码由用户判断处理 + (void)codec; + (void)errorCode; + (void)userData; + OH_LOG_ERROR(LOG_APP, "On error, error code: %{public}d", errorCode); +} + +// 设置 OnStreamChanged 回调函数 +void SampleCallback::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) { +// surface模式下,该回调函数无作用 + (void)codec; + (void)format; + (void)userData; +} + +// 设置 OH_AVCodecOnNeedInputBuffer 回调函数,编码输入帧送入数据队列 +void SampleCallback::OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { +// surface模式下,该回调函数无作用,用户通过获取的surface输入数据 + OH_LOG_INFO(LOG_APP, "==DEMO== Video OnNeedInputBuffer"); + + (void)userData; + (void)index; + (void)buffer; + if (userData == nullptr) { + return; + } + (void)codec; + CodecUserData *codecUserData = static_cast(userData); + std::unique_lock lock(codecUserData->inputMutex_); + codecUserData->inputBufferInfoQueue_.emplace(index, buffer); + codecUserData->inputCond_.notify_all(); +} + +// 设置 OH_AVCodecOnNewOutputBuffer 回调函数,编码完成帧送入输出队列 +void SampleCallback::OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { + // 完成帧buffer对应的index,送入outIndexQueue队列 + // 完成帧的数据buffer送入outBufferQueue队列 + // 数据处理,请参考: + // - 释放编码帧 + OH_LOG_INFO(LOG_APP, "==DEMO== Video OnNewOutputBuffer"); + if (userData == nullptr) { + return; + } + (void)codec; + CodecUserData *codecUserData = static_cast(userData); + std::unique_lock lock(codecUserData->outputMutex_); + codecUserData->outputBufferInfoQueue_.emplace(index, buffer); + codecUserData->outputCond_.notify_all(); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.h new file mode 100644 index 0000000000000000000000000000000000000000..0324949f8b4b5c3de36db042e291d1b80632935e --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 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 AVCODEC_SAMPLE_CALLBACK_H +#define AVCODEC_SAMPLE_CALLBACK_H +#define LOG_DOMAIN 0x3200 +#define LOG_TAG "MY_NDKDEMO" + +#include "sample_info.h" +#include +class SampleCallback { +public: + SampleCallback() {} + SampleCallback(SampleCallback *p1) {} + static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData); + static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData); + static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData); + static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData); + + OH_AVMuxer *muxer_ = nullptr; + int32_t g_videoTrackId = -1; +}; + +#endif //AVCODEC_SAMPLE_CALLBACK_H diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ets b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..6ff5e236f745340788f2e8bc1382a3562847e914 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2025 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 { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + let permissionNames: Array = ['ohos.permission.MEDIA_LOCATION', 'ohos.permission.READ_MEDIA', + 'ohos.permission.WRITE_MEDIA', 'ohos.permission.CAMERA', 'ohos.permission.MICROPHONE']; + globalThis.abilityWant = this.launchWant; + globalThis.abilityContext = this.context; + let atManager = abilityAccessCtrl.createAtManager(); + atManager.requestPermissionsFromUser(globalThis.abilityContext, permissionNames).then((data) => { + hilog.info(0x0000, 'testTag', '%{public}s', 'requestPermissionsFromUser called'); + }); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +}; diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..20b967c87bd2ea7e06347b4c84fc6c7a9c0a15df --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,28 @@ + +/* + * Copyright (c) 2025 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'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/ets/pages/Index.ets b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..a561b00e060374bd1ebb904b21f1c5df301547f2 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2025 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'; +import testNapi from 'libentry.so'; +import camera from '@ohos.multimedia.camera'; +import image from '@ohos.multimedia.image'; +import media from '@ohos.multimedia.media'; +import { BusinessError } from'@kit.BasicServicesKit'; +import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; +const permissions: Array = ['ohos.permission.CAMERA']; + +const componentType_Jpeg = image.ComponentType.JPEG + +@Entry +@Component +export struct Index { + @State message: string = 'Hello World'; + // XComponentController + private mXComponentController: XComponentController = new XComponentController(); + public videoRecorder?: media.AVRecorder; + // surfaceID value + @State focusMode: number = 2; + @State cameraDeviceIndex: number = 0; + @State sceneMode: number = 2; + @State previewId: string = ''; + @State photoId: string = ''; + @State videoId: string = ''; + @State xComponentWidth: number = 384; + @State xComponentHeight: number = 450; + + build() { + Column() { + XComponent({ + id: 'componentId', + type: XComponentType.SURFACE, + controller: this.mXComponentController + }) + .onLoad(async () => { + this.previewId = this.mXComponentController.getXComponentSurfaceId(); + hilog.info(0x0000, 'testTag', 'previewId: %{public}s', this.previewId); + + hilog.info(0x0000, 'testTag', 'Prepare AVRecorder %{public}d', testNapi.prepareAVRecorder()); + + hilog.info(0x0000, 'testTag', 'prepare Camera %{public}d', testNapi.prepareCamera(this.focusMode, this.cameraDeviceIndex, + this.sceneMode, this.previewId, this.photoId, this.videoId)); + }) + .onDestroy(() => { + // 组件销毁时释放录制资源 + hilog.info(0x0000, 'testTag', 'Application is closing, perform cleanup.'); + testNapi.releaseAVRecorder(); + }) + .backgroundColor(Color.Black) + .width('100%') + .height('70%') + Flex({ direction: FlexDirection.Row, wrap:FlexWrap.Wrap, justifyContent: FlexAlign.SpaceEvenly, + alignItems: ItemAlign.Center, alignContent:FlexAlign.Center }) { + + // ** 可选: 获取实时录制参数 ** + Button($r('app.string.GetConfig'), { type: ButtonType.Circle, stateEffect: true }) + .id("GetConfig") + .backgroundColor(0xF55A42) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Get AVRecorder Config %{public}d', testNapi.getAVRecorderConfig()); + }) + + // ** 可选: 获取编码信息 ** + Button($r('app.string.GetInfo'), { type: ButtonType.Circle, stateEffect: true }) + .id("GetInfo") + .backgroundColor(0xF55A42) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Get AVRecorder EncoderInfo %{public}d', testNapi.getAvailableEncoder()); + }) + } + Flex({ direction: FlexDirection.Row, wrap:FlexWrap.Wrap, justifyContent: FlexAlign.SpaceEvenly, + alignItems: ItemAlign.Center, alignContent:FlexAlign.Center }){ + Button($r('app.string.Prepare'), { type: ButtonType.Circle, stateEffect: true }) + .id("Prepare") + .backgroundColor(Color.Black) + .width(65) + .height(65) + .onClick(() => { + this.previewId = this.mXComponentController.getXComponentSurfaceId(); + hilog.info(0x0000, 'testTag', 'dztdztdzt previewId: %{public}s', this.previewId); + hilog.info(0x0000, 'testTag', 'Prepare AVRecorder %{public}d', testNapi.prepareAVRecorder()); + hilog.info(0x0000, 'testTag', 'prepare Camera %{public}d', testNapi.prepareCamera(this.focusMode, this.cameraDeviceIndex, + this.sceneMode, this.previewId, this.photoId, this.videoId)); + hilog.info(0x0000, 'testTag', 'Start AVRecorder %{public}d', testNapi.startAVRecorder()); + }) + Button($r('app.string.Start'), { type: ButtonType.Circle, stateEffect: true }) + .id("Start") + .backgroundColor(0xF55A42) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'After prepare surfaceId: %{public}s', this.videoId); + hilog.info(0x0000, 'testTag', 'Start AVRecorder %{public}d', testNapi.startAVRecorder()); + }) + Button($r('app.string.Pause'), { type: ButtonType.Normal, stateEffect: true }) + .id("Pause") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Pause AVRecorder %{public}d', testNapi.pauseAVRecorder()); + }) + Button($r('app.string.Resume'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Resume") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Pause AVRecorder %{public}d', testNapi.resumeAVRecorder()); + }) + } + Flex({ direction: FlexDirection.Row, wrap:FlexWrap.Wrap, justifyContent: FlexAlign.SpaceEvenly, + alignItems: ItemAlign.Center, alignContent:FlexAlign.Center }){ + Button($r('app.string.Stop'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Stop") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Stop AVRecorder %{public}d', testNapi.stopAVRecorder()); + }) + Button($r('app.string.Reset'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Reset") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Reset AVRecorder %{public}d', testNapi.resetAVRecorder()); + }) + Button($r('app.string.Release'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Release") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Release AVRecorder %{public}d', testNapi.releaseAVRecorder()); + }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/module.json5 b/code/DocsSample/Media/AVRecorder/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c1964ea1db74d53564fae83a2848ca634e8d92f8 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/module.json5 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 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. + */ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "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:icon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.INTERNET", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.CAMERA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.MEDIA_LOCATION", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.KEEP_BACKGROUND_RUNNING", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + } + ] + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/color.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/string.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..4d2dc3eec6924f7e0974d5fd535ff16aafa6e950 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/string.json @@ -0,0 +1,56 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "AVRecorderSample" + }, + { + "name": "sample_label", + "value": "AVRecorderSample" + }, + { + "name": "GetConfig", + "value": "GetConfig" + }, + { + "name": "GetInfo", + "value": "GetInfo" + }, + { + "name": "Prepare", + "value": "Prepare" + }, + { + "name": "Start", + "value": "Start" + }, + { + "name": "Pause", + "value": "Pause" + }, + { + "name": "Resume", + "value": "Resume" + }, + { + "name": "Stop", + "value": "Stop" + }, + { + "name": "Reset", + "value": "Reset" + }, + { + "name": "Release", + "value": "Release" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/background.png b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/background.png differ diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/foreground.png b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/foreground.png differ diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/icon.png b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/icon.png differ diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/layered_image.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/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/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/startIcon.png b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/startIcon.png differ diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/profile/backup_config.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/profile/main_pages.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/en_US/element/string.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..601ab25fe4da66d4420ed9d455631cbdeaa9f4a8 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "AVRecorderSample" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/zh_CN/element/string.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f2585ecb9fb8847443d12a908df5ac3c4158e673 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "AVRecorderSample" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/ets/test/Ability.test.ets b/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..461d8d7fa495820bc108184791c4d90396dc0820 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 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 AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import Base from '@ohos.base'; +import { Driver, ON } from '@ohos.UiTest'; +import fs from '@ohos.file.fs'; + +const TAG = 'abilityTest'; +const domain: number = 0x0000; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + it('assertContain', 0, async () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let want: Want = { + bundleName: 'com.sample.avrecordersample', + abilityName: 'EntryAbility' + }; + let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); + abilityDelegator.startAbility(want, (err: Base.BusinessError) => { + hilog.info(domain, TAG, 'StartAbility get err ' + JSON.stringify(err)); + expect(err).assertNull(); + }) + let driver = await Driver.create(); + await driver.delayMs(2000); + let allowBtn1 = await driver.findComponent(ON.text(getContext().resourceManager.getStringSync($r('app.string.Prepare')))); + await allowBtn1.click(); + await driver.delayMs(1000); + let allowBtn2 = await driver.findComponent(ON.text(getContext().resourceManager.getStringSync($r('app.string.Start')))); + await allowBtn2.click(); + await driver.delayMs(2000); + let btn3 = await driver.findComponent(ON.text(getContext().resourceManager.getStringSync($r('app.string.Pause')))); + await btn3.click(); + await driver.delayMs(2000); + let btn4 = await driver.findComponent(ON.text(getContext().resourceManager.getStringSync($r('app.string.Resume')))); + await btn4.click(); + await driver.delayMs(2000); + let allowBtn3 = await driver.findComponent(ON.text(getContext().resourceManager.getStringSync($r('app.string.Stop')))); + await allowBtn3.click(); + await driver.delayMs(2000); + let btn5 = await driver.findComponent(ON.text(getContext().resourceManager.getStringSync($r('app.string.Release')))); + await btn5.click(); + let files: string[] = fs.listFileSync('/data/storage/el2/base/files/'); + expect(files).assertContain('avrecorder01.mp4'); + }) + }) +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/ets/test/List.test.ets b/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a10a79ed1d91b6040cc81d926b62c250e8f3866d --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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 abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/module.json5 b/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..289100b7775914b8848b7017b97fad55b85bb1bc --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/test/ List.test.ets b/code/DocsSample/Media/AVRecorder/entry/src/test/ List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/test/ List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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 localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/test/LocalUnit.test.ets b/code/DocsSample/Media/AVRecorder/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..05912c780dc1638f69dcd41b8498ce91304edc5d --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/hvigor/hvigor-config.json5 b/code/DocsSample/Media/AVRecorder/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..83e32c681a01e88d6010a24cb2434b3415b144c0 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/hvigor/hvigor-config.json5 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2025 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. + */ + +{ + "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": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + }, + "properties": { + // 配置为0,表示不启用内存缓存配置,默认为4,数值越低,内存中缓存数据越少 + "hvigor.pool.cache.capacity": 0, + // 默认配置为cpu核数-1, 包含ohos.arkCompile.maxSize4,值越小,占用内存越少 + "hvigor.pool.maxSize" : 5, + // 默认配置值为5, 值越小,占用内存越少 + "ohos.arkCompile.maxSize": 3, + // 默认配置值为true, 表示开启内存缓存,占用内存较多,配置为false,关闭内存缓存,占用内存较少 + "hvigor.enableMemoryCache": false + } +} diff --git a/code/DocsSample/Media/AVRecorder/hvigorfile.ts b/code/DocsSample/Media/AVRecorder/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..9decabcd15254bcd76825a00d7edf3ad0921c6bb --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/hvigorfile.ts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2025 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. + */ + +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +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/code/DocsSample/Media/AVRecorder/hvigorw b/code/DocsSample/Media/AVRecorder/hvigorw new file mode 100644 index 0000000000000000000000000000000000000000..3cf92084c1449f910e604b341202fb63ee43080c --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/hvigorw @@ -0,0 +1,60 @@ +# 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. +#!/bin/bash + +# ---------------------------------------------------------------------------- +# Hvigor startup script, version 1.0.0 +# +# Required ENV vars: +# ------------------ +# NODE_HOME - location of a Node home dir +# or +# Add /usr/local/nodejs/bin to the PATH environment variable +# ---------------------------------------------------------------------------- + +HVIGOR_APP_HOME=$(dirname $(readlink -f $0)) +HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js +warn() { + echo "" + echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m" +} + +error() { + echo "" + echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m" +} + +fail() { + error "$@" + exit 1 +} + +# Determine node to start hvigor wrapper script +if [ -n "${NODE_HOME}" ];then + EXECUTABLE_NODE="${NODE_HOME}/bin/node" + if [ ! -x "$EXECUTABLE_NODE" ];then + fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed" + fi +else + EXECUTABLE_NODE="node" + which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path" +fi + +# Check hvigor wrapper script +if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then + fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}" +fi + +# start hvigor-wrapper script +exec "${EXECUTABLE_NODE}" \ + "${HVIGOR_WRAPPER_SCRIPT}" "$@" diff --git a/code/DocsSample/Media/AVRecorder/hvigorw.bat b/code/DocsSample/Media/AVRecorder/hvigorw.bat new file mode 100644 index 0000000000000000000000000000000000000000..d77138670c41fdd9e06419d1f07ddbd010d72d4e --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/hvigorw.bat @@ -0,0 +1,63 @@ +@rem Copyright (C) 2025 Huawei Device Co., Ltd. +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@echo off +@rem +@rem ------------------------------------------------------------------- +@rem Hvigor startup script for Windows, version 1.0.0 +@rem +@rem Required ENV vars: +@rem ------------------ +@rem NODE_HOME - location of a Node home dir +@rem or +@rem Add %NODE_HOME%/bin to the PATH environment variable +@rem ------------------------------------------------------------------- +@rem + +set DIRNAME=%~dp0 +set APP_BASE_NAME=%~n0 +set NODE_EXE_PATH="" +set APP_HOME=. +set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js +set NODE_EXE=node.exe +@rem set NODE_OPTS="--max-old-space-size=4096" + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +if not defined NODE_OPTS set NODE_OPTS="--" + +@rem Find node.exe +if defined NODE_HOME ( + set NODE_HOME=%NODE_HOME:"=% + set "PATH=%PATH%;%NODE_HOME%" + set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE% +) + +%NODE_EXE% --version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" ( + "%NODE_EXE%" "%NODE_OPTS%" "%WRAPPER_MODULE_PATH%" %* +) else if exist "%NODE_EXE_PATH%" ( + "%NODE_EXE_PATH%" "%NODE_OPTS%" "%WRAPPER_MODULE_PATH%" %* +) else ( + echo. + echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH. + echo. + echo Please set the NODE_HOME variable in your environment to match the + echo location of your NodeJs installation. +) + +if "%ERRORLEVEL%" == "0"( + if "%OS%" == "Windows_NT" endlocal +) else ( + exit /b %ERRORLEVEL% +) diff --git a/code/DocsSample/Media/AVRecorder/oh-package.json5 b/code/DocsSample/Media/AVRecorder/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..bf39c8a7eae3489bfee9bdcdd62bfb504be6ac8c --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/oh-package.json5 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 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. + */ + +{ + "modelVersion": "5.0.0", + "license": "", + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + }, + "author": "", + "name": "AVRecorderSample", + "description": "Please describe the basic information.", + "main": "", + "version": "1.0.0", + "dependencies": {} +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/ohosTest.md b/code/DocsSample/Media/AVRecorder/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..b419a7aba494cf2a49e9761a9b581bf8554a7868 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/ohosTest.md @@ -0,0 +1,10 @@ +# AVRecorderSample测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|----------------|-----------|---------------------------------------------------------|---------------------------|------|------| +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 音视频录制功能 | 进入示例应用 | 1. 点击Prepare
2. 点击Start
3. 一段时间后点击Stop | 生成录制文件到沙箱 | 是 | Pass | +| 音频录制功能 | 进入示例应用 | 1. Demo中选择音频录制模式
2. 点击Prepare
3. 点击Start
4. 一段时间后点击Stop | 生成录制文件到沙箱 | 是 | Pass | +| 录制文件保存图库功能 | 进入示例应用 | 1. Demo中fileGenerationMode选择AUTO_CREATE模式
2. 点击Prepare
3. 点击Start
4. 一段时间后点击Stop | 视频文件保存至图库 | 是 | Pass | \ No newline at end of file