diff --git a/ohos/vap/.gitignore b/ohos/vap/.gitignore
new file mode 100644
index 00000000..d2ff2014
--- /dev/null
+++ b/ohos/vap/.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/ohos/vap/AppScope/app.json5 b/ohos/vap/AppScope/app.json5
new file mode 100644
index 00000000..1ebb8e62
--- /dev/null
+++ b/ohos/vap/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.openharmony.vap",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.1.3",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/ohos/vap/AppScope/resources/base/element/string.json b/ohos/vap/AppScope/resources/base/element/string.json
new file mode 100644
index 00000000..1080233f
--- /dev/null
+++ b/ohos/vap/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "MyApplication"
+ }
+ ]
+}
diff --git a/ohos/vap/AppScope/resources/base/media/app_icon.png b/ohos/vap/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 00000000..cd45accb
Binary files /dev/null and b/ohos/vap/AppScope/resources/base/media/app_icon.png differ
diff --git a/ohos/vap/COMMITTERS.md b/ohos/vap/COMMITTERS.md
new file mode 100644
index 00000000..c10d0065
--- /dev/null
+++ b/ohos/vap/COMMITTERS.md
@@ -0,0 +1,8 @@
+## Committers列表
+
+### 以下是此项目的committer人员
+不区分先后顺序
+
+- [MaDiXin](https://gitee.com/MaDiXin)
+- [XiaFeng](https://gitee.com/xiafeng_xf_admin)
+- [ZhuChengCheng](https://gitee.com/zhu_chengcheng)
diff --git a/ohos/vap/LICENSE b/ohos/vap/LICENSE
new file mode 100644
index 00000000..f433b1a5
--- /dev/null
+++ b/ohos/vap/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/ohos/vap/LICENSE.MIT b/ohos/vap/LICENSE.MIT
new file mode 100644
index 00000000..5844fa83
--- /dev/null
+++ b/ohos/vap/LICENSE.MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2013-2024 Niels Lohmann
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/ohos/vap/LICENSE.txt b/ohos/vap/LICENSE.txt
new file mode 100644
index 00000000..f433b1a5
--- /dev/null
+++ b/ohos/vap/LICENSE.txt
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/ohos/vap/OAT.xml b/ohos/vap/OAT.xml
new file mode 100644
index 00000000..171deca5
--- /dev/null
+++ b/ohos/vap/OAT.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ohos/vap/README.OpenSource b/ohos/vap/README.OpenSource
new file mode 100644
index 00000000..74c295fc
--- /dev/null
+++ b/ohos/vap/README.OpenSource
@@ -0,0 +1,12 @@
+[
+ {
+ "Name": "VAP",
+ "License": "MIT License",
+ "License File": " LICENSE.txt ",
+ "Version Number": "2.0.28",
+ "Owner" : "xiafeng@huawei.com",
+ "Upstream URL": "https://github.com/Tencent/vap",
+ "Description": "VAP is a implementing special effect animations. It features a high compression rate and hardware decoding."
+ "Dependencies": ["json"]
+ }
+]
\ No newline at end of file
diff --git a/ohos/vap/README.md b/ohos/vap/README.md
new file mode 100644
index 00000000..94ac8958
--- /dev/null
+++ b/ohos/vap/README.md
@@ -0,0 +1,272 @@
+
+ OHOS-VAP
+
+
+
+ English | 简体中文
+
+
+
+
+
+
+
+
+In the era of digital entertainment and online interaction, the quality of visual effects directly impacts user experience. `OHOS-VAP` is a powerful animation particle effect rendering component built on `OpenHarmony` using `OpenGL` technology and specialized algorithms. Not only does it provide stunning animation effects for applications, but it also creates an immersive visual experience for users.
+
+
+
+## Key Features
+
+- Compared to Webp and Apng animation schemes, it offers high compression rates (smaller assets) and hardware decoding (faster decoding) advantages.
+- Compared to Lottie, it can achieve more complex animation effects (like particle effects).
+- High-performance rendering: With the powerful capabilities of OpenGL, OHOS-VAP achieves efficient particle effect rendering, ensuring a smooth user experience across various devices.
+- Easy integration: OHOS-VAP has a simple design, making it easy to integrate with existing projects, helping developers quickly implement stunning animation effects and enhance application appeal.
+- Multi-platform support: Compatible with multiple devices, whether on phones, tablets, or computers, OHOS-VAP can provide consistent visual effects, facilitating cross-terminal application development.
+
+## Application Scenarios
+
+- Live broadcast effects: On major short video platforms such as Douyin, Kuaishou, and others, use OHOS-VAP to add cool gift effects to live broadcasts, enhancing audience interaction and increasing the fun of the broadcast.
+- E-commerce promotional activities: In gaming and e-commerce platform events, use OHOS-VAP to achieve stunning product display effects, attract users' attention, and drive sales conversions.
+- Game experience enhancement: Add particle effects to game scenes to enhance overall gaming experience, immersing players in a more vivid virtual world.
+ 
+
+## Build Dependencies
+
+- IDE Version: DevEco Studio 5.0.1.403
+- SDK Version: ohos_sdk_public 5.0.0 (API Version 12 Release)
+- Developers can call the `this.xComponentContext.play()` interface to implement custom video parameter paths (supports network URLs).
+
+### C/C++ Layer Directory Structure
+
+```
+├─include # Mask, Mix, Renderer, Utility class header files storage
+│ ├─mask
+│ ├─mix
+│ ├─render
+│ └─util
+├─manager # xcomponent life cycle management
+├─mask # Implementation of masking
+├─mix # Implementation of mixing
+├─napi # Napi layer function encapsulation
+├─render # Implementation of the renderer
+├─types # Interface declarations
+│ └─libvap # so file interface declarations
+└─util # Implementation of utility classes
+```
+
+## Source code download
+1. This project relies on json library, which is introduced by `git submodule`, and `--recursive` parameter should be added when downloading code.
+```shell
+git clone --recursive https://gitcode.com/openharmony-tpc/openharmony_tpc_samples.git
+```
+2. Start compiling the project.
+
+## Quick Start
+1. For API mode, refer to the example code [API Mode](./示例代码.ets)
+2. For component mode, refer to the example code [Component Mode](./组件模式.ets), for easier use.
+
+### Importing Header Files
+
+Import header files in the usage file.
+
+```typescript
+import { VAPPlayer,MixData } from '@ohos/vap';
+```
+
+### Define VAPPlayer Component
+
+```typescript
+private vapPlayer: VAPPlayer | undefined = undefined;
+@State buttonEnabled: boolean = true; // This state controls whether the button can be clicked
+@State src: string = "/storage/Users/currentUser/Documents/1.mp4"; // This path can be a network path
+```
+
+### Configure Network Resource Download Path
+```typescript
+// For specific usage, refer to the example code
+// Get sandbox path
+let context : Context = getContext(this) as Context
+let dir = context.filesDir
+```
+
+### Interface
+
+```typescript
+private xComponentId: string = 'xcomponentId_' + util.generateRandomUUID()
+XComponent({
+ id: this.xComponentId, // Unique identifier
+ type: 'surface',
+ libraryname: 'vap'
+})
+ .onLoad((xComponentContext?: object | Record void>) => {
+ if (xComponentContext) {
+ this.vapPlayer = new VAPPlayer(this.xComponentId)
+ this.vapPlayer.setContext(xComponentContext)
+ this.vapPlayer.sandDir = dir // Set storage path
+ }
+ })
+ .backgroundColor(Color.Transparent)
+ .height('100%')
+ .visibility(this.buttonEnabled ? Visibility.Hidden: Visibility.Visible)
+ .width('80%')
+```
+
+### Set Video Alignment Mode
+
+ Set the video alignment mode through the `setFitType` interface (supports FIT_XY, FIT_CENTER, CENTER_CROP)
+
+
+ **This interface needs to be used before `play`.**
+
+```typescript
+this.vapPlayer?.setFitType(fitType)
+```
+
+### Usage
+
+#### Using the Play Interface
+Customizing the order of merged animation information requires specifying `tag`, which is the information specified during video creation, accessible via `this.vapPlayer.getVideoInfo(uri)`.
+When the merged information is text, you can configure the text alignment, color, and size.
+```typescript
+let opts: Array = [{
+ tag: 'sImg1',
+ imgUri: getContext(this).filesDir + '/head1.png'
+}, {
+ tag: 'abc',
+ txt: "星河Harmony NEXT",
+ imgUri: getContext(this).filesDir + '/head1.png'
+}, {
+ tag: 'sTxt1',
+ txt: "星河Harmony NEXT",
+ textAlign: this.textAlign,
+ fontWeight: this.fontWeight,
+ color: this.color
+}];
+this.buttonEnabled = false;
+
+this.vapPlayer?.play(getContext(this).filesDir + "/vapx.mp4", opts, () => {
+ this.buttonEnabled = true;
+});
+```
+
+#### Using Pause
+
+```typescript
+this.vapPlayer?.pause()
+```
+
+#### Using Stop
+
+```typescript
+this.vapPlayer?.stop()
+```
+
+#### Listening for Gestures
+
+- During animation playback, if the clickable area is tapped and a merged animation resource is clicked, a callback will return that resource (string).
+- **This interface needs to be used before `play`.**
+```typescript
+this.vapPlayer?.on('click', (state)=>{
+ if(state) {
+ console.log('js get onClick: ' + state)
+ }
+})
+```
+
+#### Listening for Playback Lifecycle Changes
+**This interface needs to be used before `play`.**
+```typescript
+this.vapPlayer?.on('stateChange', (state, ret)=>{
+ if(state) {
+ console.log('js get on: ' + state)
+ if(ret)
+ console.log('js get on frame: ' + JSON.stringify(ret))
+ }
+})
+```
+
+- Callback parameter `state` reflects the current playback status.
+```typescript
+enum VapState {
+ UNKNOWN,
+ READY,
+ START,
+ RENDER,
+ COMPLETE,
+ DESTROY,
+ FAILED
+}
+```
+- Parameter `ret`, when `state` is `RENDER` or `START`, returns the `AnimConfig` object.
+- Parameter `ret`, when `state` is `FAILED`, reflects the current error code.
+- Parameter `ret`, other statuses will be `undefined`.
+
+#### Application Exit Background
+
+```typescript
+ onPageHide(): void {
+ console.log('[LIFECYCLE-Page] onPageHide');
+ this.vapPlayer?.stop()
+ }
+```
+You can call the `onPageHide` method in the page lifecycle.
+
+#### Compatibility Mode for Legacy Videos (alphaplayer symmetrical videos)
+```typescript
+this.vapPlayer?.setVideoMode(VideoMode.VIDEO_MODE_SPLIT_HORIZONTAL)
+```
+For older videos, it is recommended to call this interface. **This interface needs to be used before `play`.**
+
+### **Constraints and Limitations**
+Passes in the following versions:
+- DevEco Studio 5.0(5.0.3.810), SDK: API12(5.0.0.60)
+
+### **Permissions Setup**
+
+* **No configuration required if the video file is confirmed to be in the sandbox.**
+* Add permissions in the application module's `module.json5`, for example: `entry\src\main\module.json5`
+* `READ_MEDIA` to read files in the user's directory (like documents); `WRITE_MEDIA` (to download to the user's directory); `INTERNET` to download network files.
+
+```json
+"requestPermissions": [
+{
+"name": 'ohos.permission.READ_MEDIA',
+"reason": '$string:read_file',
+"usedScene": {
+"abilities": [
+"EntryAbility"
+],
+"when": "always"
+}
+},
+{
+"name": 'ohos.permission.WRITE_MEDIA',
+"reason": '$string:read_file',
+"usedScene": {
+"abilities": [
+"EntryAbility"
+],
+"when": "always"
+}
+},
+{
+"name": "ohos.permission.INTERNET"
+}
+]
+```
+
+## Compile Build
+
+- After creating the project successfully, to build run `Build -> Build Hap(s)/APP(s) -> build App(s) ` option.
+- The `/entry/build/default/outputs` will generate a `hap` package.
+- Sign and install the generated `hap` package.
+
+## Test Demo
+
+Click the `Play` button to test animation effects, and click again to enter loop playback.
diff --git a/ohos/vap/README_zh.md b/ohos/vap/README_zh.md
new file mode 100644
index 00000000..3b3c89e1
--- /dev/null
+++ b/ohos/vap/README_zh.md
@@ -0,0 +1,270 @@
+
+ OHOS-VAP
+
+
+
+ English | 简体中文
+
+
+
+
+
+
+
+
+在数字娱乐和在线互动的时代,视觉效果的精美程度直接影响用户体验。`OHOS-VAP` 是一个基于 `OpenHarmony` 运用 `OpenGL` 技术和特殊算法打造的强大动画粒子特效渲染组件。它不仅能够为应用程序提供令人惊叹的动画效果,更为用户创造了一种身临其境的视觉享受。
+
+
+
+## 主要特征
+
+- 相比Webp, Apng动图方案,具有高压缩率(素材更小)、硬件解码(解码更快)的优点.
+- 相比Lottie,能实现更复杂的动画效果(比如粒子特效)
+- 高性能渲染:凭借 OpenGL 的强大能力,OHOS-VAP 实现了高效的粒子特效渲染,确保流畅的用户体验,适用于各种设备。
+- 易于集成:OHOS-VAP 设计简洁,易于与现有项目集成,帮助开发者快速实现酷炫的动画效果,提升应用的吸引力。
+- 多平台支持:兼容多个设备,无论是手机、平板还是电脑,OHOS-VAP 都能提供一致的视觉效果,助力跨终端应用开发。
+
+## 应用场景
+
+- 直播间特效:在各大短视频平台中如抖音,快手,得物,企鹅电竞,利用 OHOS-VAP 为直播间增添炫酷的礼物特效,提升观众的互动体验,增加直播的趣味性。
+- 电商活动推广:在游戏领域及电商平台的活动中,使用 OHOS-VAP 实现令人惊叹的产品展示效果,吸引用户眼球,推动销售转化。
+- 游戏体验提升:为游戏场景增添粒子特效,提升整体游戏体验,让玩家沉浸在更为生动的虚拟世界中。
+ 
+
+## 构建依赖
+
+- IDE版本:DevEco Studio 5.0.1.403
+- SDK版本:ohos_sdk_public 5.0.0 (API Version 12 Release)
+- 对于开发人员可以调用`this.xComponentContext.play()`接口来实现自定义视频传参路径(支持网路URL)
+
+### C/C++层目录结构
+
+```
+├─include # 遮罩 融合 渲染器 工具类头文件存放
+│ ├─mask
+│ ├─mix
+│ ├─render
+│ └─util
+├─manager # xcomponent 生命周期管理
+├─mask # 遮罩的实现
+├─mix # 融合实现
+├─napi # Napi 层功能的封装
+├─render # 渲染器的实现
+├─types # 接口声明
+│ └─libvap # so文件接口声明
+└─util # 工具类的实现0
+```
+## 源码下载
+1. 本项目依赖 json 库,通过`git submodule`引入,下载代码时需加上`--recursive`参数。
+```shell
+git clone --recursive https://gitcode.com/openharmony-tpc/openharmony_tpc_samples.git
+```
+2. 开始编译项目。
+
+## 快速使用
+1. api模式 可参考示例代码 [api模式](./示例代码.ets)
+2. 组件模式 可参考示例代码 [组件模式](./组件模式.ets),使用更便捷
+
+
+### 头文件引入
+
+在使用文件中进行头文件的引入
+
+```typescript
+import { VAPPlayer,MixData } from '@ohos/vap';
+```
+
+### 定义 VAPPlayer 组件
+
+```typescript
+private vapPlayer: VAPPlayer | undefined = undefined;
+@State buttonEnabled: boolean = true; // 该状态为控制按钮是否可以点击
+@State src: string = "/storage/Users/currentUser/Documents/1.mp4"; // 该路径可为网络路径
+```
+
+### 配置网络资源下载路径
+```typescript
+// 具体使用可参考示例代码
+// 获取沙箱路径
+let context : Context = getContext(this) as Context
+let dir = context.filesDir
+```
+### 界面
+
+```typescript
+private xComponentId: string = 'xcomponentId_' + util.generateRandomUUID()
+XComponent({
+ id: this.xComponentId, // 唯一标识
+ type: 'surface',
+ libraryname: 'vap'
+})
+ .onLoad((xComponentContext?: object | Record void>) => {
+ if (xComponentContext) {
+ this.vapPlayer = new VAPPlayer(this.xComponentId)
+ this.vapPlayer.setContext(xComponentContext)
+ this.vapPlayer.sandDir = dir // 设置存储路径
+ }
+ })
+ .backgroundColor(Color.Transparent)
+ .height('100%')
+ .visibility(this.buttonEnabled ? Visibility.Hidden: Visibility.Visible)
+ .width('80%')
+```
+### 设置视频对齐方式
+
+ 通过`setFitType`这个接口设置视频对齐方式(支持FIT_XY,FIT_CENTER,CENTER_CROP)
+
+
+ **接口需要在`play`之前使用**
+
+```typescript
+this.vapPlayer?.setFitType(fitType)
+```
+
+### 使用
+
+#### 播放接口 Play 的使用
+融合动画信息顺序自定义,需要指定 `tag`, `tag` 为视频制作时指定,该信息可通过`this.vapPlayer.getVideoInfo(uri)`
+当融合信息为字体时,可配置字体的对齐,颜色,大小
+```typescript
+let opts: Array = [{
+ tag: 'sImg1',
+ imgUri: getContext(this).filesDir + '/head1.png'
+}, {
+ tag: 'abc',
+ txt: "星河Harmony NEXT",
+ imgUri: getContext(this).filesDir + '/head1.png'
+}, {
+ tag: 'sTxt1',
+ txt: "星河Harmony NEXT",
+ textAlign: this.textAlign,
+ fontWeight: this.fontWeight,
+ color: this.color
+}];
+this.buttonEnabled = false;
+
+this.vapPlayer?.play(getContext(this).filesDir + "/vapx.mp4", opts, () => {
+ this.buttonEnabled = true;
+});
+```
+
+#### 暂停的使用
+
+```typescript
+this.vapPlayer?.pause()
+```
+
+#### 停止的使用
+
+```typescript
+this.vapPlayer?.stop()
+```
+
+#### 监听手势
+
+- 在动画播放过程中点击播放区域,如果点击到融合动画资源,回调会返回该资源(字符串)
+- **接口需要在`play`之前使用**
+```typescript
+this.vapPlayer?.on('click', (state)=>{
+ if(state) {
+ console.log('js get onClick: ' + state)
+ }
+})
+```
+
+#### 监听播放生命周期变化
+**接口需要在`play`之前使用**
+```typescript
+this.vapPlayer?.on('stateChange', (state, ret)=>{
+ if(state) {
+ console.log('js get on: ' + state)
+ if(ret)
+ console.log('js get on frame: ' + JSON.stringify(ret))
+ }
+})
+```
+
+- 回调参数 `state` 反应当前播放的状态
+```typescript
+enum VapState {
+ UNKNOWN,
+ READY,
+ START,
+ RENDER,
+ COMPLETE,
+ DESTROY,
+ FAILED
+}
+```
+- 参数 `ret` ,当 `state` 为 `RENDER` 或 `START` 返回 `AnimConfig` 对象
+- 参数 `ret` ,当 `state` 为 `FAILED` 反应当前的错误码
+- 参数 `ret` ,其余状态为 `undefined`
+
+#### 应用退出后台
+
+```typescript
+ onPageHide(): void {
+ console.log('[LIFECYCLE-Page] onPageHide');
+ this.vapPlayer?.stop()
+ }
+```
+可在页面的生命周期中调用`onPageHide`方法
+
+#### 兼容老视频(alphaplayer 对称的视频)
+```typescript
+this.vapPlayer?.setVideoMode(VideoMode.VIDEO_MODE_SPLIT_HORIZONTAL)
+```
+对于老视频推荐调用这个接口,**接口需要在`play`之前使用**
+
+### **约束与限制**
+在下述版本通过
+- DevEco Studio 5.0(5.0.3.810), SDK: API12(5.0.0.60)
+
+### **权限设置**
+
+* **如果确定视频文件在沙箱中则不必配置**
+* 在应用模块的`module.json5`中添加权限, 例如:`entry\src\main\module.json5`
+* `READ_MEDIA` 读取用户目录下的文件(比如 文档); `WRITE_MEDIA`(下载到用户目录下);`INTERNET` 下载网络文件
+
+```json
+"requestPermissions": [
+{
+"name": 'ohos.permission.READ_MEDIA',
+"reason": '$string:read_file',
+"usedScene": {
+"abilities": [
+"EntryAbility"
+],
+"when": "always"
+}
+},
+{
+"name": 'ohos.permission.WRITE_MEDIA',
+"reason": '$string:read_file',
+"usedScene": {
+"abilities": [
+"EntryAbility"
+],
+"when": "always"
+}
+},
+{
+"name": "ohos.permission.INTERNET"
+}
+]
+```
+
+## 编译构建
+
+- 工程创建成功后,构建请运行 `Build -> Build Hap(s)/APP(s) -> build App(s) `选项
+- `/entry/build/default/outputs` 生成 `hap` 包
+- 签名安装生成的 `hap` 包
+
+## 测试demo
+
+点击 `Play` 按钮,测试动画效果,再次点击进入循环播放
diff --git a/ohos/vap/build-profile.json5 b/ohos/vap/build-profile.json5
new file mode 100644
index 00000000..102fb2f8
--- /dev/null
+++ b/ohos/vap/build-profile.json5
@@ -0,0 +1,36 @@
+{
+ "app": {
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compileSdkVersion": 12,
+ "compatibleSdkVersion": 12,
+ "runtimeOS": "OpenHarmony"
+ }
+ ],
+ "buildModeSet": [
+ {
+ "name": "release"
+ }
+ ],
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "vap_module",
+ "srcPath": "./vap_module",
+ }
+ ]
+}
diff --git a/ohos/vap/entry/.gitignore b/ohos/vap/entry/.gitignore
new file mode 100644
index 00000000..e2713a27
--- /dev/null
+++ b/ohos/vap/entry/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/ohos/vap/entry/build-profile.json5 b/ohos/vap/entry/build-profile.json5
new file mode 100644
index 00000000..c92f15c3
--- /dev/null
+++ b/ohos/vap/entry/build-profile.json5
@@ -0,0 +1,14 @@
+
+{
+ "apiType" : "stageMode",
+ "buildOption" : {
+ },
+ "targets" : [
+ {
+ "name" : "default"
+ },
+ {
+ "name" : "ohosTest"
+ }
+ ]
+}
diff --git a/ohos/vap/entry/hvigorfile.ts b/ohos/vap/entry/hvigorfile.ts
new file mode 100644
index 00000000..c6edcd90
--- /dev/null
+++ b/ohos/vap/entry/hvigorfile.ts
@@ -0,0 +1,6 @@
+import { hapTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/ohos/vap/entry/obfuscation-rules.txt b/ohos/vap/entry/obfuscation-rules.txt
new file mode 100644
index 00000000..985b2aeb
--- /dev/null
+++ b/ohos/vap/entry/obfuscation-rules.txt
@@ -0,0 +1,18 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
\ No newline at end of file
diff --git a/ohos/vap/entry/oh-package-lock.json5 b/ohos/vap/entry/oh-package-lock.json5
new file mode 100644
index 00000000..232f58dc
--- /dev/null
+++ b/ohos/vap/entry/oh-package-lock.json5
@@ -0,0 +1,18 @@
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {
+ "@ohos/vap@../vap_module": "@ohos/vap@../vap_module"
+ },
+ "packages": {
+ "@ohos/vap@../vap_module": {
+ "name": "@ohos/vap",
+ "version": "1.1.3",
+ "resolved": "../vap_module",
+ "registryType": "local"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/oh-package.json5 b/ohos/vap/entry/oh-package.json5
new file mode 100644
index 00000000..51143c7f
--- /dev/null
+++ b/ohos/vap/entry/oh-package.json5
@@ -0,0 +1,17 @@
+{
+ "license": "Apache-2.0",
+ "devDependencies": {},
+ "author": "",
+ "name": "entry",
+ "ohos": {
+ "org": "huawei",
+ "directoryLevel": "module",
+ "buildTool": "hvigor"
+ },
+ "description": "example description",
+ "main": "",
+ "version": "1.1.3",
+ "dependencies": {
+ "@ohos/vap": "file:../vap_module"
+ }
+}
diff --git a/ohos/vap/entry/src/main/ets/common/FileUtil.ts b/ohos/vap/entry/src/main/ets/common/FileUtil.ts
new file mode 100644
index 00000000..45a15bb1
--- /dev/null
+++ b/ohos/vap/entry/src/main/ets/common/FileUtil.ts
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 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 { BusinessError } from '@kit.BasicServicesKit';
+import common from '@ohos.app.ability.common'
+
+import fs from '@ohos.file.fs';
+import { http } from '@kit.NetworkKit';
+
+export class FileUtil {
+
+ copyRawfileToContext(context:common.UIAbilityContext) {
+ let filePath = context.filesDir;
+ try {
+ context.resourceManager.getRawFileList("").then((value: Array) => {
+ value.forEach(fileName => {
+ let fileContent: ArrayBufferLike = context.resourceManager.getRawFileContentSync(fileName).buffer;
+ let newFile = fs.openSync(filePath + "/" + fileName, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+ fs.writeSync(newFile.fd, fileContent);
+ fs.close(newFile);
+ });
+
+ }).catch((error: BusinessError) => {
+ console.error(`promise getRawFileList failed, error code: ${error.code}, message: ${error.message}.`);
+ });
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ console.error(`promise getRawFileList failed, error code: ${code}, message: ${message}.`);
+ }
+ }
+
+ async downloadFile(url:string,context:common.UIAbilityContext): Promise{
+ const fileName = this.extractFileName(url);
+ let filePath = context.filesDir+"/" + fileName
+ let res = fs.accessSync(filePath);
+ if (res) {
+ return filePath;
+ }
+ let httpRequest = http.createHttp();
+ try {
+ let data = await httpRequest.request(url, {
+ method: http.RequestMethod.GET,
+ expectDataType: http.HttpDataType.ARRAY_BUFFER,
+ })
+ let buf:ArrayBuffer = data.result as ArrayBuffer;
+ let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+ fs.writeSync(file.fd, buf);
+ fs.closeSync(file);
+ } catch (err) {
+ console.error("accessSync failed with error message: " + err.message + ", error code: " + err.code);
+ filePath = ''
+ } finally {
+ httpRequest.destroy();
+ }
+ return filePath
+ }
+
+ extractFileName(url: string): string {
+ const matches = url.match(/\/([^\/?#]+)[^\/]*$/);
+ if (matches && matches.length > 1) {
+ return matches[1];
+ }
+ return '';
+ }
+
+}
+
+
diff --git a/ohos/vap/entry/src/main/ets/common/LogUtil.ets b/ohos/vap/entry/src/main/ets/common/LogUtil.ets
new file mode 100644
index 00000000..8eefae7b
--- /dev/null
+++ b/ohos/vap/entry/src/main/ets/common/LogUtil.ets
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export class LogUtil {
+ public static OFF: number = 1
+ public static LOG: number = 2
+ public static DEBUG: number = 3
+ public static INFO: number = 4
+ public static WARN: number = 5
+ public static ERROR: number = 6
+ public static ALL: number = 7
+ public static mLogLevel:number = LogUtil.ALL;
+
+ public static debug(message: string, ...args: Object[]) {
+ if (LogUtil.mLogLevel >= LogUtil.DEBUG) {
+ console.debug(message, args)
+ }
+ }
+
+ public static info(message: string, ...args: Object[]) {
+ if (LogUtil.mLogLevel >= LogUtil.INFO) {
+ console.info(message, args)
+ }
+ }
+
+ public static log(message: string, ...args: Object[]) {
+ if (LogUtil.mLogLevel >= LogUtil.LOG) {
+ console.log(message, args)
+ }
+ }
+
+ public static warn(message: string, ...args: Object[]) {
+ if (LogUtil.mLogLevel >= LogUtil.WARN) {
+ console.warn(message, args)
+ }
+ }
+
+ // error 不做拦截
+ public static error(message: string, ...args: Object[]) {
+ if(LogUtil.mLogLevel >= LogUtil.ERROR) {
+ console.error(message, args)
+ }
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/ets/entryability/EntryAbility.ts b/ohos/vap/entry/src/main/ets/entryability/EntryAbility.ts
new file mode 100644
index 00000000..9b1ae7d6
--- /dev/null
+++ b/ohos/vap/entry/src/main/ets/entryability/EntryAbility.ts
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+import UIAbility from '@ohos.app.ability.UIAbility';
+import window from '@ohos.window';
+import hilog from '@ohos.hilog';
+import nativerender from 'libvap.so';
+import { FileUtil } from '../common/FileUtil'
+export enum ContextType {
+ APP_LIFECYCLE,
+ PAGE_LIFECYCLE,
+}
+
+const nativeAppLifecycle = nativerender.getContext(ContextType.APP_LIFECYCLE as any);
+
+export default class EntryAbility extends UIAbility {
+ onCreate(want, launchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+ nativeAppLifecycle.onCreate();
+ globalThis.abilityWant = want;
+ let fileUtil = new FileUtil();
+ fileUtil.copyRawfileToContext(this.context);
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
+ nativeAppLifecycle.onDestroy();
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ // Main window is created, set main page for this ability
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
+ nativeAppLifecycle.onShow();
+ windowStage.loadContent('pages/Index', (err, data) => {
+ 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. Data: %{public}s', JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ // Main window is destroyed, release UI related resources
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
+ nativeAppLifecycle.onHide();
+ }
+
+ onForeground() {
+ // Ability has brought to foreground
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
+ }
+
+ onBackground() {
+ // Ability has back to background
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
+ }
+};
diff --git a/ohos/vap/entry/src/main/ets/pages/GeneralAnimation.ets b/ohos/vap/entry/src/main/ets/pages/GeneralAnimation.ets
new file mode 100644
index 00000000..de083cdc
--- /dev/null
+++ b/ohos/vap/entry/src/main/ets/pages/GeneralAnimation.ets
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { DownloadData, VAPPlayer } from '@ohos/vap';
+import { systemDateTime } from '@kit.BasicServicesKit';
+import { LogUtil } from '../common/LogUtil';
+import { util } from '@kit.ArkTS';
+import { VAPComponent, FitType, MixData, VideoMode } from '@ohos/vap';
+
+@Entry
+@Component
+struct GeneralAnimation {
+ private vapPlayer: VAPPlayer | undefined = undefined;
+ @State buttonEnabled: boolean = true;
+ @State fitType: FitType = FitType.FIT_CENTER;
+ private playTimes: number = 0;
+ private stopTimes: number = 0;
+ private pauseTimes: number = 0;
+ private xComponentId: string = 'xcomponentId_' + util.generateRandomUUID();
+
+ aboutToDisappear(): void {
+ LogUtil.info('aboutToDisappear')
+ this.vapPlayer?.stop()
+ }
+
+ onPageShow(): void {
+ LogUtil.info('onPageShow')
+ }
+
+ onPageHide(): void {
+ LogUtil.info('onPageHide')
+ this.vapPlayer?.stop()
+ }
+
+ play() {
+ if (this.vapPlayer === undefined) {
+ LogUtil.error('plz create XComponent first')
+ return
+ }
+ this.vapPlayer?.setFitType(this.fitType)
+ this.vapPlayer?.setVideoMode(VideoMode.VIDEO_MODE_SPLIT_HORIZONTAL)
+ try {
+ let opts: Array = new Array();
+ this.buttonEnabled = false;
+
+ this.vapPlayer?.setDownloadAttribute(50000, (data: DownloadData) => {
+ console.log(`download progress: ${JSON.stringify(data)}`);
+ });
+
+ let startTime = systemDateTime.getTime(true)
+
+ this.vapPlayer?.setLoop(3); // 动画循环播放3次
+ this.vapPlayer?.play(getContext(this).filesDir + "/great_gift.mp4", opts, () => {
+ LogUtil.info("js get callback")
+ this.buttonEnabled = true;
+ });
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(this.playTimes + " play cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(this.playTimes + " play error " + JSON.stringify(e));
+ }
+ this.playTimes++;
+ }
+
+ pause() {
+ try {
+ let startTime = systemDateTime.getTime(true);
+ this.vapPlayer?.pause();
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(this.pauseTimes + " pause cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(this.pauseTimes + " pause error " + JSON.stringify(e));
+ }
+ this.pauseTimes++;
+ }
+
+ stop() {
+ try {
+ let startTime = systemDateTime.getTime(true);
+ this.vapPlayer?.stop();
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(this.stopTimes + " stop cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(this.stopTimes + " stop error " + JSON.stringify(e));
+ }
+ this.stopTimes++;
+ }
+
+ build() {
+ Column() {
+ Stack() {
+ XComponent({
+ id: this.xComponentId,
+ type: 'surface',
+ libraryname: 'vap'
+ })
+ .onLoad((context?: object) => {
+ if (context) {
+ this.vapPlayer = new VAPPlayer(this.xComponentId);
+ this.vapPlayer.setContext(context);
+ }
+ })
+ .backgroundColor(Color.Transparent)
+ .width('100%')
+ .height('100%')
+ .visibility(this.buttonEnabled ? Visibility.Hidden : Visibility.Visible)
+ }.backgroundImage($r('app.media.bg'))
+ .backgroundImageSize(ImageSize.FILL)
+ .height('90%')
+ .width('100%')
+
+ Scroll() {
+ Row() {
+ Select([{ value: 'fix_xy' }, { value: 'fix_center' }, { value: 'center_crop' }])
+ .selected(1)
+ .value('fix_center')
+ .onSelect((index: number) => {
+ console.info('Select: ' + index)
+ this.fitType = index
+ })
+ Button('Play')
+ .fontWeight(500)
+ .onClick(() => {
+ this.play()
+ })
+ .width('200')
+ .enabled(this.buttonEnabled)
+ Button('pause')
+ .onClick(() => {
+ this.pause()
+ })
+ Button('stop')
+ .onClick(() => {
+ this.stop()
+ })
+ }
+ }
+ .width('100%')
+ .scrollable(ScrollDirection.Horizontal)
+ .padding({ bottom: 10 })
+ .margin({ left: 5, right: 5 })
+ .border({
+ color: Color.Grey,
+ style: BorderStyle.Solid,
+ radius: 5,
+ width: 2
+ })
+ .backgroundColor(Color.White)
+ }
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/ets/pages/Index.ets b/ohos/vap/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 00000000..8192de94
--- /dev/null
+++ b/ohos/vap/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import router from '@ohos.router';
+
+@Entry
+@Component
+struct Index{
+ build() {
+ Scroll() {
+ Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
+ Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
+ Button("测试普通动画")
+ .onClick(() => {
+ router.pushUrl({ url: "pages/GeneralAnimation" });
+ }).margin({ top: 15 })
+ }.width('100%').height(60)
+
+ Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
+ Button("测试融合动画")
+ .onClick(() => {
+ router.pushUrl({ url: "pages/VAPXAnimation" });
+ }).margin({ top: 15 })
+ }.width('100%').height(60)
+
+ Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
+ Button("测试新监听")
+ .onClick(() => {
+ router.pushUrl({ url: "pages/NewOn" });
+ }).margin({ top: 15 })
+ }.width('100%').height(60)
+ }.backgroundColor(Color.Pink)
+ .margin(10)
+ .padding(20)
+ .borderRadius(10)
+ }
+ .width('100%')
+ .height('100%')
+ }
+}
diff --git a/ohos/vap/entry/src/main/ets/pages/NewOn.ets b/ohos/vap/entry/src/main/ets/pages/NewOn.ets
new file mode 100644
index 00000000..4520a3a8
--- /dev/null
+++ b/ohos/vap/entry/src/main/ets/pages/NewOn.ets
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { VAPPlayer, VapState } from '@ohos/vap';
+import { systemDateTime } from '@kit.BasicServicesKit';
+import { LogUtil } from '../common/LogUtil';
+import { util } from '@kit.ArkTS';
+import { FitType, MixData, VideoMode } from '@ohos/vap';
+import { router } from '@kit.ArkUI';
+
+// 场景: 应用开屏效果, 可点击跳过
+@Entry
+@Component
+struct GeneralAnimation {
+ private vapPlayer: VAPPlayer | undefined = undefined;
+ @State showVideo: boolean = true;
+ @State fitType: FitType = FitType.CENTER_CROP;
+ private videoName: string = "demo.mp4";
+ private xComponentId: string = 'xComponentId_xx';
+
+ aboutToDisappear(): void {
+ LogUtil.info('aboutToDisappear')
+ }
+
+ onPageShow(): void {
+ LogUtil.info('onPageShow')
+ }
+
+ onPageHide(): void {
+ LogUtil.info('onPageHide')
+ this.vapPlayer?.stop()
+ }
+
+ on() {
+ this.vapPlayer?.on('stateChange', (state, ret) => {
+ LogUtil.info(`vapPlayer on state: ${state}`)
+ if (state === VapState.COMPLETE) {
+ LogUtil.info(`vapPlayer play complete: ${state}`)
+ }
+ if (state === VapState.FAILED && ret) {
+ LogUtil.error(`vapPlayer error: ${JSON.stringify(ret)}`)
+ }
+ if (state === VapState.DESTROY) {
+ this.vapPlayer = undefined
+ this.showVideo = false;
+ LogUtil.info(`vapPlayer DESTROY: ${state}`)
+ }
+ })
+ }
+
+ play() {
+ if (this.vapPlayer === undefined) {
+ LogUtil.error('plz create XComponent first')
+ return
+ }
+
+ this.on();
+
+ this.vapPlayer?.setFitType(this.fitType)
+ this.vapPlayer?.setVideoMode(VideoMode.VIDEO_MODE_SPLIT_HORIZONTAL)
+ try {
+ let opts: Array = [];
+
+ let startTime = systemDateTime.getTime(true)
+
+ this.vapPlayer?.play(getContext(this).filesDir + "/" + this.videoName, opts, () => {
+ LogUtil.info("js get callback")
+ this.showVideo = false
+ });
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(" play cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(" play error " + JSON.stringify(e));
+ }
+ }
+
+ pause() {
+ try {
+ let startTime = systemDateTime.getTime(true);
+ this.vapPlayer?.pause();
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(" pause cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(" pause error " + JSON.stringify(e));
+ }
+ }
+
+ stop() {
+ try {
+ let startTime = systemDateTime.getTime(true);
+ this.vapPlayer?.stop();
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info("stop cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error("stop error " + JSON.stringify(e));
+ }
+ }
+
+ build() {
+ Column() {
+ Stack() {
+ if (!this.showVideo) {
+ Column() {
+ Button("返回")
+ .onClick(() => {
+ router.back()
+ })
+ Text("进入主页")
+ Text("占位文本")
+ .width('100%')
+ .textAlign(TextAlign.Center)
+ .border({ width: 1 })
+ .padding(10)
+ .fontColor(Color.Blue)
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
+ }
+ .width('100%')
+ .height('100%')
+ } else {
+ XComponent({
+ id: this.xComponentId,
+ type: 'surface',
+ libraryname: 'vap'
+ })
+ .onLoad((context?: object) => {
+ if (context) {
+ this.vapPlayer = new VAPPlayer(this.xComponentId);
+ this.vapPlayer.setContext(context);
+ }
+ this.play()
+ })
+ .backgroundColor(Color.Transparent)
+ .width('100%')
+ .height('100%')
+
+ Button('Skip')
+ .fontWeight(500)
+ .onClick(() => {
+ this.stop()
+ this.showVideo = false
+ this.vapPlayer = undefined //必须,建议使用之前的visibility控制显示 容器都没了,还能调用方法!!!
+ })
+ .borderRadius(4)
+ .height(40)
+ .width(200)
+ }
+ }.backgroundImage($r('app.media.bg'))
+ .backgroundImageSize(ImageSize.FILL)
+ .height('100%')
+ .width('100%')
+ }
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/ets/pages/VAPXAnimation.ets b/ohos/vap/entry/src/main/ets/pages/VAPXAnimation.ets
new file mode 100644
index 00000000..34b4d025
--- /dev/null
+++ b/ohos/vap/entry/src/main/ets/pages/VAPXAnimation.ets
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { MixData, VAPPlayer, VAPColor } from '@ohos/vap';
+import { systemDateTime } from '@kit.BasicServicesKit';
+import { LogUtil } from '../common/LogUtil';
+import { util } from '@kit.ArkTS';
+import { FitType } from '@ohos/vap';
+import { VAPFontWeight } from '@ohos/vap';
+import { VAPTextAlign } from '@ohos/vap';
+import { SrcInfo, SrcType } from '@ohos/vap';
+import text from '@ohos.graphics.text';
+
+class ColorBean implements VAPColor {
+ a: number = 255;
+ r: number = 2;
+ g: number = 255;
+ b: number = 187
+}
+
+@Entry
+@Component
+struct VAPXAnimation {
+ private vapPlayer: VAPPlayer | undefined = undefined;
+ @State buttonEnabled: boolean = true;
+ @State fitType: FitType = FitType.FIT_CENTER;
+ @State textAlign: VAPTextAlign = VAPTextAlign.TEXT_ALIGN_LEFT;
+ @State fontWeight: VAPFontWeight = VAPFontWeight.NORMAL;
+ @State color: ColorBean = new ColorBean;
+ @State showColor: number = 0;
+ private srcInfo: SrcInfo[] | undefined = undefined
+ private playTimes: number = 0;
+ private stopTimes: number = 0;
+ private pauseTimes: number = 0;
+ private colorIdx: number = 0;
+ private xComponentId: string = 'xcomponentId_' + util.generateRandomUUID()
+ private videoPath: string = getContext(this).filesDir + "/123.mp4";
+
+ @Styles tipTxt() {
+ .backgroundColor('#fff')
+ .foregroundColor('#000')
+ }
+ aboutToDisappear(): void {
+ LogUtil.info('aboutToDisappear')
+ this.vapPlayer?.stop()
+ }
+
+ onPageShow(): void {
+ LogUtil.info('onPageShow')
+ this.showColor = (((this.color.r & 0xff) << 16) | ((this.color.g & 0xff) << 8) | ((this.color.b & 0xff)))
+ }
+
+ onPageHide(): void {
+ LogUtil.info('onPageHide')
+ this.vapPlayer?.stop()
+ }
+
+ play() {
+ if (this.vapPlayer === undefined) {
+ LogUtil.error('plz create XComponent first')
+ return
+ }
+ this.vapPlayer?.setFitType(this.fitType)
+ try {
+ if (this.srcInfo) {
+ let mixData: Array = []
+ this.srcInfo.map((ele, idx) => {
+ if (ele.type == SrcType.IMG) {
+ mixData.push({ tag: ele.tag, imgUri: '图片地址' })
+ } else if (ele.type == SrcType.TXT) {
+ mixData.push({ tag: ele.tag, txt: '文本信息', color: this.color })
+ }
+ })
+ console.log('config mixData: ' + JSON.stringify(mixData))
+ } else {
+ console.log('error not get srcInfo')
+ }
+
+ let opts: Array = [];
+ if (this.srcInfo != undefined) {
+ for (let s of this.srcInfo) {
+ if (s.type == SrcType.IMG) {
+ opts.push({
+ tag: s.tag,
+ imgUri: getContext(this).filesDir + '/head1.png'
+ })
+ } else if (s.type == SrcType.TXT) {
+ opts.push({
+ tag: s.tag,
+ txt: "星河Harmony NEXT 星河Harmony NEXT",
+ textAlign: this.textAlign, // VAPTextAlign.TEXT_ALIGN_JUSTIFY对齐方式规格见 https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-text-V5#textalign
+ fontWeight: this.fontWeight,
+ color: this.color
+ })
+ }
+ }
+ }
+ this.buttonEnabled = false;
+
+ let startTime = systemDateTime.getTime(true)
+
+ this.vapPlayer?.play(this.videoPath, opts, () => {
+ LogUtil.info("js get callback")
+ this.buttonEnabled = true;
+ });
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(this.playTimes + " play cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(this.playTimes + " play error " + JSON.stringify(e));
+ }
+ this.playTimes++;
+ }
+
+ pause() {
+ try {
+ let startTime = systemDateTime.getTime(true);
+ this.vapPlayer?.pause();
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(this.pauseTimes + " pause cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(this.pauseTimes + " pause error " + JSON.stringify(e));
+ }
+ this.pauseTimes++;
+ }
+
+ stop() {
+ try {
+ let startTime = systemDateTime.getTime(true);
+ this.vapPlayer?.stop();
+ let endTime = systemDateTime.getTime(true)
+ LogUtil.info(this.stopTimes + " stop cost " + (endTime - startTime) / 1000)
+ } catch (e) {
+ LogUtil.error(this.stopTimes + " stop error " + JSON.stringify(e));
+ }
+ this.stopTimes++;
+ }
+
+ build() {
+ Column() {
+ Stack() {
+ XComponent({
+ id: this.xComponentId,
+ type: 'surface',
+ libraryname: 'vap'
+ })
+ .onLoad((context?: object) => {
+ if (context) {
+ this.vapPlayer = new VAPPlayer(this.xComponentId);
+ this.vapPlayer.setContext(context);
+ let info = this.vapPlayer.getVideoInfo(this.videoPath)
+ console.log('getVideoInfo info ' + JSON.stringify(info))
+ this.srcInfo = info?.srcInfos
+ }
+ })
+ .backgroundColor(Color.Transparent)
+ .width('100%')
+ .height('100%')
+ .visibility(this.buttonEnabled ? Visibility.Hidden : Visibility.Visible)
+
+ Scroll() {
+ Row({ space: 10 }) {
+ Text('色彩分量:').fontWeight(FontWeight.Bold)
+ Select([{ value: 'red' }, { value: 'green' }, { value: 'blue' }])
+ .selected(0)
+ .value('red')
+ .onSelect((index: number) => {
+ this.colorIdx = index
+ })
+ TextInput()
+ .type(InputType.Number)
+ .width(80)
+ .maxLength(3)
+ .onChange((value: string) => {
+ if (this.colorIdx == 0) {
+ this.color.r = Number(value) & 0xff
+ } else if (this.colorIdx == 1) {
+ this.color.g = Number(value) & 0xff
+ } else if (this.colorIdx == 2) {
+ this.color.b = Number(value) & 0xff
+ }
+ this.showColor =
+ (((this.color.r & 0xff) << 16) | ((this.color.g & 0xff) << 8) | ((this.color.b & 0xff)))
+ })
+ Text('当前色彩:').tipTxt().fontWeight(FontWeight.Bold)
+ Text().width(20).height(20).backgroundColor(this.showColor)
+
+ Text('视频对齐:').fontWeight(FontWeight.Bold)
+ Select([{ value: 'fix_xy' }, { value: 'fix_center' }, { value: 'center_crop' }])
+ .selected(1)
+ .value('fix_center')
+ .onSelect((index: number) => {
+ this.fitType = index
+ })
+ Text('字体权重:').fontWeight(FontWeight.Bold)
+ Select([{ value: 'thin' }, { value: 'extra_light' }, { value: 'light' }, { value: 'normal' },
+ { value: 'medium' }, { value: 'semi_bold' },
+ { value: 'bold' }, { value: 'extra_bold' }, { value: 'black' }])
+ .selected(3)
+ .value('normal')
+ .onSelect((index: number) => {
+ this.fontWeight = index
+ })
+ Text('字体对齐:').fontWeight(FontWeight.Bold)
+ Select([{ value: 'left' }, { value: 'right' }, { value: 'center' }, { value: 'justify' },
+ { value: 'start' }, { value: 'end' }])
+ .selected(0)
+ .value('left')
+ .onSelect((index: number) => {
+ this.textAlign = index
+ })
+ }
+ }
+ .width('100%')
+ .scrollable(ScrollDirection.Horizontal)
+ .padding({ bottom: 10 })
+ .margin({ left: 5, right: 5 })
+ .border({
+ color: Color.Grey,
+ style: BorderStyle.Solid,
+ radius: 5,
+ width: 2
+ })
+ .backgroundColor(Color.White)
+ .opacity(0.6)
+ }
+ .backgroundImage($r('app.media.bg'))
+ .backgroundImageSize(ImageSize.FILL)
+ .height('93%')
+ .width('100%')
+ .alignContent(Alignment.Bottom)
+
+ Row() {
+ Button('Play')
+ .fontWeight(500)
+ .onClick(() => {
+ this.play()
+ })
+ .width('200')
+ .enabled(this.buttonEnabled)
+ Button('pause')
+ .onClick(() => {
+ this.pause()
+ })
+ Button('stop')
+ .onClick(() => {
+ this.stop()
+ })
+ }
+ .margin({ top: 15 })
+ .width('100%')
+ .justifyContent(FlexAlign.SpaceAround)
+ .alignItems(VerticalAlign.Bottom)
+ }
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/module.json5 b/ohos/vap/entry/src/main/module.json5
new file mode 100644
index 00000000..1e2746b4
--- /dev/null
+++ b/ohos/vap/entry/src/main/module.json5
@@ -0,0 +1,62 @@
+{
+ "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.ts",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:startIcon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "requestPermissions": [
+ {
+ "name": 'ohos.permission.READ_MEDIA',
+ "reason": '$string:read_file',
+ "usedScene": {
+ "abilities": [
+ "EntryAbility"
+ ],
+ "when": "always"
+ }
+ },
+ {
+ "name": 'ohos.permission.WRITE_MEDIA',
+ "reason": '$string:read_file',
+ "usedScene": {
+ "abilities": [
+ "EntryAbility"
+ ],
+ "when": "always"
+ }
+ },
+ {
+ "name": "ohos.permission.INTERNET"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/resources/base/element/color.json b/ohos/vap/entry/src/main/resources/base/element/color.json
new file mode 100644
index 00000000..ee559ba3
--- /dev/null
+++ b/ohos/vap/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,12 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ },
+ {
+ "name": "first",
+ "value": "#92D6CC"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/resources/base/element/float.json b/ohos/vap/entry/src/main/resources/base/element/float.json
new file mode 100644
index 00000000..80919a95
--- /dev/null
+++ b/ohos/vap/entry/src/main/resources/base/element/float.json
@@ -0,0 +1,48 @@
+{
+ "float": [
+ {
+ "name": "title_text_font_size",
+ "value": "24fp"
+ },
+ {
+ "name": "title_text_margin_left",
+ "value": "24vp"
+ },
+ {
+ "name": "title_text_margin_top",
+ "value": "12vp"
+ },
+ {
+ "name": "title_margin_top",
+ "value": "24vp"
+ },
+ {
+ "name": "title_height",
+ "value": "56vp"
+ },
+ {
+ "name": "xcomponent_margin_top",
+ "value": "27vp"
+ },
+ {
+ "name": "xcomponent_margin_left",
+ "value": "12vp"
+ },
+ {
+ "name": "xcomponent_margin_right",
+ "value": "12vp"
+ },
+ {
+ "name": "button_font_size",
+ "value": "16fp"
+ },
+ {
+ "name": "button_margin_bottom",
+ "value": "24vp"
+ },
+ {
+ "name": "button_height",
+ "value": "40vp"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/resources/base/element/string.json b/ohos/vap/entry/src/main/resources/base/element/string.json
new file mode 100644
index 00000000..9e41f7c4
--- /dev/null
+++ b/ohos/vap/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,28 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "XComponent"
+ },
+ {
+ "name": "title",
+ "value": "Render Example"
+ },
+ {
+ "name": "button_text",
+ "value": "LoadYUV"
+ },
+ {
+ "name": "read_file",
+ "value": "文件读取"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/resources/base/media/bg.png b/ohos/vap/entry/src/main/resources/base/media/bg.png
new file mode 100644
index 00000000..9172073c
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/base/media/bg.png differ
diff --git a/ohos/vap/entry/src/main/resources/base/media/coollb.png b/ohos/vap/entry/src/main/resources/base/media/coollb.png
new file mode 100644
index 00000000..bc9db6fd
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/base/media/coollb.png differ
diff --git a/ohos/vap/entry/src/main/resources/base/media/icon.png b/ohos/vap/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 00000000..ce307a88
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/base/media/icon.png differ
diff --git a/ohos/vap/entry/src/main/resources/base/media/startIcon.png b/ohos/vap/entry/src/main/resources/base/media/startIcon.png
new file mode 100644
index 00000000..95b3d6ba
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/base/media/startIcon.png differ
diff --git a/ohos/vap/entry/src/main/resources/base/profile/main_pages.json b/ohos/vap/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 00000000..f7d3db49
--- /dev/null
+++ b/ohos/vap/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,8 @@
+{
+ "src": [
+ "pages/Index",
+ "pages/GeneralAnimation",
+ "pages/VAPXAnimation",
+ "pages/NewOn"
+ ]
+}
diff --git a/ohos/vap/entry/src/main/resources/en_US/element/string.json b/ohos/vap/entry/src/main/resources/en_US/element/string.json
new file mode 100644
index 00000000..f9459551
--- /dev/null
+++ b/ohos/vap/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": "label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/main/resources/rawfile/123.mp4 b/ohos/vap/entry/src/main/resources/rawfile/123.mp4
new file mode 100644
index 00000000..5d9affc3
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/rawfile/123.mp4 differ
diff --git a/ohos/vap/entry/src/main/resources/rawfile/demo.mp4 b/ohos/vap/entry/src/main/resources/rawfile/demo.mp4
new file mode 100644
index 00000000..3c12bf31
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/rawfile/demo.mp4 differ
diff --git a/ohos/vap/entry/src/main/resources/rawfile/great_gift.mp4 b/ohos/vap/entry/src/main/resources/rawfile/great_gift.mp4
new file mode 100644
index 00000000..bbbcf0e9
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/rawfile/great_gift.mp4 differ
diff --git a/ohos/vap/entry/src/main/resources/rawfile/head1.png b/ohos/vap/entry/src/main/resources/rawfile/head1.png
new file mode 100644
index 00000000..1b24cebf
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/rawfile/head1.png differ
diff --git a/ohos/vap/entry/src/main/resources/rawfile/vapx.mp4 b/ohos/vap/entry/src/main/resources/rawfile/vapx.mp4
new file mode 100644
index 00000000..76f39230
Binary files /dev/null and b/ohos/vap/entry/src/main/resources/rawfile/vapx.mp4 differ
diff --git a/ohos/vap/entry/src/main/resources/zh_CN/element/string.json b/ohos/vap/entry/src/main/resources/zh_CN/element/string.json
new file mode 100644
index 00000000..12e8fdb2
--- /dev/null
+++ b/ohos/vap/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": "vap"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/ohosTest/ets/test/Ability.test.ets b/ohos/vap/entry/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 00000000..91689f8e
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import hilog from '@ohos.hilog';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
+
+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, () => {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
+ 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/ohos/vap/entry/src/ohosTest/ets/test/List.test.ets b/ohos/vap/entry/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 00000000..4ef6a155
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import abilityTest from './Ability.test';
+
+export default function testsuite() {
+ abilityTest();
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/ohosTest/ets/testability/TestAbility.ets b/ohos/vap/entry/src/ohosTest/ets/testability/TestAbility.ets
new file mode 100644
index 00000000..3df3b195
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/ets/testability/TestAbility.ets
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import UIAbility from '@ohos.app.ability.UIAbility';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+import hilog from '@ohos.hilog';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+import window from '@ohos.window';
+import Want from '@ohos.app.ability.Want';
+import AbilityConstant from '@ohos.app.ability.AbilityConstant';
+
+export default class TestAbility extends UIAbility {
+ onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
+ let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator;
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
+ let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs;
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments();
+ hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
+ windowStage.loadContent('testability/pages/Index', (err, data) => {
+ 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. Data: %{public}s',
+ JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
+ }
+
+ onForeground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
+ }
+
+ onBackground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/ohosTest/ets/testability/pages/Index.ets b/ohos/vap/entry/src/ohosTest/ets/testability/pages/Index.ets
new file mode 100644
index 00000000..cb16c9a2
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/ets/testability/pages/Index.ets
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@Entry
+@Component
+struct Index {
+ @State message: string = 'Hello World';
+
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(50)
+ .fontWeight(FontWeight.Bold)
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets b/ohos/vap/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets
new file mode 100644
index 00000000..7ffc8507
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import hilog from '@ohos.hilog';
+import TestRunner from '@ohos.application.testRunner';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+import Want from '@ohos.app.ability.Want';
+
+let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator | undefined = undefined
+let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs | undefined = undefined
+
+async function onAbilityCreateCallback() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
+}
+
+async function addAbilityMonitorCallback(err : Error) {
+ hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
+}
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
+ }
+
+ async onRun() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
+ const bundleName = abilityDelegatorArguments.bundleName;
+ const testAbilityName = 'TestAbility';
+ let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
+ abilityName: testAbilityName,
+ onAbilityCreate: onAbilityCreateCallback,
+ };
+ abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
+ const want: Want = {
+ bundleName: bundleName,
+ abilityName: testAbilityName
+ };
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
+ abilityDelegator.startAbility(want, (err, data) => {
+ hilog.info(0x0000, 'testTag', 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
+ hilog.info(0x0000, 'testTag', 'startAbility : data : %{public}s',JSON.stringify(data) ?? '');
+ })
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/ohosTest/module.json5 b/ohos/vap/entry/src/ohosTest/module.json5
new file mode 100644
index 00000000..4fc97017
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/module.json5
@@ -0,0 +1,37 @@
+{
+ "module": {
+ "name": "entry_test",
+ "type": "feature",
+ "description": "$string:module_test_desc",
+ "mainElement": "TestAbility",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:test_pages",
+ "abilities": [
+ {
+ "name": "TestAbility",
+ "srcEntry": "./ets/testability/TestAbility.ets",
+ "description": "$string:TestAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:TestAbility_label",
+ "exported": true,
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "skills": [
+ {
+ "actions": [
+ "action.system.home"
+ ],
+ "entities": [
+ "entity.system.home"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/ohos/vap/entry/src/ohosTest/resources/base/element/color.json b/ohos/vap/entry/src/ohosTest/resources/base/element/color.json
new file mode 100644
index 00000000..3c712962
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/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/ohos/vap/entry/src/ohosTest/resources/base/element/string.json b/ohos/vap/entry/src/ohosTest/resources/base/element/string.json
new file mode 100644
index 00000000..65d8fa5a
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_test_desc",
+ "value": "test ability description"
+ },
+ {
+ "name": "TestAbility_desc",
+ "value": "the test ability"
+ },
+ {
+ "name": "TestAbility_label",
+ "value": "test label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/ohosTest/resources/base/media/icon.png b/ohos/vap/entry/src/ohosTest/resources/base/media/icon.png
new file mode 100644
index 00000000..ce307a88
Binary files /dev/null and b/ohos/vap/entry/src/ohosTest/resources/base/media/icon.png differ
diff --git a/ohos/vap/entry/src/ohosTest/resources/base/profile/test_pages.json b/ohos/vap/entry/src/ohosTest/resources/base/profile/test_pages.json
new file mode 100644
index 00000000..b7e7343c
--- /dev/null
+++ b/ohos/vap/entry/src/ohosTest/resources/base/profile/test_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "testability/pages/Index"
+ ]
+}
diff --git a/ohos/vap/entry/src/test/List.test.ets b/ohos/vap/entry/src/test/List.test.ets
new file mode 100644
index 00000000..acfaf9f4
--- /dev/null
+++ b/ohos/vap/entry/src/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import localUnitTest from './LocalUnit.test';
+
+export default function testsuite() {
+ localUnitTest();
+}
\ No newline at end of file
diff --git a/ohos/vap/entry/src/test/LocalUnit.test.ets b/ohos/vap/entry/src/test/LocalUnit.test.ets
new file mode 100644
index 00000000..91906500
--- /dev/null
+++ b/ohos/vap/entry/src/test/LocalUnit.test.ets
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { 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/ohos/vap/hvigor/hvigor-config.json5 b/ohos/vap/hvigor/hvigor-config.json5
new file mode 100644
index 00000000..73bfab4e
--- /dev/null
+++ b/ohos/vap/hvigor/hvigor-config.json5
@@ -0,0 +1,17 @@
+{
+ "modelVersion": "5.0.0",
+ "dependencies": {
+ },
+ "execution": {
+ // "daemon": true, /* Enable daemon compilation. Default: true */
+ // "incremental": true, /* Enable incremental compilation. Default: true */
+ // "parallel": true, /* Enable parallel compilation. Default: true */
+ // "typeCheck": false, /* Enable typeCheck. Default: false */
+ },
+ "logging": {
+ // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
+ },
+ "debugging": {
+ // "stacktrace": false /* Disable stacktrace compilation. Default: false */
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/hvigorfile.ts b/ohos/vap/hvigorfile.ts
new file mode 100644
index 00000000..f3cb9f1a
--- /dev/null
+++ b/ohos/vap/hvigorfile.ts
@@ -0,0 +1,6 @@
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/ohos/vap/imgs/1.gif b/ohos/vap/imgs/1.gif
new file mode 100644
index 00000000..f522d74d
Binary files /dev/null and b/ohos/vap/imgs/1.gif differ
diff --git a/ohos/vap/imgs/2.gif b/ohos/vap/imgs/2.gif
new file mode 100644
index 00000000..a0009190
Binary files /dev/null and b/ohos/vap/imgs/2.gif differ
diff --git a/ohos/vap/imgs/4.gif b/ohos/vap/imgs/4.gif
new file mode 100644
index 00000000..2f4c61ce
Binary files /dev/null and b/ohos/vap/imgs/4.gif differ
diff --git a/ohos/vap/imgs/5.gif b/ohos/vap/imgs/5.gif
new file mode 100644
index 00000000..ddbe60dd
Binary files /dev/null and b/ohos/vap/imgs/5.gif differ
diff --git a/ohos/vap/imgs/crop.png b/ohos/vap/imgs/crop.png
new file mode 100644
index 00000000..bd7abbbc
Binary files /dev/null and b/ohos/vap/imgs/crop.png differ
diff --git a/ohos/vap/imgs/icon.png b/ohos/vap/imgs/icon.png
new file mode 100644
index 00000000..c8748024
Binary files /dev/null and b/ohos/vap/imgs/icon.png differ
diff --git a/ohos/vap/oh-package-lock.json5 b/ohos/vap/oh-package-lock.json5
new file mode 100644
index 00000000..f538ae29
--- /dev/null
+++ b/ohos/vap/oh-package-lock.json5
@@ -0,0 +1,19 @@
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {
+ "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19"
+ },
+ "packages": {
+ "@ohos/hypium@1.0.19": {
+ "name": "@ohos/hypium",
+ "version": "1.0.19",
+ "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==",
+ "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har",
+ "registryType": "ohpm"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ohos/vap/oh-package.json5 b/ohos/vap/oh-package.json5
new file mode 100644
index 00000000..eb97424f
--- /dev/null
+++ b/ohos/vap/oh-package.json5
@@ -0,0 +1,9 @@
+{
+ "modelVersion": "5.0.0",
+ "description": "Please describe the basic information.",
+ "dependencies": {},
+ "devDependencies": {
+ "@ohos/hypium": "1.0.19"
+ },
+ "dynamicDependencies": {}
+}
\ No newline at end of file
diff --git a/ohos/vap/vap_module/.gitignore b/ohos/vap/vap_module/.gitignore
new file mode 100644
index 00000000..e2713a27
--- /dev/null
+++ b/ohos/vap/vap_module/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/ohos/vap/vap_module/BuildProfile.ets b/ohos/vap/vap_module/BuildProfile.ets
new file mode 100644
index 00000000..82dffd72
--- /dev/null
+++ b/ohos/vap/vap_module/BuildProfile.ets
@@ -0,0 +1,17 @@
+/**
+ * Use these variables when you tailor your ArkTS code. They must be of the const type.
+ */
+export const HAR_VERSION = '1.1.3';
+export const BUILD_MODE_NAME = 'debug';
+export const DEBUG = true;
+export const TARGET_NAME = 'default';
+
+/**
+ * BuildProfile Class is used only for compatibility purposes.
+ */
+export default class BuildProfile {
+ static readonly HAR_VERSION = HAR_VERSION;
+ static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
+ static readonly DEBUG = DEBUG;
+ static readonly TARGET_NAME = TARGET_NAME;
+}
\ No newline at end of file
diff --git a/ohos/vap/vap_module/CHANGELOG.md b/ohos/vap/vap_module/CHANGELOG.md
new file mode 100644
index 00000000..10934597
--- /dev/null
+++ b/ohos/vap/vap_module/CHANGELOG.md
@@ -0,0 +1,34 @@
+# 版本记录
+
+## 1.1.3
+
+---
+
+1. Fix loop bug.
+
+## 1.1.2
+
+---
+
+1. Fix the memory leak.
+
+## 1.1.1
+
+---
+
+1. 增强vap视频融合的通用性以及填充模式
+2. 同步上游社区代码,修复在快速创建销毁xcomponent组件时出现的crash问题
+
+## 1.1.0
+
+---
+
+1. 兼容部分MP4文件
+2. 优化监听逻辑
+3. 修复特定场景下的闪退
+
+## 1.0.0 初版
+
+---
+
+1. 发布1.0.0初版
\ No newline at end of file
diff --git a/ohos/vap/vap_module/Index.ets b/ohos/vap/vap_module/Index.ets
new file mode 100644
index 00000000..286f8c16
--- /dev/null
+++ b/ohos/vap/vap_module/Index.ets
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './src/main/ets/VAPPlayer'
+export * from './src/main/ets/Index'
+export * from './src/main/ets/DataDeclare'
diff --git a/ohos/vap/vap_module/LICENSE b/ohos/vap/vap_module/LICENSE
new file mode 100644
index 00000000..f433b1a5
--- /dev/null
+++ b/ohos/vap/vap_module/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/ohos/vap/vap_module/README.md b/ohos/vap/vap_module/README.md
new file mode 100644
index 00000000..63ab1c94
--- /dev/null
+++ b/ohos/vap/vap_module/README.md
@@ -0,0 +1,224 @@
+# OHOS-VAP
+
+---
+
+## 简介
+
+---
+
+腾讯vap的OpenHarmony版本,提供高性能,炫酷视频动画播放
+
+## 下载安装
+
+```bash
+ohpm install @ohos/vap
+```
+
+## 接口
+
+---
+| 接口 | 功能 |
+|--------------|---------------|
+| play | 播放 |
+| pause | 暂停 |
+| stop | 停止 |
+| on | 监听生命周期/手势 |
+| setFitType | 设置视频对齐方式 |
+| setVideoMode | 设置视频格式(兼容老视频) |
+| getVideoInfo | 获取融合动画配置信息 |
+ 详细使用可参考 [demo工程](https://gitcode.com/openharmony-tpc/openharmony_tpc_samples/tree/master/vap)
+
+## 使用
+
+---
+
+### 头文件引入
+
+在应用文件中添加头文件
+
+```typescript
+import { VAPPlayer,MixData } from '@ohos/vap';
+```
+
+### 定义 VAPPlayer 组件
+
+```typescript
+private vapPlayer: VAPPlayer | undefined = undefined;
+@State buttonEnabled: boolean = true; // 该状态为控制按钮是否可以点击
+@State src: string = "/storage/Users/currentUser/Documents/1.mp4"; // 该路径可为网络路径
+```
+
+### 配置网络资源下载路径
+```typescript
+// 具体使用可参考示例代码
+// 获取沙箱路径
+let context : Context = getContext(this) as Context
+let dir = context.filesDir
+```
+### 界面
+
+```typescript
+XComponent({
+ id: 'xcomponentId', // 唯一标识
+ type: 'surface',
+ libraryname: 'vap'
+})
+ .onLoad((xComponentContext?: object | Record void>) => {
+ if (xComponentContext) {
+ this.vapPlayer = new VAPPlayer
+ this.vapPlayer.setContext(xComponentContext)
+ this.vapPlayer.sandDir = dir // 设置存储路径
+ }
+ })
+ .backgroundColor(Color.Transparent)
+ .height('100%')
+ .visibility(this.buttonEnabled ? Visibility.Hidden: Visibility.Visible)
+ .width('80%')
+```
+### 设置视频对齐方式
+
+ 通过`setFitType`这个接口设置视频对齐方式(支持FIT_XY,FIT_CENTER,CENTER_CROP)
+
+ **接口需要在`play`之前使用**
+
+```typescript
+this.vapPlayer?.setFitType(fitType)
+```
+
+### 使用
+
+#### 播放接口 Play 的使用
+融合动画信息顺序自定义,需要指定 `tag`, `tag` 为视频制作时指定,该信息可通过`this.vapPlayer.getVideoInfo(uri)`
+当融合信息为字体时,可配置字体的对齐,颜色,大小
+```typescript
+let opts: Array = [{
+ tag: 'sImg1',
+ imgUri: getContext(this).filesDir + '/head1.png'
+}, {
+ tag: 'abc',
+ txt: "星河Harmony NEXT",
+ imgUri: getContext(this).filesDir + '/head1.png'
+}, {
+ tag: 'sTxt1',
+ txt: "星河Harmony NEXT",
+ textAlign: this.textAlign,
+ fontWeight: this.fontWeight,
+ color: this.color
+}];
+this.buttonEnabled = false;
+
+this.vapPlayer?.play(getContext(this).filesDir + "/vapx.mp4", opts, () => {
+ this.buttonEnabled = true;
+});
+```
+
+#### 暂停的使用
+
+```typescript
+this.vapPlayer?.pause()
+```
+
+#### 停止的使用
+
+```typescript
+this.vapPlayer?.stop()
+```
+
+#### 监听手势
+
+- 在动画播放过程中点击播放区域,如果点击到融合动画资源,回调会返回该资源(字符串)
+- **接口需要在`play`之前使用**
+```typescript
+this.vapPlayer?.on('click', (state)=>{
+ if(state) {
+ console.log('js get onClick: ' + state)
+ }
+})
+```
+
+#### 监听播放生命周期变化
+**接口需要在`play`之前使用**
+```typescript
+this.vapPlayer?.on('stateChange', (state, ret)=>{
+ if(state) {
+ console.log('js get on: ' + state)
+ if(ret)
+ console.log('js get on frame: ' + JSON.stringify(ret))
+ }
+})
+```
+
+- 回调参数 `state` 反应当前播放的状态
+```typescript
+enum VapState {
+ UNKNOWN,
+ READY,
+ START,
+ RENDER,
+ COMPLETE,
+ DESTROY,
+ FAILED
+}
+```
+- 参数 `ret` ,当 `state` 为 `RENDER` 或 `START` 返回 `AnimConfig` 对象
+- 参数 `ret` ,当 `state` 为 `FAILED` 反应当前的错误码
+- 参数 `ret` ,其余状态为 `undefined`
+
+#### 应用退出后台
+
+```typescript
+ onPageHide(): void {
+ console.log('[LIFECYCLE-Page] onPageHide');
+ this.vapPlayer?.stop()
+ }
+```
+可在页面的生命周期中调用`onPageHide`方法
+
+## 兼容老视频(alphaplayer 对称的视频)
+```typescript
+this.vapPlayer?.setVideoMode(VideoMode.VIDEO_MODE_SPLIT_HORIZONTAL)
+```
+对于老视频推荐调用这个接口,**接口需要在`play`之前使用**
+
+## 约束与限制
+
+---
+
+在下述版本通过
+- DevEco Studio 5.0(5.0.3.810), SDK: API12(5.0.0.60)
+
+## 权限设置
+
+---
+
+* **如果确定视频文件在沙箱中则不必配置**
+* 在应用模块的`module.json5`中添加权限, 例如:`entry\src\main\module.json5`
+* `READ_MEDIA` 读取用户目录下的文件(比如 文档); `WRITE_MEDIA`(下载到用户目录下);`INTERNET` 下载网络文件
+
+```json
+"requestPermissions": [
+{
+"name": 'ohos.permission.READ_MEDIA',
+"reason": '$string:read_file',
+"usedScene": {
+"abilities": [
+"EntryAbility"
+],
+"when": "always"
+}
+},
+{
+"name": 'ohos.permission.WRITE_MEDIA',
+"reason": '$string:read_file',
+"usedScene": {
+"abilities": [
+"EntryAbility"
+],
+"when": "always"
+}
+},
+{
+"name": "ohos.permission.INTERNET"
+}
+]
+```
diff --git a/ohos/vap/vap_module/build-profile.json5 b/ohos/vap/vap_module/build-profile.json5
new file mode 100644
index 00000000..4dfd923f
--- /dev/null
+++ b/ohos/vap/vap_module/build-profile.json5
@@ -0,0 +1,22 @@
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ "externalNativeOptions": {
+ "path": "./src/main/cpp/CMakeLists.txt",
+ "arguments": "-DCMAKE_BUILD_TYPE='Release'",
+ "abiFilters": [
+ "arm64-v8a",
+ "x86_64",
+ ],
+ "cppFlags": ""
+ },
+ },
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest"
+ }
+ ]
+}
diff --git a/ohos/vap/vap_module/consumer-rules.txt b/ohos/vap/vap_module/consumer-rules.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/ohos/vap/vap_module/hvigorfile.ts b/ohos/vap/vap_module/hvigorfile.ts
new file mode 100644
index 00000000..42187071
--- /dev/null
+++ b/ohos/vap/vap_module/hvigorfile.ts
@@ -0,0 +1,6 @@
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/ohos/vap/vap_module/obfuscation-rules.txt b/ohos/vap/vap_module/obfuscation-rules.txt
new file mode 100644
index 00000000..69c4d6a8
--- /dev/null
+++ b/ohos/vap/vap_module/obfuscation-rules.txt
@@ -0,0 +1,18 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
\ No newline at end of file
diff --git a/ohos/vap/vap_module/oh-package-lock.json5 b/ohos/vap/vap_module/oh-package-lock.json5
new file mode 100644
index 00000000..22f9d347
--- /dev/null
+++ b/ohos/vap/vap_module/oh-package-lock.json5
@@ -0,0 +1,9 @@
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {},
+ "packages": {}
+}
\ No newline at end of file
diff --git a/ohos/vap/vap_module/oh-package.json5 b/ohos/vap/vap_module/oh-package.json5
new file mode 100644
index 00000000..63fc4179
--- /dev/null
+++ b/ohos/vap/vap_module/oh-package.json5
@@ -0,0 +1,10 @@
+{
+ "name": "@ohos/vap",
+ "version": "1.1.3",
+ "description": "A cool video animation playback solution.",
+ "main": "Index.ets",
+ "author": "ohos_tpc",
+ "license": "Apache-2.0",
+ "repository": "https://gitcode.com/openharmony-tpc/openharmony_tpc_samples/tree/master/vap",
+ "dependencies": {}
+}
\ No newline at end of file
diff --git a/ohos/vap/vap_module/src/main/cpp/CMakeLists.txt b/ohos/vap/vap_module/src/main/cpp/CMakeLists.txt
new file mode 100644
index 00000000..102596c0
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,70 @@
+# the minimum version of CMake.
+cmake_minimum_required(VERSION 3.4.1)
+project(XComponent)
+
+set(CMAKE_CXX_STANDARD 17)
+set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+add_definitions(-DOHOS_PLATFORM)
+
+include_directories(
+ ${NATIVERENDER_ROOT_PATH}
+ ${NATIVERENDER_ROOT_PATH}/include
+ ${NATIVERENDER_ROOT_PATH}/include/util
+ ${NATIVERENDER_ROOT_PATH}/include/render
+ ${NATIVERENDER_ROOT_PATH}/include/mask
+ ${NATIVERENDER_ROOT_PATH}/include/mix
+ ${NATIVERENDER_ROOT_PATH}/include/napi
+ ${NATIVERENDER_ROOT_PATH}/include/util/json/include
+)
+
+add_library(vap SHARED
+ manager/plugin_manager.cpp
+ mask/mask_config.cpp
+ mask/mask_render.cpp
+ mask/mask_shader.cpp
+ mix/frame.cpp
+ mix/mix_render.cpp
+ mix/mix_shader.cpp
+ mix/src.cpp
+ napi/n_val.cpp
+ napi/n_func_arg.cpp
+ render/egl_core.cpp
+ render/plugin_render.cpp
+ render/yuv_render.cpp
+ render/anim_config.cpp
+ util/shader_util.cpp
+ util/tex_coords_util.cpp
+ util/vertex_util.cpp
+ util/texture_load_util.cpp
+ napi_init.cpp
+ video_decoder.cpp
+ demuxer.cpp
+ player.cpp
+ audio_decoder.cpp
+ resource_request.cpp
+ vap_callback.cpp
+)
+target_compile_definitions(vap PUBLIC -DNAPI_VERSION=16)
+target_link_libraries(vap PUBLIC EGL)
+target_link_libraries(vap PUBLIC GLESv3)
+target_link_libraries(vap PUBLIC hilog_ndk.z)
+target_link_libraries(vap PUBLIC ace_ndk.z)
+target_link_libraries(vap PUBLIC ace_napi.z)
+target_link_libraries(vap PUBLIC libc++.a)
+target_link_libraries(vap PUBLIC z)
+target_link_libraries(vap PUBLIC uv)
+target_link_libraries(vap PUBLIC libace_napi.z.so)
+target_link_libraries(vap PUBLIC libnative_media_codecbase.so)
+target_link_libraries(vap PUBLIC libnative_media_core.so)
+target_link_libraries(vap PUBLIC libnative_media_vdec.so)
+target_link_libraries(vap PUBLIC libnative_media_adec.so)
+target_link_libraries(vap PUBLIC libnative_media_acodec.so)
+target_link_libraries(vap PUBLIC libnative_media_avsource.so)
+target_link_libraries(vap PUBLIC libnative_media_avdemuxer.so)
+target_link_libraries(vap PUBLIC libavplayer.so)
+target_link_libraries(vap PUBLIC libohaudio.so)
+target_link_libraries(vap PUBLIC libnative_drawing.so)
+target_link_libraries(vap PUBLIC libpixelmap_ndk.z.so)
+target_link_libraries(vap PUBLIC libimage_source.so)
+target_link_libraries(vap PUBLIC libpixelmap.so)
+#target_link_libraries(vap PUBLIC nlohmann_json::nlohmann_json)
\ No newline at end of file
diff --git a/ohos/vap/vap_module/src/main/cpp/audio_decoder.cpp b/ohos/vap/vap_module/src/main/cpp/audio_decoder.cpp
new file mode 100644
index 00000000..acab4277
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/audio_decoder.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "audio_decoder.h"
+
+#include
+#include
+
+#include "log.h"
+
+#undef LOG_TAG
+#define LOG_TAG "AudioDecoder"
+
+namespace {
+void OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
+{
+ (void)codec;
+ (void)errorCode;
+ (void)userData;
+ LOGE("On codec error, error code: %{public}d", errorCode);
+}
+
+void OnCodecFormatChange(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
+{
+ LOGI("On codec format change");
+}
+
+void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
+{
+ if (userData == nullptr) {
+ return;
+ }
+ (void)codec;
+ ADecSignal *m_signal = static_cast(userData);
+ std::unique_lock lock(m_signal->audioInputMutex);
+ m_signal->audioInputBufferInfoQueue.emplace(index, buffer, codec);
+ m_signal->audioInputCond.notify_all();
+}
+
+void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
+{
+ if (userData == nullptr) {
+ return;
+ }
+ (void)codec;
+ ADecSignal *m_signal = static_cast(userData);
+ std::unique_lock lock(m_signal->audioOutputMutex);
+ m_signal->audioOutputBufferInfoQueue.emplace(index, buffer, codec);
+ m_signal->audioOutputCond.notify_all();
+}
+}
+
+AudioDecoder::~AudioDecoder()
+{
+ Release();
+}
+
+int32_t AudioDecoder::CreateAudioDecoder(const std::string &codecMime)
+{
+ decoder_ = OH_AudioCodec_CreateByMime(codecMime.c_str(), false);
+ if (decoder_ == nullptr) {
+ LOGE("create audio decoder_ failed");
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t AudioDecoder::SetCallback(ADecSignal *signal)
+{
+ int32_t ret = AV_ERR_OK;
+ ret = OH_AudioCodec_RegisterCallback(decoder_, {OnCodecError, OnCodecFormatChange,
+ OnNeedInputBuffer, OnNewOutputBuffer}, signal);
+ if (ret != AV_ERR_OK) {
+ LOGE("Set callback failed, ret: %{public}d", ret);
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t AudioDecoder::ConfigureAudioDecoder(const VAPInfo &sampleInfo)
+{
+ OH_AVFormat *format = OH_AVFormat_Create();
+ if (format == nullptr) {
+ LOGE("AVFormat create failed");
+ return AV_ERR_UNKNOWN;
+ }
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, sampleInfo.sampleRate);
+ OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, sampleInfo.audioBitrate);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, sampleInfo.channelCount);
+ if (strcmp(sampleInfo.audioCodecMime.c_str(), "audio/mp4a-latm") == 0) {
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_AAC_IS_ADTS, 1);
+ LOGD("audio mime is aac");
+ } else {
+ LOGD("audio mime is not aac");
+ }
+ LOGD("AudioDecoder config: %{public}d - %{public}ld = %{public}d", sampleInfo.sampleRate,
+ sampleInfo.audioBitrate, sampleInfo.channelCount);
+ int ret = OH_AudioCodec_Configure(decoder_, format);
+ if (ret != AV_ERR_OK) {
+ LOGE("Config failed, ret: %{public}d", ret);
+ return AV_ERR_UNKNOWN;
+ }
+ OH_AVFormat_Destroy(format);
+ format = nullptr;
+
+ return AV_ERR_OK;
+}
+
+int32_t AudioDecoder::Config(const VAPInfo &sampleInfo, ADecSignal *signal)
+{
+ if (decoder_ == nullptr) {
+ LOGE("Decoder is null");
+ return AV_ERR_UNKNOWN;
+ }
+ if (signal == nullptr) {
+ LOGE("Invalid param: codecUserData");
+ return AV_ERR_UNKNOWN;
+ }
+
+ int32_t ret = ConfigureAudioDecoder(sampleInfo);
+ if (ret != AV_ERR_OK) {
+ LOGE("Configure failed");
+ return AV_ERR_UNKNOWN;
+ }
+
+ ret = SetCallback(signal);
+ if (ret != AV_ERR_OK) {
+ LOGE("Set callback failed, ret: %{public}d", ret);
+ return AV_ERR_UNKNOWN;
+ }
+
+ ret = OH_AudioCodec_Prepare(decoder_);
+ if (ret != AV_ERR_OK) {
+ LOGE("audio Prepare failed, ret: %{public}d", ret);
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t AudioDecoder::StartAudioDecoder()
+{
+ if (decoder_ == nullptr) {
+ LOGE("Decoder is null");
+ return AV_ERR_UNKNOWN;
+ }
+
+ int ret = OH_AudioCodec_Start(decoder_);
+ if (ret != AV_ERR_OK) {
+ LOGE("audio Start failed, ret: %{public}d", ret);
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t AudioDecoder::PushInputData(AudioCodecBufferInfo &info)
+{
+ if (decoder_ == nullptr) {
+ LOGE("Decoder is null");
+ return AV_ERR_UNKNOWN;
+ }
+ int32_t ret = OH_AVBuffer_SetBufferAttr(info.bufferOrigin, &info.attr);
+ if (ret != AV_ERR_OK) {
+ LOGE("Set avbuffer attr failed");
+ return AV_ERR_UNKNOWN;
+ }
+ ret = OH_AudioCodec_PushInputBuffer(decoder_, info.bufferIndex);
+ if (ret != AV_ERR_OK) {
+ LOGE("Push input data failed");
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t AudioDecoder::FreeOutputData(uint32_t bufferIndex, bool render)
+{
+ if (decoder_ == nullptr) {
+ LOGE("Decoder is null");
+ return AV_ERR_UNKNOWN;
+ }
+
+ int32_t ret = AV_ERR_OK;
+ ret = OH_AudioCodec_FreeOutputBuffer(decoder_, bufferIndex);
+ if (ret != AV_ERR_OK) {
+ LOGE("audio Free output data failed");
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t AudioDecoder::Release()
+{
+ if (decoder_ != nullptr) {
+ OH_AudioCodec_Flush(decoder_);
+ OH_AudioCodec_Stop(decoder_);
+ OH_AudioCodec_Destroy(decoder_);
+ decoder_ = nullptr;
+ }
+ return AV_ERR_OK;
+}
\ No newline at end of file
diff --git a/ohos/vap/vap_module/src/main/cpp/demuxer.cpp b/ohos/vap/vap_module/src/main/cpp/demuxer.cpp
new file mode 100644
index 00000000..48f232de
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/demuxer.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include "demuxer.h"
+
+Demuxer::~Demuxer()
+{
+ Release();
+}
+
+int32_t Demuxer::CreateDemuxer(VAPInfo &info)
+{
+ source_ = OH_AVSource_CreateWithFD(info.inputFd, info.inputFileOffset, info.inputFileSize);
+ if (source_ == nullptr) {
+ LOGE("create source_ failed");
+ return AV_ERR_UNKNOWN;
+ }
+
+ demuxer_ = OH_AVDemuxer_CreateWithSource(source_);
+ if (demuxer_ == nullptr) {
+ LOGE("create demuxer_ failed");
+ return AV_ERR_UNKNOWN;
+ }
+
+ auto sourceFormat = std::shared_ptr(OH_AVSource_GetSourceFormat(source_), OH_AVFormat_Destroy);
+ if (sourceFormat == nullptr) {
+ LOGE("get source_ format failed");
+ return AV_ERR_UNKNOWN;
+ }
+
+ int32_t ret = GetTrackInfo(sourceFormat, info);
+ if (ret != AV_ERR_OK) {
+ LOGE("get track info failed");
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t Demuxer::GetTrackInfo(std::shared_ptr sourceFormat, VAPInfo &info)
+{
+ int32_t trackCount = 0;
+ OH_AVFormat_GetIntValue(sourceFormat.get(), OH_MD_KEY_TRACK_COUNT, &trackCount);
+ for (int32_t index = 0; index < trackCount; index++) {
+ int trackType = -1;
+ auto trackFormat = std::shared_ptr(OH_AVSource_GetTrackFormat(source_, index),
+ OH_AVFormat_Destroy);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_TRACK_TYPE, &trackType);
+ if (trackType == MEDIA_TYPE_VID) {
+ OH_AVDemuxer_SelectTrackByID(demuxer_, index);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_WIDTH, &info.videoWidth);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_HEIGHT, &info.videoHeight);
+ OH_AVFormat_GetDoubleValue(trackFormat.get(), OH_MD_KEY_FRAME_RATE, &info.frameRate);
+ OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_BITRATE, &info.bitrate);
+ OH_AVFormat_GetIntValue(trackFormat.get(), "video_is_hdr_vivid", &info.isHDRVivid);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_ROTATION, &info.rotation);
+ char *codecMime;
+ OH_AVFormat_GetStringValue(trackFormat.get(), OH_MD_KEY_CODEC_MIME, const_cast(&codecMime));
+ info.codecMime = codecMime;
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_PROFILE, &info.hevcProfile);
+ videoTrackId_ = index;
+
+ LOGI("Demuxer config: %{public}d*%{public}d, %{public}.1ffps, %{public}ld" "kbps",
+ info.videoWidth, info.videoHeight, info.frameRate, info.bitrate / ONE_K);
+ } else if (trackType == MEDIA_TYPE_AUD) {
+ OH_AVDemuxer_SelectTrackByID(demuxer_, index);
+ OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_BITRATE, &info.audioBitrate);
+ OH_AVFormat_GetIntValue(trackFormat.get(),
+ OH_MD_KEY_AUD_SAMPLE_RATE, reinterpret_cast(&info.sampleRate));
+ OH_AVFormat_GetIntValue(trackFormat.get(),
+ OH_MD_KEY_AUD_CHANNEL_COUNT, reinterpret_cast(&info.channelCount));
+
+ char *audioCodecMime;
+ OH_AVFormat_GetStringValue(trackFormat.get(),
+ OH_MD_KEY_CODEC_MIME, const_cast(&audioCodecMime));
+ info.audioCodecMime = audioCodecMime;
+ audioTrackId_ = index;
+
+ LOGI("Audio Demuxer config: %{public}d %{public}d, %{public}ld"
+ "kbps",
+ info.channelCount, info.sampleRate, info.audioBitrate / ONE_K);
+ }
+ }
+ return AV_ERR_OK;
+}
+
+int32_t Demuxer::ReadSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr)
+{
+ int32_t ret = OH_AVDemuxer_ReadSampleBuffer(demuxer_, videoTrackId_, buffer);
+ if (ret != AV_ERR_OK) {
+ LOGE("read sample failed");
+ return AV_ERR_UNKNOWN;
+ }
+
+ ret = OH_AVBuffer_GetBufferAttr(buffer, &attr);
+ if (ret != AV_ERR_OK) {
+ LOGE("get buffer attr failed");
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t Demuxer::ReadAudioSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr)
+{
+ int32_t ret = OH_AVDemuxer_ReadSampleBuffer(demuxer_, audioTrackId_, buffer);
+ if (ret != AV_ERR_OK) {
+ LOGE("read audio sample failed");
+ return AV_ERR_UNKNOWN;
+ }
+
+ ret = OH_AVBuffer_GetBufferAttr(buffer, &attr);
+ if (ret != AV_ERR_OK) {
+ LOGE("get audio buffer attr failed");
+ return AV_ERR_UNKNOWN;
+ }
+ return AV_ERR_OK;
+}
+
+int32_t Demuxer::Release()
+{
+ if (source_ != nullptr) {
+ OH_AVSource_Destroy(source_);
+ source_ = nullptr;
+ }
+ if (demuxer_ != nullptr) {
+ OH_AVDemuxer_Destroy(demuxer_);
+ demuxer_ = nullptr;
+ }
+ return AV_ERR_OK;
+}
diff --git a/ohos/vap/vap_module/src/main/cpp/include/audio_decoder.h b/ohos/vap/vap_module/src/main/cpp/include/audio_decoder.h
new file mode 100644
index 00000000..63b54324
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/audio_decoder.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_AUDIO_DECODER_H
+#define VAP_AUDIO_DECODER_H
+
+#include "multimedia/player_framework/native_avcodec_videodecoder.h"
+#include "multimedia/player_framework/native_avbuffer_info.h"
+#include "data_info.h"
+
+class AudioDecoder {
+public:
+ AudioDecoder() = default;
+ ~AudioDecoder();
+
+ int32_t CreateAudioDecoder(const std::string &codecMime);
+ int32_t ConfigureAudioDecoder(const VAPInfo &sampleInfo);
+ int32_t Config(const VAPInfo &sampleInfo, ADecSignal *signal);
+ int32_t StartAudioDecoder();
+ int32_t PushInputData(AudioCodecBufferInfo &info);
+ int32_t FreeOutputData(uint32_t bufferIndex, bool render);
+ int32_t Release();
+
+private:
+ int32_t SetCallback(ADecSignal *signal);
+
+ bool isAVBufferMode_ = false;
+ OH_AVCodec *decoder_ = nullptr;
+};
+#endif // VAP_AUDIO_DECODER_H
\ No newline at end of file
diff --git a/ohos/vap/vap_module/src/main/cpp/include/common_const.h b/ohos/vap/vap_module/src/main/cpp/include/common_const.h
new file mode 100644
index 00000000..a19a48e5
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/common_const.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMMON_CONST_H
+#define COMMON_CONST_H
+
+#include
+
+namespace CommonConst {
+ static constexpr int32_t ZERO = 0;
+ static constexpr int32_t ONE = 1;
+ static constexpr int32_t TWO = 2;
+ static constexpr int32_t THREE = 3;
+ static constexpr int32_t FOUR = 4;
+ static constexpr int32_t FIVE = 5;
+ static constexpr int32_t SIX = 6;
+ static constexpr int32_t SEVEN = 7;
+ static constexpr int32_t EIGHT = 8;
+
+ static constexpr int32_t THREE_TIME_EIGHT = 24;
+ static constexpr int32_t TWO_TIME_EIGHT = 16;
+
+ static constexpr int32_t NEGATIVE_ONE = -1;
+ static constexpr int32_t NINETY_DEGREES = 90;
+
+ static constexpr int32_t ONE_EIGHT_HEX = 0xff;
+}
+
+#endif
diff --git a/ohos/vap/vap_module/src/main/cpp/include/data_info.h b/ohos/vap/vap_module/src/main/cpp/include/data_info.h
new file mode 100644
index 00000000..70c991cd
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/data_info.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_DATATYPE_INFO_H
+#define VAP_DATATYPE_INFO_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "mix_render.h"
+#include "multimedia/player_framework/native_avcodec_base.h"
+#include "multimedia/player_framework/native_avbuffer.h"
+
+#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 AudioInitData {
+ OH_AudioStream_Type type = AUDIOSTREAM_TYPE_RENDERER;
+ int32_t samplingRate = 48000;
+ int32_t channelCount = 2;
+ OH_AudioStream_SampleFormat format = AUDIOSTREAM_SAMPLE_S16LE;
+ OH_AudioStream_EncodingType encodingType = AUDIOSTREAM_ENCODING_TYPE_RAW;
+ OH_AudioStream_Usage usage = AUDIOSTREAM_USAGE_MUSIC;
+};
+
+struct VAPInfo {
+ 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 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 audioBitrate;
+ uint32_t sampleRate;
+ uint32_t channelCount;
+ std::string audioCodecMime;
+
+ 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; // AV_PIXEL_FORMAT_YUVI420;
+ bool needDumpOutput = false;
+ uint32_t bitrateMode = CBR;
+ int32_t hevcProfile = HEVC_PROFILE_MAIN;
+ int32_t rotation = 0;
+ NativeWindow* window = nullptr;
+
+ uint32_t bufferSize = 0;
+ double readTime = 0;
+ double memcpyTime = 0;
+ double writeTime = 0;
+
+ void (*playDoneCallback)(void *context) = nullptr;
+ void *playDoneCallbackData = nullptr;
+
+ int32_t width;
+ int32_t height;
+ std::string uri;
+ std::map iptData;
+};
+
+struct CodecBufferInfo {
+ uint32_t bufferIndex = 0;
+ uintptr_t *buffer = nullptr;
+ uint8_t *bufferAddr = nullptr;
+ OH_AVCodec *codec = nullptr;
+ OH_AVBuffer *bufferOrigin = 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);
+ };
+
+ CodecBufferInfo(uint32_t argBufferIndex, OH_AVBuffer *argBuffer, OH_AVCodec *argCodec)
+ : bufferIndex(argBufferIndex), bufferOrigin(argBuffer), codec(argCodec)
+ {
+ OH_AVBuffer_GetBufferAttr(argBuffer, &attr);
+ };
+};
+
+struct AudioCodecBufferInfo {
+ uint32_t bufferIndex = 0;
+ uint8_t *bufferAddr = nullptr;
+ OH_AVCodec *codec = nullptr;
+ OH_AVBuffer *bufferOrigin = nullptr;
+ OH_AVCodecBufferAttr attr = {0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE};
+
+ AudioCodecBufferInfo(uint32_t argBufferIndex, OH_AVBuffer *argBuffer, OH_AVCodec *argCodec)
+ : bufferIndex(argBufferIndex), bufferOrigin(argBuffer), codec(argCodec)
+ {
+ OH_AVBuffer_GetBufferAttr(argBuffer, &attr);
+ };
+};
+
+class ADecSignal {
+public:
+ std::mutex audioInputMutex;
+ std::condition_variable audioInputCond;
+ std::queue audioInputBufferInfoQueue;
+ std::mutex audioOutputMutex;
+ std::condition_variable audioOutputCond;
+ std::queue audioOutputBufferInfoQueue;
+ std::mutex renderMutex;
+ std::condition_variable renderCond;
+ std::queue renderQueue;
+ bool isInterrupt = false;
+
+ void ClearQueue()
+ {
+ {
+ std::unique_lock lock(audioInputMutex);
+ auto emptyQueue = std::queue();
+ audioInputBufferInfoQueue.swap(emptyQueue);
+ }
+ {
+ std::unique_lock lock(audioOutputMutex);
+ auto emptyQueue = std::queue();
+ audioOutputBufferInfoQueue.swap(emptyQueue);
+ }
+ }
+};
+
+class VDecSignal {
+public:
+ 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;
+
+ 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);
+ }
+ }
+};
+
+enum VapState {
+ UNKNOWN,
+ READY,
+ START,
+ RENDER,
+ COMPLETE,
+ DESTROY,
+ FAILED
+};
+
+struct JSAnimConfig {
+ int32_t version;
+ int32_t totalFrames;
+ int32_t width;
+ int32_t height;
+ int32_t videoWidth;
+ int32_t videoHeight;
+ Orien orien;
+ int32_t fps;
+ bool isMix;
+ PointRect alphaPointRect;
+ PointRect rgbPointRect;
+ int32_t currentFrame;
+};
+
+enum class VideoFitType {
+ FIT_XY,
+ FIT_CENTER,
+ CENTER_CROP
+};
+
+typedef struct CallbackContext {
+ napi_env env = nullptr;
+ napi_ref callbackRef = nullptr;
+ VapState vapState = VapState::UNKNOWN;
+ int32_t err;
+ JSAnimConfig jsAnimConfig;
+} CallbackContext;
+
+#endif // VAP_DATATYPE_INFO_H
\ No newline at end of file
diff --git a/ohos/vap/vap_module/src/main/cpp/include/demuxer.h b/ohos/vap/vap_module/src/main/cpp/include/demuxer.h
new file mode 100644
index 00000000..e2ef235f
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/demuxer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_DEMUXER_H
+#define VAP_DEMUXER_H
+
+#include
+#include "multimedia/player_framework/native_avdemuxer.h"
+#include "data_info.h"
+
+static constexpr int32_t ONE_K = 1024;
+
+class Demuxer {
+public:
+ ~Demuxer();
+ int32_t CreateDemuxer(VAPInfo &sampleInfo);
+ int32_t GetTrackInfo(std::shared_ptr sourceFormat, VAPInfo &info);
+ int32_t ReadSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr);
+ int32_t ReadAudioSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr);
+ int32_t Release();
+
+ bool hasAudio() { return audioTrackId_ != -1; }
+ bool hasVideo() { return videoTrackId_ != -1; }
+
+private:
+ OH_AVSource *source_ = nullptr;
+ OH_AVDemuxer *demuxer_ = nullptr;
+ int32_t videoTrackId_ = -1;
+ int32_t audioTrackId_ = -1;
+};
+
+#endif // VAP_DEMUXER_H
\ No newline at end of file
diff --git a/ohos/vap/vap_module/src/main/cpp/include/mask/mask_config.h b/ohos/vap/vap_module/src/main/cpp/include/mask/mask_config.h
new file mode 100644
index 00000000..6b512169
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/mask/mask_config.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_MASK_CONFIG_H
+#define VAP_MASK_CONFIG_H
+
+#include
+#include
+
+#include "texture_load_util.h"
+#include "vertex_util.h"
+
+class MaskConfig {
+public:
+ MaskConfig(int32_t width, int32_t height);
+ ~MaskConfig();
+
+ int32_t GetMaskTexId();
+ int32_t UpdateMaskTex(BitMap alphaMaskBitmap);
+
+public:
+ std::tuple maskTexPair_ =
+ std::move(std::make_tuple(PointRect(0, 0, 0, 0), RefVec2(0, 0)));
+
+ std::tuple maskPositionPair_ =
+ std::move(std::make_tuple(PointRect(0, 0, 0, 0), RefVec2(0, 0)));
+
+ int32_t width_; // animConfig width
+ int32_t height_;
+private:
+ GLuint maskTexId_ = 0;
+};
+
+#endif // VAP_MASK_CONFIG_H
diff --git a/ohos/vap/vap_module/src/main/cpp/include/mask/mask_render.h b/ohos/vap/vap_module/src/main/cpp/include/mask/mask_render.h
new file mode 100644
index 00000000..d85c57f8
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/mask/mask_render.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_MASK_RENDER_H
+#define VAP_MASK_RENDER_H
+
+#include "mask_config.h"
+#include "mask_shader.h"
+#include "vertex_util.h"
+
+class MaskRender {
+public:
+ MaskRender(bool edgeBlur);
+ void RenderFrame(MaskConfig maskConfig);
+
+public:
+ std::unique_ptr m_maskShader;
+ VertexUtil m_vertexArray;
+
+private:
+ VertexUtil m_maskArray;
+};
+
+#endif // VAP_MASK_RENDER_H
diff --git a/ohos/vap/vap_module/src/main/cpp/include/mask/mask_shader.h b/ohos/vap/vap_module/src/main/cpp/include/mask/mask_shader.h
new file mode 100644
index 00000000..790f5a97
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/mask/mask_shader.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_MASK_SHADER_H
+#define VAP_MASK_SHADER_H
+
+#include
+#include "shader_util.h"
+
+static constexpr char MASK_VERTEX[] =
+ "attribute vec4 vPosition;\n"
+ "attribute vec4 vTexCoordinateAlphaMask;\n"
+ "varying vec2 v_TexCoordinateAlphaMask;\n"
+ "\n"
+ "void main() {\n"
+ " v_TexCoordinateAlphaMask = vec2(vTexCoordinateAlphaMask.x, vTexCoordinateAlphaMask.y);\n"
+ " gl_Position = vPosition;\n"
+ "}\n\0";
+
+static constexpr char FRAGMENT_BLUR_EDGE[] =
+ "precision mediump float;\n"
+ "uniform sampler2D uTextureAlphaMask;\n"
+ "varying vec2 v_TexCoordinateAlphaMask;\n"
+ "mat3 weight = mat3(0.0625,0.125,0.0625,0.125,0.25,0.125,0.0625,0.125,0.0625);\n "
+ "int coreSize=3;\n"
+ "float texelOffset = .01;\n"
+ "\n"
+ "void main() {\n"
+ " float alphaResult = 0.;\n"
+ " for(int y = 0; y < coreSize; y++) {\n"
+ " for(int x = 0;x < coreSize; x++) {\n"
+ " alphaResult += texture2D(uTextureAlphaMask, vec2(v_TexCoordinateAlphaMask.x + (-1.0 + float(x)) * "
+ "texelOffset,v_TexCoordinateAlphaMask.y + (-1.0 + float(y)) * texelOffset)).a * weight[x][y];\n"
+ " }\n"
+ " }\n"
+ " gl_FragColor = vec4(0, 0, 0, alphaResult);\n"
+ "}\n\0";
+
+static constexpr char FRAGMENT_NO_BLUR_EDGE[] =
+ "precision mediump float;\n"
+ "uniform sampler2D uTextureAlphaMask;\n"
+ "varying vec2 v_TexCoordinateAlphaMask;\n"
+ "\n"
+ "void main () {\n"
+ " vec4 alphaMaskColor = texture2D(uTextureAlphaMask, v_TexCoordinateAlphaMask);\n"
+ " gl_FragColor = vec4(0, 0, 0, alphaMaskColor.a);\n"
+ "}\n\0";
+
+static constexpr char FRAGMENT_ROW[] =
+ "precision mediump float;\n"
+ "uniform sampler2D uTextureAlphaMask;\n"
+ "varying vec2 v_TexCoordinateAlphaMask;\n"
+ "vec3 weight = vec3(0.4026,0.2442,0.0545);\n "
+ "\n"
+ "void main() {\n"
+ " float texelOffset = .01;\n"
+ " vec2 uv[5];\n"
+ " uv[0]= v_TexCoordinateAlphaMask;\n"
+ " uv[1]=vec2(uv[0].x+texelOffset*1.0, uv[0].y);\n"
+ " uv[2]=vec2(uv[0].x-texelOffset*1.0, uv[0].y);\n"
+ " uv[3]=vec2(uv[0].x+texelOffset*2.0, uv[0].y);\n"
+ " uv[4]=vec2(uv[0].x-texelOffset*2.0, uv[0].y);\n"
+ " float alphaResult = texture2D(uTextureAlphaMask, uv[0]).a * weight[0];\n"
+ " for(int i = 1; i < 3; ++i) {\n"
+ " alphaResult += texture2D(uTextureAlphaMask, uv[2*i-1]).a * weight[i];\n"
+ " alphaResult += texture2D(uTextureAlphaMask, uv[2*i]).a * weight[i];\n"
+ " }\n"
+ " gl_FragColor = vec4(0, 0, 0, alphaResult);\n"
+ "}\n\0";
+
+class MaskShader {
+public:
+ MaskShader(bool edgeBlurBoolean = false);
+
+ void UseProgram();
+
+public:
+ int32_t m_uTextureMaskUnitLocation;
+ int32_t m_aPositionLocation;
+ int32_t m_aTextureMaskCoordinatesLocation;
+
+private:
+ int32_t m_program;
+
+private:
+ const char *U_TEXTURE_ALPHA_MASK_UNIT = "uTextureAlphaMask";
+ const char *A_POSITION = "vPosition";
+ const char *A_TEXTURE_MASK_COORDINATES = "vTexCoordinateAlphaMask";
+};
+
+#endif // VAP_MASK_SHADER_H
\ No newline at end of file
diff --git a/ohos/vap/vap_module/src/main/cpp/include/mix/frame.h b/ohos/vap/vap_module/src/main/cpp/include/mix/frame.h
new file mode 100644
index 00000000..ecc30bd6
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/mix/frame.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_FRAME_H
+#define VAP_FRAME_H
+
+#include
+#include
+
+#include
+#include "vertex_util.h"
+
+using json = nlohmann::json;
+
+class Frame {
+public:
+ Frame(json jsonObj);
+
+ std::string srcId = "";
+ int32_t z = 0;
+ PointRect frame;
+ PointRect mFrame;
+ int32_t mt = 0; // 遮罩旋转角度v2 版本只支持 0 与 90度
+
+ bool operator<(const Frame &f) const { return z < f.z; }
+ void PrintInfo();
+};
+
+class FrameSet {
+public:
+ FrameSet(json jsonObj);
+
+ std::vector frames;
+ int index;
+};
+
+class FrameAll {
+public:
+ FrameAll(json jsonObj);
+
+ std::map frameAll;
+};
+#endif // VAP_FRAME_H
diff --git a/ohos/vap/vap_module/src/main/cpp/include/mix/mix_render.h b/ohos/vap/vap_module/src/main/cpp/include/mix/mix_render.h
new file mode 100644
index 00000000..c0918c58
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/mix/mix_render.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_MIX_RENDER_H
+#define VAP_MIX_RENDER_H
+
+#include
+#include
+#include
+
+#include "anim_config.h"
+#include "frame.h"
+#include "mix_shader.h"
+#include "resource_request.h"
+#include "src.h"
+#include "texture_load_util.h"
+#include "vertex_util.h"
+
+struct MixConfigSize {
+ int32_t width;
+ int32_t height;
+ int32_t videoWidth;
+ int32_t videoHeight;
+};
+
+#define SET_COLOR 0x01
+#define SET_TEXT_ALIGN 0x02
+#define SET_FONT_WEIGHT 0x04
+
+struct MixInputData {
+ std::string txt = "DEFAULT_TEXT";
+ std::string imgUri = "DEFAULT_URI";
+
+ uint8_t isSet = 0;
+ ColorARGB color;
+ OH_Drawing_TextAlign textAlign;
+ OH_Drawing_FontWeight fontWeight;
+};
+
+class MixRender {
+public:
+ MixRender(std::map iptData);
+ ~MixRender();
+
+ void Init();
+ void GenSrcTexture(Src src, BitMap &bitmap, const MixInputData mixData);
+ void RenderFrame(MixConfigSize config, Frame frame, Src src);
+ void SetVideoTextureId(GLuint id);
+ void SetAnimConfig(std::shared_ptr animConfig)
+ {
+ m_animConfig = animConfig;
+ Init();
+ }
+
+ GLuint videoTextureId;
+ std::unique_ptr m_shader;
+ VertexUtil m_vertexArray;
+ VertexUtil m_srcArray;
+ VertexUtil m_maskArray;
+ std::shared_ptr m_animConfig;
+ bool haveSrc = false;
+
+private:
+ void GenSrcCoordsArray(VertexUtil &array, int32_t fw, int32_t fh, int32_t sw, int32_t sh, FitType fitType);
+
+ std::vector m_textureIds;
+ std::map m_mixData;
+};
+
+#endif // VAP_MIX_RENDER_H
diff --git a/ohos/vap/vap_module/src/main/cpp/include/mix/mix_shader.h b/ohos/vap/vap_module/src/main/cpp/include/mix/mix_shader.h
new file mode 100644
index 00000000..046a5aa6
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/mix/mix_shader.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_MIX_SHADER_H
+#define VAP_MIX_SHADER_H
+
+#include
+
+#include "shader_util.h"
+
+static constexpr char VERTEX[] =
+ "attribute vec4 a_Position;\n"
+ "attribute vec2 a_TextureSrcCoordinates;\n"
+ "attribute vec2 a_TextureMaskCoordinates;\n"
+ "varying vec2 v_TextureSrcCoordinates;\n"
+ "varying vec2 v_TextureMaskCoordinates;\n"
+ "void main()\n"
+ "{\n"
+ " v_TextureSrcCoordinates = a_TextureSrcCoordinates;\n"
+ " v_TextureMaskCoordinates = a_TextureMaskCoordinates;\n"
+ " gl_Position = a_Position;\n"
+ "}\n\0";
+
+static constexpr char FRAGMENT[] =
+ "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float; \n"
+ "uniform sampler2D u_TextureSrcUnit;\n"
+ "uniform sampler2D u_TextureMaskUnit;\n"
+ "uniform int u_isFill;\n"
+ "uniform vec4 u_Color;\n"
+ "varying vec2 v_TextureSrcCoordinates;\n"
+ "varying vec2 v_TextureMaskCoordinates;\n"
+ "void main()\n"
+ "{\n"
+ " vec4 srcRgba = texture2D(u_TextureSrcUnit, v_TextureSrcCoordinates);\n"
+ " vec4 maskRgba = texture2D(u_TextureMaskUnit, v_TextureMaskCoordinates);\n"
+ " float isFill = step(0.5, float(u_isFill));\n"
+ " vec4 srcRgbaCal = isFill * vec4(u_Color.r, u_Color.g, u_Color.b, srcRgba.a) + (1.0 - isFill) * srcRgba;\n"
+ " gl_FragColor = vec4(srcRgbaCal.r, srcRgbaCal.g, srcRgbaCal.b, srcRgba.a * maskRgba.r);\n"
+ "}\n\0";
+
+class MixShader {
+public:
+ MixShader();
+ void UseProgram();
+
+public:
+ // Shader program
+ int32_t m_program;
+
+ // Uniform locations
+ int32_t m_uTextureSrcUnitLocation;
+ int32_t m_uTextureMaskUnitLocation;
+ int32_t m_uIsFillLocation;
+ int32_t m_uColorLocation;
+
+ // Attribute locations
+ int32_t m_aPositionLocation;
+ int32_t m_aTextureSrcCoordinatesLocation;
+ int32_t m_aTextureMaskCoordinatesLocation;
+
+private:
+ const char *U_TEXTURE_SRC_UNIT = "u_TextureSrcUnit";
+ const char *U_TEXTURE_MASK_UNIT = "u_TextureMaskUnit";
+ const char *U_IS_FILL = "u_isFill";
+ const char *U_COLOR = "u_Color";
+
+ const char *A_POSITION = "a_Position";
+ const char *A_TEXTURE_SRC_COORDINATES = "a_TextureSrcCoordinates";
+ const char *A_TEXTURE_MASK_COORDINATES = "a_TextureMaskCoordinates";
+};
+
+#endif // VAP_MIX_SHADER_H
diff --git a/ohos/vap/vap_module/src/main/cpp/include/mix/src.h b/ohos/vap/vap_module/src/main/cpp/include/mix/src.h
new file mode 100644
index 00000000..d03d7d92
--- /dev/null
+++ b/ohos/vap/vap_module/src/main/cpp/include/mix/src.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VAP_SRC_H
+#define VAP_SRC_H
+
+#include