diff --git a/OAT.xml b/OAT.xml
index ede23a6b924f7e3a1dca34a3189c2094ef035ca8..cc753a0724b322ecf7aa522ded4db88f1f0318e2 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -782,7 +782,17 @@ Note:If the text contains special characters, please escape them according to th
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/ability/EntryAbility.ets b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/ability/EntryAbility.ets
index 642d74acd80d7b32d243641d700964ead8a3e968..5f81cef6f1119f9618b46394b405bfa57abbdd6d 100644
--- a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/ability/EntryAbility.ets
+++ b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/ability/EntryAbility.ets
@@ -76,7 +76,7 @@ export default class EntryAbility extends UIAbility {
}
onSaveState(reason: AbilityConstant.StateType, wantParam: Record): AbilityConstant.OnSaveResult {
- Logger.info(TAG, 'onDestroy');
+ Logger.info(TAG, 'onSaveState');
let string = this.storage.get('FaultTriggerPageString');
let counter = this.storage.get('FaultTriggerPageCounter');
wantParam['FaultTriggerPageString'] = string ?? 'Empty';
diff --git a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/FaultTriggerPage.ets b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/FaultTriggerPage.ets
index 57d867fd886b23f5c8c907f85b639be5201cac9b..5d0c57b05cd66bcfccd939f81057604051b041d0 100644
--- a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/FaultTriggerPage.ets
+++ b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/FaultTriggerPage.ets
@@ -61,7 +61,7 @@ struct FaultTriggerPage {
.fontSize('30fp')
.fontWeight(FontWeight.Bold)
.padding({ left: '24vp', right: '24vp', top: '7vp', bottom: '8vp' })
- .margin({ top: '24vp' })
+ .margin({ top: '14vp' })
.textAlign(TextAlign.Start)
.height('56vp')
.width('100%')
@@ -309,6 +309,7 @@ struct FaultTriggerPage {
.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
.padding({ left: '12vp', right: '12vp', top: '4vp', bottom: '4vp' })
.divider({ strokeWidth: '0.5vp', color: $r('app.color.text_grey_opacity') });
- }.backgroundColor($r('sys.color.ohos_id_color_sub_background')).width('100%').height('100%');
+ }.backgroundColor($r('sys.color.ohos_id_color_sub_background')).width('100%').height('100%')
+ .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]);
}
}
diff --git a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/Index.ets b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/Index.ets
index 6b5d3cb12eccb9906636dc8c72bf9a81ce349837..5d0ad7ec9b40c6a496587d8356b6d597f9fa963b 100644
--- a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/Index.ets
+++ b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/Index.ets
@@ -35,7 +35,7 @@ struct FirstPage {
.fontSize('30fp')
.fontWeight(FontWeight.Bold)
.padding({ left: '24vp', right: '24vp', top: '7vp', bottom: '8vp' })
- .margin({ top: '24vp' })
+ .margin({ top: '14vp' })
.textAlign(TextAlign.Start)
.height('56vp')
.width('100%')
@@ -84,9 +84,10 @@ struct FirstPage {
router.pushUrl({ url: 'pages/FaultTriggerPage' });
})
.width('88.9%')
- .margin({ top: '520vp', right: '24vp', left: '24vp', bottom: '24vp' })
+ .margin({ top: '480vp', right: '24vp', left: '24vp', bottom: '34vp' })
.height('40vp')
.backgroundColor($r('app.color.text_blue_opacity'));
- }.backgroundColor($r('sys.color.ohos_id_color_sub_background')).width('100%').height('100%');
+ }.backgroundColor($r('sys.color.ohos_id_color_sub_background')).width('100%').height('100%')
+ .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]);
}
}
diff --git a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/RecoveryPage.ets b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/RecoveryPage.ets
index 94a06d95385cbf63b912e73884f0cbccf127a843..9f4bb4093b7f9614986f1a7b9b3dc7ccf6f7b223 100644
--- a/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/RecoveryPage.ets
+++ b/code/BasicFeature/DFX/AppRecovery/entry/src/main/ets/pages/RecoveryPage.ets
@@ -37,7 +37,7 @@ struct Index {
.fontSize('30fp')
.fontWeight(FontWeight.Bold)
.padding({ left: '24vp', right: '24vp', top: '4vp', bottom: '4vp' })
- .margin({ top: '24vp' })
+ .margin({ top: '14vp' })
.textAlign(TextAlign.Start)
.height('56vp')
.width('100%')
@@ -106,6 +106,7 @@ struct Index {
.borderRadius('24vp')
.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
.padding({ left: '12vp', right: '12vp', top: '4vp', bottom: '4vp' })
- }.backgroundColor($r('sys.color.ohos_id_color_sub_background')).width('100%').height('100%');
+ }.backgroundColor($r('sys.color.ohos_id_color_sub_background')).width('100%').height('100%')
+ .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]);
}
}
diff --git a/code/BasicFeature/DFX/AppRecovery/entry/src/main/module.json5 b/code/BasicFeature/DFX/AppRecovery/entry/src/main/module.json5
index a62676c8a0a917df9f16e03bd567509d6334d11a..a096762082fa635a29e2722dde744167fd5a9630 100644
--- a/code/BasicFeature/DFX/AppRecovery/entry/src/main/module.json5
+++ b/code/BasicFeature/DFX/AppRecovery/entry/src/main/module.json5
@@ -18,28 +18,24 @@
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
- "srcEntrance": "./ets/app/MyAbilityStage.ets",
+ "srcEntry": "./ets/app/MyAbilityStage.ets",
"mainElement": "EntryAbility",
"deviceTypes": [
"default"
],
- "metadata": [ {
- "name": "ArkTSPartialUpdate",
- "value": "false"
- } ],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
- "srcEntrance": "./ets/ability/EntryAbility.ets",
+ "srcEntry": "./ets/ability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
- "visible": true,
+ "exported": true,
"recoverable": true,
"skills": [
{
@@ -54,24 +50,24 @@
},
{
"name": "SecondAbility",
- "srcEntrance": "./ets/ability/SecondAbility.ets",
+ "srcEntry": "./ets/ability/SecondAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:TextAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
- "visible": true,
+ "exported": true,
"recoverable": true
},
{
"name": "RecoveryAbility",
- "srcEntrance": "./ets/ability/RecoveryAbility.ets",
+ "srcEntry": "./ets/ability/RecoveryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:RecoveryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
- "visible": true
+ "exported": true
}
]
}
diff --git a/code/BasicFeature/DeviceManagement/DeviceManagementCollection/feature/capabilities/src/main/ets/capabilities/StationaryManager.ets b/code/BasicFeature/DeviceManagement/DeviceManagementCollection/feature/capabilities/src/main/ets/capabilities/StationaryManager.ets
index ebe6b3b6874751397471274bc915a47dd59974ac..7d2e783fa68903046c146dab152139028d70b286 100644
--- a/code/BasicFeature/DeviceManagement/DeviceManagementCollection/feature/capabilities/src/main/ets/capabilities/StationaryManager.ets
+++ b/code/BasicFeature/DeviceManagement/DeviceManagementCollection/feature/capabilities/src/main/ets/capabilities/StationaryManager.ets
@@ -47,7 +47,7 @@ export struct StationaryManager {
switch (index) {
case 0:
try {
- stationary.on('still', stationary.ActivityEvent.ENTER_EXIT, 3, (data) => {
+ stationary.on('still', stationary.ActivityEvent.ENTER_EXIT, 1000000000, (data) => {
this.result = `on still success:${JSON.stringify(data)}`;
})
this.result = ``;
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AK47.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AK47.png
index 8bed40617b07c305b188e36b209d1b5184c11ede..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AK47.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AK47.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AssaultRifle.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AssaultRifle.png
index 71d1a81b9a10ee3c986c51da959f290f5f397095..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AssaultRifle.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/AssaultRifle.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle5.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle5.png
index 9c54b2bb02fbb23e7c6b3511173f1dafb94ecf65..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle5.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle5.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle6.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle6.png
index 47ead0655e19885aa28c92d62f04d610f8a59ae7..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle6.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Battle6.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/CZ75.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/CZ75.png
index d4cb62341716c3a42319746fbf5cf76ed29ef550..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/CZ75.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/CZ75.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/HK416.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/HK416.png
index 49cf90102c18dd47bb5138d0a492278d2c8661e2..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/HK416.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/HK416.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/M4.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/M4.png
index d9ded788895475343b11b785ce6ff8a6415aac31..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/M4.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/M4.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/MP5.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/MP5.png
index 4b3016f5566a82f472695c07c5a5a72409e56dea..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/MP5.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/MP5.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Rifle.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Rifle.png
index 2bbb5539462dbe46b3d6d4e9d40f2d18a2256f69..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Rifle.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Rifle.png differ
diff --git a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Winchester.png b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Winchester.png
index 5a873ce7ce371c4ebc4c3f01b2448d88fa3bf4b9..ce307a8827bd75456441ceb57d530e4c8d45d36c 100644
Binary files a/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Winchester.png and b/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/Winchester.png differ
diff --git a/code/BasicFeature/FileManagement/FileShare/SandboxShare/README_zh.md b/code/BasicFeature/FileManagement/FileShare/SandboxShare/README_zh.md
index d50fbe18ac6bb75551f7d544a31610277d5425ee..daa8974200957af45a5164b015920194b33a6d4d 100644
--- a/code/BasicFeature/FileManagement/FileShare/SandboxShare/README_zh.md
+++ b/code/BasicFeature/FileManagement/FileShare/SandboxShare/README_zh.md
@@ -12,7 +12,7 @@
使用说明:
-1. 因本应用的功能依赖Picker应用,在使用本应用之前首先应安装[Picker](code/BasicFeature/FileManagement/FileShare/Picker)应用;
+1. 因本应用的功能依赖Picker应用,在使用本应用之前首先应安装[Picker](/code/SystemFeature/FileManagement/FileShare/Picker/README_zh.md)应用;
2. 在主界面,可以点击沙箱文件夹列出文件夹中的文件,同时也可以直接点击沙箱目录下的文件进入文件分享界面;
3. 点击沙箱文件,进入文件分享界面,点击分享图标,文件将以picker方式打开文件,点击编辑图标,文件进入可编辑模式,在textArea中输入内容,然后点击保存,文件内容更新,返回沙箱应用首页,文件修改成功。
@@ -34,13 +34,13 @@ entry/src/main/ets/
```
### 具体实现
-* 增添文件、查找指定类型文件、获取文件uri、传递want信息启动ability的功能接口封装在fileFs.ts,源码参考:[fileFs.ts](src/main/ets/fileFs/fileFs.ts)
+* 增添文件、查找指定类型文件、获取文件uri、传递want信息启动ability的功能接口封装在fileFs.ts,源码参考:[fileFs.ts](/code/BasicFeature/FileManagement/FileShare/SandboxShare/entry/src/main/ets/fileFs/fileFs.ts)
* 使用fs.mkdirSync、fs.openSync、fs.writeSync、fs.readSync、fs.closeSync分别用来来创建文件夹、打开文件、写文件、读文件、关闭文件,接口参考:[@ohos.file.fs](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-core-file-kit/js-apis-file-fs.md)
* 使用fileUri.getUriFromPath来获取文件uri,接口参考:[@ohos.file.fileuri](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-core-file-kit/js-apis-file-fileuri.md)
- * 分享文件至picker应用打开并编辑:在分享页面[show.ets](src/main/ets/pages/Show.ets)
+ * 分享文件至picker应用打开并编辑:在分享页面[show.ets](/code/BasicFeature/FileManagement/FileShare/SandboxShare/entry/src/main/ets/pages/Show.ets)
调用 implicitStartAbility 方法传递want参数启动新的ability,接口参考:[@ohos.ability.wantConstant](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ability-kit/js-apis-app-ability-wantConstant.md)、[@ohos.application.Want](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ability-kit/js-apis-app-ability-want.md)
@@ -56,7 +56,7 @@ entry/src/main/ets/
### 依赖
-本应用需要依赖[Picker](code/BasicFeature/FileManagement/FileShare/Picker)应用,沙箱文件需分享至Picker应用打开并编辑保存
+本应用需要依赖[Picker](/code/SystemFeature/FileManagement/FileShare/Picker/README_zh.md)应用,沙箱文件需分享至Picker应用打开并编辑保存
### 约束与限制
diff --git a/code/BasicFeature/Media/AVRecorder/AppScope/app.json5 b/code/BasicFeature/Media/AVRecorder/AppScope/app.json5
index 8144c6d886269b3ff896fc5efd480b259346c513..00bb30fbdc79a07de238ff9750c690400eff8bcf 100644
--- a/code/BasicFeature/Media/AVRecorder/AppScope/app.json5
+++ b/code/BasicFeature/Media/AVRecorder/AppScope/app.json5
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Huawei Device Co., Ltd.
+ * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
diff --git a/code/BasicFeature/Media/AVRecorder/README.md b/code/BasicFeature/Media/AVRecorder/README.md
index 91017eb56aebbe6761a7c59d74ea615ae7e4e903..bf0883b99a3bc3bc52adad557c3d381d19c6964f 100644
--- a/code/BasicFeature/Media/AVRecorder/README.md
+++ b/code/BasicFeature/Media/AVRecorder/README.md
@@ -22,7 +22,7 @@ ohos.permission.WRITE_MEDIA, which allows an app to write media files to the use
### Constraints
1. This sample can only be run on standard-system devices that use the phone.
-2. This sample is based on the stage model, which is supported from API version 9. You should manully fetch Full SDK from gitee and replace them in DevEco Studio.
-3. DevEco Studio 3.1 Beta2 (Build Version:3.1.0.400, built on April 7, 2023) must be used.
+2. This sample is based on the stage model, which is supported from API version 12. You should manully fetch Full SDK from gitee and replace them in DevEco Studio.
+3. DevEco Studio Next 5.0 Beta1 (Build Version:5.0.3.800, built on Sep 4, 2024) must be used.
3. Camera apis can only be used by system app. In order to run this sample, you should generate signature manually with hap-sign-tool.
diff --git a/code/BasicFeature/Media/AVRecorder/README_zh.md b/code/BasicFeature/Media/AVRecorder/README_zh.md
index 88e54379d2b8697288015818bee0701cc1c33c8d..1ef12400391a0fe764f35190cc156c5ab286c6ec 100644
--- a/code/BasicFeature/Media/AVRecorder/README_zh.md
+++ b/code/BasicFeature/Media/AVRecorder/README_zh.md
@@ -2,9 +2,9 @@
### 介绍
-音视频录制应用是基于AVRecorder接口开发的实现音频录制和视频录制功能的应用,音视频录制的主要工作是捕获音频信号,接收视频信号,完成音视频编码并保存到文件中,帮助开发者轻松实现音视频录制功能,包括开始录制、暂停录制、恢复录制、停止录制、释放资源等功能控制。它允许调用者指定录制的编码格式、封装格式、文件路径等参数。
+音视频录制应用是基于AVRecorder接口开发的实现音频录制和视频录制功能的应用,音视频录制的主要工作是捕获音频信号,接收视频信号,完成音视频编码并保存到文件中,帮助开发者轻松实现音视频录制功能,包括开始录制、暂停录制、恢复录制、停止录制、释放资源等功能控制。它允许调用者指定录制的图像size、音频采样频率等参数。
-本示例主要使用@ohos.multimedia.media中的AVRecorder接口实现了录制功能;另外辅助使用@ohos.multimedia.medialibrary接口,实现了创建录制文件功能,接口使用以及权限获取详见[媒体库管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-media-library-kit/js-apis-medialibrary.md)。使用@ohos.multimedia.camera接口,实现了相机预览及出流功能,接口使用以及权限获取详见[相机管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-camera-kit/js-apis-camera.md)。
+本示例主要使用@kit.MediaKit中的AVRecorder接口实现了录制功能;通过@kit.CoreFileKit接口支持,完成录制文件的创建,接口使用以及权限获取详见[文件管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-core-file-kit/Readme-CN.md)。使用@kit.CameraKit接口,实现了相机预览及出流功能,接口使用以及权限获取详见[相机管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-camera-kit/js-apis-camera.md)。
### 效果预览
@@ -18,6 +18,7 @@
2. 在主界面,可以点击视频录制、音频录制进入对应功能界面。
3. 点击视频录制页面,进入页面呈现摄像头预览画面,用户可以通过点击左上角的设置图标进行视频分辨率参数设置,点击”开始“”暂停“”恢复“”停止“等对应图标按钮进行视频录控相关操作。
4. 点击音频录制页面,用户可以通过点击左上角的设置图标进行音频采样率参数设置,点击”开始“”暂停“”恢复“”停止“等对应图标按钮进行音频录控相关操作。
+5. 在RK板硬件平台上,录制功能的性能可能受限,请在多种设备上进行测试以确保兼容性。
### 工程目录
@@ -40,8 +41,8 @@ entry/src/main/ets/
* 录控功能接口调用实现参考工程目录中的音频录制页面和视频录制页面
* 调用create()、prepare()、getInputSurface()、start()、pause()、resume()、stop()、reset()、release()接口实现录制器的创建、准备、录控操作、重置、销毁实例等功能;
- * 视频录制[VRecorder.ets](entry/src/main/ets/recorder/VideoRecorder.ets)调用Camera接口实现相机出流功能配合视频录制功能,相机的实现方法参考自相机接口[@ohos.multimedia.camera](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-camera-kit/js-apis-camera.md)
-* 调用MediaLibrary实现创建录制文件代码在[SaveCameraAsset.ets](entry/src/main/ets/utils/SaveCameraAsset.ets),实现方法参考[@ohos.multimedia.medialibrary](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-media-library-kit/js-apis-medialibrary.md)接口说明
+ * 视频录制[VRecorder.ets](entry/src/main/ets/recorder/VideoRecorder.ets)调用Camera接口实现相机出流配合视频录制功能,相机的实现方法参考自相机接口[@kit.CameraKit](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-camera-kit/js-apis-camera.md)
+* 调用文件基础服务接口实现创建录制文件代码在[SaveCameraAsset.ets](entry/src/main/ets/utils/SaveCameraAsset.ets),实现方法参考[@kit.CoreFileKit](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-core-file-kit/Readme-CN.md)接口说明
### 相关权限
@@ -51,7 +52,7 @@ entry/src/main/ets/
1.允许应用使用麦克风:[ohos.permission.MICROPHONE](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/AccessToken/permissions-for-all.md#ohospermissionmicrophone)
-2.允许应用使用相机拍摄照片和录制视频:[ohos.permission.CAMERA](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-camera-kit/js-apis-camera.md)
+2.允许应用使用相机拍照和录制视频:[ohos.permission.CAMERA](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/AccessToken/permissions-for-all.md#ohospermissioncamera)
3.允许应用读取用户外部存储中的媒体文件信息:[ohos.permission.READ_MEDIA](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/AccessToken/permissions-for-all.md#ohospermissionread_media)
@@ -67,9 +68,9 @@ entry/src/main/ets/
1.本示例仅支持在标准系统上运行,支持设备:Phone。
-2.本示例仅支持API9版本SDK,版本号:3.2.10.8。
+2.本示例仅支持API12版本SDK,版本号:5.0.0.65。
-3.本示例使用的IDE版本信息:DevEco Studio 3.1 Beta2 (Build Version:3.1.0.400, built on April 7, 2023)。
+3.本示例使用的IDE版本信息:DevEco Studio Next 5.0 Beta1 (Build Version:5.0.3.800, built on Sep 4, 2024)。
4.相机、媒体库为系统接口,需要配置高权限签名,相关权限级别可查阅权限列表,需要配置系统应用签名,可以参考[特殊权限配置方法](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/hapsigntool-overview.md)。
diff --git a/code/BasicFeature/Media/AVRecorder/build-profile.json5 b/code/BasicFeature/Media/AVRecorder/build-profile.json5
index 21dc67a99d8a1ab4ba28397ac2a17c9c3dd39e7a..41281d08083bf4d6cbefbefa5f7a616697bc3ca1 100644
--- a/code/BasicFeature/Media/AVRecorder/build-profile.json5
+++ b/code/BasicFeature/Media/AVRecorder/build-profile.json5
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Huawei Device Co., Ltd.
+ * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -16,12 +16,13 @@
{
"app": {
"signingConfigs": [],
- "compileSdkVersion": 9,
- "compatibleSdkVersion": 9,
"products": [
{
"name": "default",
"signingConfig": "default",
+ "compileSdkVersion": 12,
+ "compatibleSdkVersion": 12,
+ "runtimeOS": "OpenHarmony"
}
]
},
diff --git a/code/BasicFeature/Media/AVRecorder/entry/build-profile.json5 b/code/BasicFeature/Media/AVRecorder/entry/build-profile.json5
index 5ef60de78f49384eb91a1ecbcdbe528285e501bb..ca237e5aebcd437d6d27bf1707d2b5e245faf23f 100644
--- a/code/BasicFeature/Media/AVRecorder/entry/build-profile.json5
+++ b/code/BasicFeature/Media/AVRecorder/entry/build-profile.json5
@@ -1,17 +1,17 @@
/*
- * 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.
- */
+* Copyright (C) 2023-2024 Huawei Device Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
{
"apiType": 'stageMode',
@@ -22,7 +22,7 @@
"name": "default"
},
{
- "name": "ohosTest",
+ "name": "ohosTest"
}
]
}
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVRecorder/entry/oh-package.json5 b/code/BasicFeature/Media/AVRecorder/entry/oh-package.json5
index 402bef64646483ab2c3fc838384c33188cf7bbc5..a228c91fbe9056706bd1c7b4c2c5b7422f67e087 100644
--- a/code/BasicFeature/Media/AVRecorder/entry/oh-package.json5
+++ b/code/BasicFeature/Media/AVRecorder/entry/oh-package.json5
@@ -1,5 +1,5 @@
/*
-* Copyright (C) 2023 Huawei Device Co., Ltd.
+* Copyright (C) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -18,7 +18,6 @@
"devDependencies": {},
"name": "entry",
"description": "example description",
- "repository": {},
"version": "1.0.0",
"dependencies": {}
}
diff --git a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ts b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ts
index dd23b30f1ad4910a0f9e926d6f5f06fe25eea967..0f8892bf4264681bb8a50b453e97d95fe5904c01 100644
--- a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ts
+++ b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Huawei Device Co., Ltd.
+ * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -13,10 +13,10 @@
* limitations under the License.
*/
-import UIAbility from '@ohos.app.ability.UIAbility';
-import type window from '@ohos.window';
-import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
-import type { Permissions } from '@ohos.abilityAccessCtrl';
+import { UIAbility } from '@kit.AbilityKit';
+import { window } from '@kit.ArkUI';
+import { abilityAccessCtrl } from '@kit.AbilityKit';
+import { Permissions } from '@kit.AbilityKit';
import Logger from '../utils/Logger';
/**
@@ -33,14 +33,13 @@ export default class EntryAbility extends UIAbility {
atManager.requestPermissionsFromUser(globalThis.abilityContext, permissionNames).then((data) => {
Logger.info('testTag', 'requestPermissionsFromUser called');
});
- AppStorage.SetOrCreate('context', this.context);
}
onDestroy() {
Logger.info('testTag', 'Ability onDestroy');
}
- async onWindowStageCreate(windowStage: window.WindowStage): Promise {
+ async onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
Logger.info('testTag', 'Ability onWindowStageCreate');
diff --git a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/pages/ListPage.ets b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/pages/ListPage.ets
index 5f203204714bd299c67c6d836e16a59b911554b8..fad80ae403d7a7e671ade586e2ef3c45bd531459 100644
--- a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/pages/ListPage.ets
+++ b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/pages/ListPage.ets
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Huawei Device Co., Ltd.
+ * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -13,9 +13,7 @@
* limitations under the License.
*/
-import router from '@ohos.router';
-import common from '@ohos.app.ability.common';
-import Want from '@ohos.app.ability.Want';
+import { router } from '@kit.ArkUI';
import Logger from '../utils/Logger';
@Entry
@@ -44,16 +42,9 @@ struct ListPage {
.backgroundColor($r('app.color.button_background'))
.borderRadius(24)
.onClick(() => {
- let context: common.UIAbilityContext | undefined = AppStorage.Get('context');
- let want: Want = {
- bundleName: "com.samples.video_recorder",
- abilityName: "EntryAbility",
- };
- context && context.startAbility(want, (err) => {
- if (err.code) {
- Logger.error('StartAbility', `Failed to startAbility. Code: ${err.code}, message: ${err.message}`);
- }
- });
+ router.pushUrl({
+ url: 'recorder/VideoRecorder',
+ })
})
.margin({ left: 12, right:12, top: 0, bottom:12})
Button() {
diff --git a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/AudioRecorder.ets b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/AudioRecorder.ets
index ceab0e8bba0e200125ebab6c889ccae0a07348c9..6415057fd47132b8f8ebecbcdec8884fdb3050a5 100644
--- a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/AudioRecorder.ets
+++ b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/AudioRecorder.ets
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Huawei Device Co., Ltd.
+ * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -13,7 +13,8 @@
* limitations under the License.
*/
-import media from '@ohos.multimedia.media';
+import { media } from '@kit.MediaKit';
+import { BusinessError } from '@kit.BasicServicesKit';
import { dateTime } from '../utils/DateTimeUtils';
import Logger from '../utils/Logger';
import SaveCameraAsset from '../utils/SaveCameraAsset';
@@ -23,29 +24,29 @@ const TAG: string = 'Sample_AudioRecorder';
@Entry
@Component
struct AudioRecording {
- private audioRecorder: media.AVRecorder;
- private fdPath: string = undefined;
+ private audioRecorder?: media.AVRecorder;
+ private fdPath?: string = '';
@State frameRate: number = 15;
@State audioRecorderTimeText: string = '00:00';
private seconds: number = 0;
private timer: number = 0;
- @State displayLog: string = undefined;
+ @State displayLog: string = '';
private recorderState: string = 'free';
@State isStartRecording: boolean = false;
@State isPauseRecording: boolean = false;
private mSaveCameraAsset: SaveCameraAsset = new SaveCameraAsset(TAG);
- private mFileAssetId: number = 0; // init fd 0
+ private mFileAssetId?: number = 0; // init fd 0
@State audioChannels: number = 2; // set default audioChannels 2
@State audioSampleRate: number = 48000; // set default audioSampleRate 48000
- private avProfile = {
- audioBitrate: 48000, // set audioBitrate according to device ability
- audioChannels: 2, // set audioChannels, valid value 1-8
+ private avProfile: media.AVRecorderProfile = {
+ audioBitrate: 64000, // set audioBitrate according to device ability
+ audioChannels: 1, // set audioChannels, valid value 1-8
audioCodec: media.CodecMimeType.AUDIO_AAC, // set audioCodec, AUDIO_AAC is the only choice
- audioSampleRate: 48000, // set audioSampleRate according to device ability
+ audioSampleRate: 8000, // set audioSampleRate according to device ability
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // set fileFormat, for video is m4a
}
- private avConfig = {
+ private avConfig: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,
profile: this.avProfile,
url: 'fd://'
@@ -61,11 +62,11 @@ struct AudioRecording {
Logger.info(TAG, 'aboutToDisappear done');
}
- async failureCallback(error): Promise {
+ async failureCallback(error: BusinessError): Promise {
Logger.info(TAG, 'case failureCallback called,errMessage is ' + error.message);
}
- async catchCallback(error): Promise {
+ async catchCallback(error: BusinessError): Promise {
Logger.info(TAG, 'case catchCallback called,errMessage is ' + error.message);
}
@@ -103,89 +104,103 @@ struct AudioRecording {
// set callback on
setCallback(): void {
Logger.info(TAG, 'case callback');
- this.audioRecorder.on('stateChange', (state, reason) => {
- Logger.info(TAG, 'case state has changed, new state is' + state);
- switch (state) {
- case 'idle':
- this.recorderState = 'idle';
- break;
- case 'prepared':
- this.recorderState = 'prepared';
- break;
- case 'started':
- this.recorderState = 'started';
- this.getRecordTime();
- this.isStartRecording = true;
- this.isPauseRecording = false;
- break;
- case 'paused':
- this.recorderState = 'paused';
- clearInterval(this.timer);
- this.isPauseRecording = true;
- break;
- case 'stopped':
- this.recorderState = 'stopped';
- this.isStartRecording = false;
- break;
- case 'released':
- this.recorderState = 'released';
- break;
- case 'error':
- Logger.info(TAG, 'case error state!!!');
- this.recorderState = 'error';
- break;
- default:
- Logger.info(TAG, 'case start is unknown');
- break;
- }
- });
- this.audioRecorder.on('error', (err) => {
- Logger.info(TAG, 'case avRecorder.on(error) called, errMessage is ' + err.message);
- });
+ if (this.audioRecorder) {
+ this.audioRecorder.on('stateChange', (state, reason) => {
+ Logger.info(TAG, 'case state has changed, new state is' + state);
+ switch (state) {
+ case 'idle':
+ this.recorderState = 'idle';
+ break;
+ case 'prepared':
+ this.recorderState = 'prepared';
+ break;
+ case 'started':
+ this.recorderState = 'started';
+ this.getRecordTime();
+ this.isStartRecording = true;
+ this.isPauseRecording = false;
+ break;
+ case 'paused':
+ this.recorderState = 'paused';
+ clearInterval(this.timer);
+ this.isPauseRecording = true;
+ break;
+ case 'stopped':
+ this.recorderState = 'stopped';
+ this.isStartRecording = false;
+ break;
+ case 'released':
+ this.recorderState = 'released';
+ break;
+ case 'error':
+ Logger.info(TAG, 'case error state!!!');
+ this.recorderState = 'error';
+ break;
+ default:
+ Logger.info(TAG, 'case start is unknown');
+ break;
+ }
+ });
+ this.audioRecorder.on('error', (err) => {
+ Logger.info(TAG, 'case avRecorder.on(error) called, errMessage is ' + err.message);
+ });
+ }
}
async prepareAudioRecorder(): Promise {
Logger.info(TAG, 'case prepareAudioRecorder in');
this.avConfig.profile.audioChannels = this.audioChannels;
this.avConfig.profile.audioSampleRate = this.audioSampleRate;
- await this.audioRecorder.prepare(this.avConfig).then(() => {
- Logger.info(TAG, 'case prepare AVRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.audioRecorder) {
+ await this.audioRecorder.prepare(this.avConfig).then(() => {
+ Logger.info(TAG, 'case prepare AVRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
Logger.info(TAG, 'case prepareAudioRecorder out');
}
async startAudioRecording(): Promise {
Logger.info(TAG, 'case startAudioRecording called');
- await this.audioRecorder.start().then(() => {
- Logger.info(TAG, 'case start AudioRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.audioRecorder) {
+ await this.audioRecorder.start().then(() => {
+ Logger.info(TAG, 'case start AudioRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async pauseAudioRecording(): Promise {
Logger.info(TAG, 'case pauseAudioRecording called');
- await this.audioRecorder.pause().then(() => {
- Logger.info(TAG, 'case pause AudioRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.audioRecorder) {
+ await this.audioRecorder.pause().then(() => {
+ Logger.info(TAG, 'case pause AudioRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async resumeAudioRecording(): Promise {
Logger.info(TAG, 'case resumeAudioRecording called');
- await this.audioRecorder.resume().then(() => {
- Logger.info(TAG, 'case resume AudioRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.audioRecorder) {
+ await this.audioRecorder.resume().then(() => {
+ Logger.info(TAG, 'case resume AudioRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async stopAudioRecording(): Promise {
Logger.info(TAG, 'case stopAudioRecording called');
- await this.audioRecorder.stop().then(() => {
- Logger.info(TAG, 'case stop AudioRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.audioRecorder) {
+ await this.audioRecorder.stop().then(() => {
+ Logger.info(TAG, 'case stop AudioRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async resetAudioRecording(): Promise {
- await this.audioRecorder.reset().then(() => {
- Logger.info(TAG, 'case resetAudioRecording called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.audioRecorder) {
+ await this.audioRecorder.reset().then(() => {
+ Logger.info(TAG, 'case resetAudioRecording called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async releaseAudioRecorder(): Promise {
@@ -202,8 +217,8 @@ struct AudioRecording {
// close file fd
async closeFd(): Promise {
Logger.info(TAG, 'case closeFd called');
- if (this.fdPath) {
- await this.mSaveCameraAsset.AudioPrepareFile.close(this.mFileAssetId);
+ if (this.mSaveCameraAsset) {
+ await this.mSaveCameraAsset.closeAudioFile();
this.mFileAssetId = undefined;
this.fdPath = undefined;
Logger.info(TAG, 'case closeFd done');
@@ -367,8 +382,8 @@ struct CustomDialogSetting {
@Link audioChannels: number
@Link audioSampleRate: number
controller: CustomDialogController
- cancel: () => void
- confirm: () => void
+ cancel?: () => void
+ confirm?: () => void
@State currentAudioChannels: number = 2
@State currentAudioSampleRate: number = 48000
private initAudioChannels: number = this.audioChannels
@@ -387,7 +402,7 @@ struct CustomDialogSetting {
.margin({ left: 24, right: 24, top: 16 })
Column() {
List({ space: 10 }) {
- ForEach(this.audioSampleRateList, (item, index) => {
+ ForEach(this.audioSampleRateList, (item: number, index) => {
ListItem() {
Row() {
Text($r('app.string.audio_samplerate'))
@@ -429,7 +444,9 @@ struct CustomDialogSetting {
this.audioChannels = this.initAudioChannels
this.audioSampleRate = this.initAudioSampleRate
this.controller.close()
- this.cancel()
+ if (this.cancel) {
+ this.cancel()
+ }
})
.backgroundColor($r('app.color.button_background'))
.fontColor($r('app.color.button_color'))
@@ -448,7 +465,9 @@ struct CustomDialogSetting {
this.audioChannels = this.currentAudioChannels
this.audioSampleRate = this.currentAudioSampleRate
this.controller.close()
- this.confirm()
+ if (this.confirm) {
+ this.confirm()
+ }
})
.backgroundColor($r('app.color.button_background'))
.fontColor($r('app.color.button_color'))
diff --git a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/VideoRecorder.ets b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/VideoRecorder.ets
index d0959138fbe094b68ad5a4f6dafa6b279eceb35b..ffd051389e9be4e01ed6b842d2a08971090f11cd 100644
--- a/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/VideoRecorder.ets
+++ b/code/BasicFeature/Media/AVRecorder/entry/src/main/ets/recorder/VideoRecorder.ets
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Huawei Device Co., Ltd.
+ * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -13,8 +13,9 @@
* limitations under the License.
*/
-import camera from '@ohos.multimedia.camera';
-import media from '@ohos.multimedia.media';
+import { camera } from '@kit.CameraKit';
+import { media } from '@kit.MediaKit';
+import { BusinessError } from '@kit.BasicServicesKit';
import { dateTime } from '../utils/DateTimeUtils';
import Logger from '../utils/Logger';
import SaveCameraAsset from '../utils/SaveCameraAsset';
@@ -26,44 +27,44 @@ const TAG: string = 'Sample_VideoRecorder';
struct VideoRecording {
private surfaceId: string = '';
xcomponentController: XComponentController = new XComponentController();
- private videoRecorder: media.AVRecorder;
- private cameraManager: camera.CameraManager;
- private cameras: any = undefined;
- private cameraInput: camera.CameraInput;
- private captureSession: camera.CaptureSession;
- private previewOutput: camera.PreviewOutput;
- private videoOutput: camera.VideoOutput;
+ private videoRecorder?: media.AVRecorder;
+ private cameraManager?: camera.CameraManager;
+ private cameras?: Array;
+ private cameraInput?: camera.CameraInput;
+ private captureSession?: camera.CaptureSession;
+ private previewOutput?: camera.PreviewOutput;
+ private videoOutput?: camera.VideoOutput;
private videoOutSurfaceId: string = '';
- private fdPath: string = undefined;
+ private fdPath?: string = '';
@State videoRecorderTimeText: string = '00:00';
private seconds: number = 0;
private timer: number = 0;
private cameraIndex: number = 0;
- @State videoResolution: object = { 'frameWidth': 1280, 'frameHeight': 720};
+ @State videoResolution: Resolution = { frameWidth: 1920, frameHeight: 1080};
@State framerate: number = 30; // set default video framerate 30
@State videoCodecType: string = 'video/avc';
private recorderState: string = 'free';
@State isStartRecording: boolean = false;
@State isPauseRecording: boolean = false;
private mSaveCameraAsset: SaveCameraAsset = new SaveCameraAsset(TAG);
- private mFileAssetId: number = 0;
- private cameraOutputCapability: camera.CameraOutputCapability = undefined;
- private videoProfiles: any = undefined;
- private previewProfiles: any = undefined;
+ private mFileAssetId?: number = 0;
+ private cameraOutputCapability?: camera.CameraOutputCapability;
+ private curVideoProfiles?: Array;
+ private previewProfiles?: Array;
- private avProfile = {
+ private avProfile: media.AVRecorderProfile = {
audioBitrate: 200000, // set audioBitrate according to device ability
audioChannels: 2, // set audioChannels, valid value 1-8
audioCodec: media.CodecMimeType.AUDIO_AAC, // set audioCodec, AUDIO_AAC is the only choice
audioSampleRate: 48000, // set audioSampleRate according to device ability
fileFormat: media.ContainerFormatType.CFT_MPEG_4, // set fileFormat, for video is mp4
- videoBitrate: 300000, // set videoBitrate according to device ability
+ videoBitrate: 3000000, // set videoBitrate according to device ability
videoCodec: media.CodecMimeType.VIDEO_AVC, // set videoCodec, avc or mpeg4 can be selected
videoFrameWidth: 640, // set videoFrameWidth according to device ability
videoFrameHeight: 480, // set videoFrameHeight according to device ability
videoFrameRate: 30 // set videoFrameRate according to device ability
}
- private avConfig = {
+ private avConfig: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,
videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV,
profile: this.avProfile,
@@ -91,11 +92,11 @@ struct VideoRecording {
this.stopRecordingProcess();
}
- async failureCallback(error): Promise {
+ async failureCallback(error: BusinessError): Promise {
Logger.info(TAG, 'case failureCallback called,errMessage is ' + error.message);
}
- async catchCallback(error): Promise {
+ async catchCallback(error: BusinessError): Promise {
Logger.info(TAG, 'case catchCallback called,errMessage is ' + error.message);
}
@@ -139,59 +140,65 @@ struct VideoRecording {
Logger.info(TAG, '[camera] case getCameras failed');
}
this.cameraOutputCapability = this.cameraManager.getSupportedOutputCapability(this.cameras[this.cameraIndex]);
- this.videoProfiles = this.cameraOutputCapability.videoProfiles;
+ this.curVideoProfiles = this.cameraOutputCapability.videoProfiles;
Logger.info(TAG, 'init camera done');
}
// create camera input
async createCameraInput(): Promise {
Logger.info(TAG, 'createCameraInput called');
- this.cameraInput = this.cameraManager.createCameraInput(this.cameras[this.cameraIndex]);
- if (this.cameraInput) {
- Logger.info(TAG, '[camera] case createCameraInput success');
- } else {
- Logger.info(TAG, '[camera] case createCameraInput failed');
- return;
+ if (this.cameraManager && this.cameras && this.cameras.length > 0) {
+ this.cameraInput = this.cameraManager.createCameraInput(this.cameras[this.cameraIndex]);
+ if (this.cameraInput) {
+ Logger.info(TAG, '[camera] case createCameraInput success');
+ } else {
+ Logger.info(TAG, '[camera] case createCameraInput failed');
+ return;
+ }
+ await this.cameraInput.open().then(() => {
+ Logger.info(TAG, '[camera] case cameraInput.open() called');
+ }, this.failureCallback).catch(this.catchCallback);
}
- await this.cameraInput.open().then(() => {
- Logger.info(TAG, '[camera] case cameraInput.open() called');
- }, this.failureCallback).catch(this.catchCallback);
}
// create camera preview
async createPreviewOutput(): Promise {
Logger.info(TAG, 'createPreviewOutput called');
- this.previewProfiles = this.cameraOutputCapability.previewProfiles;
- this.previewProfiles[0].size.height = this.videoResolution['frameHeight'];
- this.previewProfiles[0].size.width = this.videoResolution['frameWidth'];
- if (this.previewProfiles[0].format === camera.CameraFormat.CAMERA_FORMAT_YUV_420_SP) {
- Logger.info(TAG, '[camera] case format is VIDEO_SOURCE_TYPE_SURFACE_YUV');
- this.avConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV;
- } else {
- Logger.info(TAG, '[camera] case format is VIDEO_SOURCE_TYPE_SURFACE_ES');
- this.avConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_ES;
- }
- this.previewOutput = this.cameraManager.createPreviewOutput(this.previewProfiles[0], this.surfaceId);
- if (!this.previewOutput) {
- Logger.info(TAG, 'create previewOutput failed!');
+ if (this.cameraOutputCapability && this.cameraManager) {
+ this.previewProfiles = this.cameraOutputCapability.previewProfiles;
+ this.previewProfiles[0].size.height = this.videoResolution.frameHeight;
+ this.previewProfiles[0].size.width = this.videoResolution.frameWidth;
+ if (this.previewProfiles[0].format === camera.CameraFormat.CAMERA_FORMAT_YUV_420_SP) {
+ Logger.info(TAG, '[camera] case format is VIDEO_SOURCE_TYPE_SURFACE_YUV');
+ this.avConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV;
+ } else {
+ Logger.info(TAG, '[camera] case format is VIDEO_SOURCE_TYPE_SURFACE_ES');
+ this.avConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_ES;
+ }
+ this.previewOutput = this.cameraManager.createPreviewOutput(this.previewProfiles[0], this.surfaceId);
+ if (!this.previewOutput) {
+ Logger.info(TAG, 'create previewOutput failed!');
+ }
+ Logger.info(TAG, 'createPreviewOutput done');
}
- Logger.info(TAG, 'createPreviewOutput done');
}
// create camera capture session
async createCaptureSession(): Promise {
Logger.info(TAG, 'createCaptureSession called');
- this.captureSession = this.cameraManager.createCaptureSession();
- if (!this.captureSession) {
- Logger.info(TAG, 'createCaptureSession failed!');
- return
+ if (this.cameraManager) {
+ this.captureSession = this.cameraManager.createCaptureSession();
+ if (!this.captureSession) {
+ Logger.info(TAG, 'createCaptureSession failed!');
+ return
+ }
+ this.captureSession.beginConfig();
+ this.captureSession.addInput(this.cameraInput);
+ this.captureSession.addOutput(this.previewOutput);
+ await this.captureSession.commitConfig().then(() => {
+ Logger.info(TAG, 'case commitConfig success');
+ }, this.failureCallback).catch(this.catchCallback);
}
- this.captureSession.beginConfig();
- this.captureSession.addInput(this.cameraInput);
- this.captureSession.addOutput(this.previewOutput);
- await this.captureSession.commitConfig().then(() => {
- Logger.info(TAG, 'case commitConfig success');
- }, this.failureCallback).catch(this.catchCallback);
}
// start captureSession
@@ -211,8 +218,10 @@ struct VideoRecording {
Logger.info(TAG, 'removeVideoOutput called');
if (this.videoOutput) {
Logger.info(TAG, 'videoOutput already exits, remove it');
- this.captureSession.removeOutput(this.videoOutput);
- Logger.info(TAG, 'remove videoOutput done');
+ if (this.captureSession) {
+ this.captureSession.removeOutput(this.videoOutput);
+ Logger.info(TAG, 'remove videoOutput done');
+ }
}
Logger.info(TAG, 'removeVideoOutput done');
}
@@ -220,10 +229,10 @@ struct VideoRecording {
// create video output
async createVideoOutput(): Promise {
Logger.info(TAG, 'createVideoOutput called');
- if (this.videoRecorder) {
- this.videoProfiles[this.cameraIndex].size.height = this.videoResolution['frameHeight'];
- this.videoProfiles[this.cameraIndex].size.width = this.videoResolution['frameWidth'];
- this.videoOutput = this.cameraManager.createVideoOutput(this.videoProfiles[this.cameraIndex], this.videoOutSurfaceId);
+ if (this.videoRecorder && this.curVideoProfiles && this.cameraManager) {
+ this.curVideoProfiles[this.cameraIndex].size.height = this.videoResolution.frameHeight;
+ this.curVideoProfiles[this.cameraIndex].size.width = this.videoResolution.frameWidth;
+ this.videoOutput = this.cameraManager.createVideoOutput(this.curVideoProfiles[this.cameraIndex], this.videoOutSurfaceId);
if (!this.videoOutput) {
Logger.info(TAG, '[camera] case create videoOutPut fail!!!');
return;
@@ -239,24 +248,26 @@ struct VideoRecording {
// add video output into CaptureSession
async restartVideoOutput(): Promise {
Logger.info(TAG, 'restartVideoOutput called');
- await this.captureSession.stop().then(() => {
- Logger.info(TAG, 'case stop captureSession success');
- }, this.failureCallback).catch(this.catchCallback);
- this.captureSession.beginConfig();
- await this.removeVideoOutput();
- await this.createVideoOutput();
- this.captureSession.addOutput(this.videoOutput);
- await this.captureSession.commitConfig().then(() => {
- Logger.info(TAG, 'case commitConfig success');
- }, this.failureCallback).catch(this.catchCallback);
- await this.startCaptureSession();
- if (this.videoOutput) {
- await this.videoOutput.start().then(() => {
- Logger.info(TAG, '[camera] case videoOutput start success');
+ if (this.captureSession) {
+ await this.captureSession.stop().then(() => {
+ Logger.info(TAG, 'case stop captureSession success');
}, this.failureCallback).catch(this.catchCallback);
- } else {
- Logger.info(TAG, 'videoOutput is null!!!');
- return;
+ this.captureSession.beginConfig();
+ await this.removeVideoOutput();
+ await this.createVideoOutput();
+ this.captureSession.addOutput(this.videoOutput);
+ await this.captureSession.commitConfig().then(() => {
+ Logger.info(TAG, 'case commitConfig success');
+ }, this.failureCallback).catch(this.catchCallback);
+ await this.startCaptureSession();
+ if (this.videoOutput) {
+ await this.videoOutput.start().then(() => {
+ Logger.info(TAG, '[camera] case videoOutput start success');
+ }, this.failureCallback).catch(this.catchCallback);
+ } else {
+ Logger.info(TAG, 'videoOutput is null!!!');
+ return;
+ }
}
}
@@ -290,7 +301,7 @@ struct VideoRecording {
async releaseCameraInput(): Promise {
Logger.info(TAG, 'releaseCameraInput called');
if (this.cameraInput) {
- this.cameraInput = null;
+ this.cameraInput = undefined;
}
Logger.info(TAG, 'releaseCameraInput done');
}
@@ -302,7 +313,7 @@ struct VideoRecording {
await this.previewOutput.release().then(() => {
Logger.info('[camera] case main previewOutput release called');
}, this.failureCallback).catch(this.catchCallback);
- this.previewOutput = null;
+ this.previewOutput = undefined;
}
Logger.info(TAG, 'releasePreviewOutput done');
}
@@ -314,7 +325,7 @@ struct VideoRecording {
await this.videoOutput.release().then(() => {
Logger.info('[camera] case main videoOutput release called');
}, this.failureCallback).catch(this.catchCallback);
- this.videoOutput = null;
+ this.videoOutput = undefined;
}
Logger.info(TAG, 'releaseVideoOutput done');
}
@@ -337,7 +348,7 @@ struct VideoRecording {
await this.captureSession.release().then(() => {
Logger.info('[camera] case main captureSession release success');
}, this.failureCallback).catch(this.catchCallback);
- this.captureSession = null;
+ this.captureSession = undefined;
}
Logger.info(TAG, 'releaseCaptureSession done');
}
@@ -356,45 +367,47 @@ struct VideoRecording {
// set callback on
setCallback(): void {
Logger.info('case callback');
- this.videoRecorder.on('stateChange', (state, reason) => {
- Logger.info('case state has changed, new state is' + state);
- switch (state) {
- case 'idle':
- this.recorderState = 'idle';
- break;
- case 'prepared':
- this.recorderState = 'prepared';
- break;
- case 'started':
- this.recorderState = 'started';
- this.getRecordTime();
- this.isStartRecording = true;
- this.isPauseRecording = false;
- break;
- case 'paused':
- this.recorderState = 'paused';
- clearInterval(this.timer);
- this.isPauseRecording = true;
- break;
- case 'stopped':
- this.recorderState = 'stopped';
- this.isStartRecording = false;
- break;
- case 'released':
- this.recorderState = 'released';
- break;
- case 'error':
- Logger.info('case error state!!!');
- this.recorderState = 'error';
- break;
- default:
- Logger.info('case start is unknown');
- break;
- }
- });
- this.videoRecorder.on('error', (err) => {
- Logger.info(TAG, 'case avRecorder.on(error) called, errMessage is ' + err.message);
- });
+ if (this.videoRecorder) {
+ this.videoRecorder.on('stateChange', (state, reason) => {
+ Logger.info('case state has changed, new state is' + state);
+ switch (state) {
+ case 'idle':
+ this.recorderState = 'idle';
+ break;
+ case 'prepared':
+ this.recorderState = 'prepared';
+ break;
+ case 'started':
+ this.recorderState = 'started';
+ this.getRecordTime();
+ this.isStartRecording = true;
+ this.isPauseRecording = false;
+ break;
+ case 'paused':
+ this.recorderState = 'paused';
+ clearInterval(this.timer);
+ this.isPauseRecording = true;
+ break;
+ case 'stopped':
+ this.recorderState = 'stopped';
+ this.isStartRecording = false;
+ break;
+ case 'released':
+ this.recorderState = 'released';
+ break;
+ case 'error':
+ Logger.info('case error state!!!');
+ this.recorderState = 'error';
+ break;
+ default:
+ Logger.info('case start is unknown');
+ break;
+ }
+ });
+ this.videoRecorder.on('error', (err) => {
+ Logger.info(TAG, 'case avRecorder.on(error) called, errMessage is ' + err.message);
+ });
+ }
}
async createVideoRecorder(): Promise {
@@ -417,61 +430,75 @@ struct VideoRecording {
} else {
this.avConfig.profile.videoCodec = media.CodecMimeType.VIDEO_AVC;
}
- this.avConfig.profile.videoFrameHeight = this.videoResolution['frameHeight'];
- this.avConfig.profile.videoFrameWidth = this.videoResolution['frameWidth'];
+ this.avConfig.profile.videoFrameHeight = this.videoResolution.frameHeight;
+ this.avConfig.profile.videoFrameWidth = this.videoResolution.frameWidth;
this.avConfig.profile.videoFrameRate = this.framerate;
- await this.videoRecorder.prepare(this.avConfig).then(() => {
- Logger.info(TAG, 'case prepare AVRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
- Logger.info(TAG, 'case prepareVideoRecorder out');
+ if (this.videoRecorder) {
+ await this.videoRecorder.prepare(this.avConfig).then(() => {
+ Logger.info(TAG, 'case prepare AVRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ Logger.info(TAG, 'case prepareVideoRecorder out');
+ }
}
async getInputSurface(): Promise {
Logger.info(TAG, 'case getInputSurface in');
- await this.videoRecorder.getInputSurface().then((outPutSurface) => {
- Logger.info('case getInputSurface called');
- if (!outPutSurface) {
- Logger.error(TAG, 'case getInputSurface ID is none');
- return
- }
- this.videoOutSurfaceId = outPutSurface;
- Logger.info(TAG, 'case outPutSurface surfaceID is: ${this.videoOutSurfaceId}');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.videoRecorder) {
+ await this.videoRecorder.getInputSurface().then((outPutSurface) => {
+ Logger.info('case getInputSurface called');
+ if (!outPutSurface) {
+ Logger.error(TAG, 'case getInputSurface ID is none');
+ return
+ }
+ this.videoOutSurfaceId = outPutSurface;
+ Logger.info(TAG, 'case outPutSurface surfaceID is: ${this.videoOutSurfaceId}');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
Logger.info(TAG, 'case getInputSurface out');
}
async startVideoRecording(): Promise {
Logger.info(TAG, 'case startVideoRecording called');
- await this.videoRecorder.start().then(() => {
- Logger.info(TAG, 'case start VideoRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.videoRecorder) {
+ await this.videoRecorder.start().then(() => {
+ Logger.info(TAG, 'case start VideoRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async pauseVideoRecording(): Promise {
Logger.info(TAG, 'case pauseVideoRecording called');
- await this.videoRecorder.pause().then(() => {
- Logger.info(TAG, 'case pause VideoRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.videoRecorder) {
+ await this.videoRecorder.pause().then(() => {
+ Logger.info(TAG, 'case pause VideoRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async resumeVideoRecording(): Promise {
Logger.info(TAG, 'case resumeVideoRecording called');
- await this.videoRecorder.resume().then(() => {
- Logger.info(TAG, 'case resume VideoRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.videoRecorder) {
+ await this.videoRecorder.resume().then(() => {
+ Logger.info(TAG, 'case resume VideoRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async stopVideoRecording(): Promise {
Logger.info(TAG, 'case stopVideoRecording called');
- await this.videoRecorder.stop().then(() => {
- Logger.info(TAG, 'case stop VideoRecorder called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.videoRecorder) {
+ await this.videoRecorder.stop().then(() => {
+ Logger.info(TAG, 'case stop VideoRecorder called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async resetVideoRecording(): Promise {
- await this.videoRecorder.reset().then(() => {
- Logger.info(TAG, 'case resetVideoRecording called');
- }, this.failureCallback).catch(this.catchCallback);
+ if (this.videoRecorder) {
+ await this.videoRecorder.reset().then(() => {
+ Logger.info(TAG, 'case resetVideoRecording called');
+ }, this.failureCallback).catch(this.catchCallback);
+ }
}
async releaseVideoRecorder(): Promise {
@@ -488,8 +515,8 @@ struct VideoRecording {
// close file fd
async closeFd(): Promise {
Logger.info(TAG, 'case closeFd called');
- if (this.fdPath) {
- await this.mSaveCameraAsset.VideoPrepareFile.close(this.mFileAssetId);
+ if (this.mSaveCameraAsset) {
+ await this.mSaveCameraAsset.closeVideoFile();
this.mFileAssetId = undefined;
this.fdPath = undefined;
Logger.info(TAG, 'case closeFd done');
@@ -575,7 +602,6 @@ struct VideoRecording {
this.surfaceId = this.xcomponentController.getXComponentSurfaceId()
Logger.info(TAG, '[VideoRecorder] surfaceId: ' + this.surfaceId)
Logger.info(TAG, 'XComponent1 loaded');
- this.enterInit();
})
.width('100%').height('100%')
Text(this.videoRecorderTimeText)
@@ -675,32 +701,51 @@ struct VideoRecording {
})
}
+class Resolution {
+ public frameWidth: number = 0
+ public frameHeight: number = 0
+}
+
+class VideoResolution {
+ public itemValue: string = ''
+ public value: Resolution = { frameWidth: 0, frameHeight: 0 }
+}
+
+class VideoFrameRate {
+ public itemValue: string = ''
+ public value: number = 0
+}
+
+class VideoCodec {
+ public itemValue: string = ''
+ public value: string = ''
+}
@CustomDialog
struct CustomDialogSetting {
- @Link videoResolution: Object
+ @Link videoResolution: Resolution
@Link videoFrameRate: number
@Link videoCodec: string
controller: CustomDialogController
- cancel: () => void
- confirm: () => void
- @State currentVideoResolution: Object = { 'frameWidth': 1280, 'frameHeight': 720 }
- @State currentVideoResolutionText: string = '[16:9]720p'
+ cancel?: () => void
+ confirm?: () => void
+ @State currentVideoResolution: Resolution = { frameWidth: 1920, frameHeight: 1080 }
+ @State currentVideoResolutionText: string = '[16:9]1080p'
@State currentVideoFramerate: number = 30
@State currentVideoCodec: string = 'video/avc'
- private initVideoResolution: Object = this.videoResolution
+ private initVideoResolution: Resolution = this.videoResolution
private initVideoFramerate: number = this.videoFrameRate
- private initVideoCodec: string = this.videoCodec
- @State videoResolutionList: Array