!6 vpe code init

Merge pull request !6 from 刘尚/master
This commit is contained in:
openharmony_ci
2025-03-01 12:44:58 +00:00
committed by Gitee
232 changed files with 35731 additions and 25 deletions
+152
View File
@@ -0,0 +1,152 @@
## c/c++
# Prerequisites
*.d
# Compiled Object files
*.ko
*.slo
*.lo
*.o
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.so.*
*.dylib
*.dll
# module files
*.mod
*.smod
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
*.lo
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
## cmake
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
## ninja
.ninja_deps
.ninja_log
## vscode
.vscode
*.code-workspace
# Local History for Visual Studio Code
.history/
## jetbrains
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
.clang-format
+22
View File
@@ -0,0 +1,22 @@
# 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("//build/config/ohos/config.gni")
import("//build/ohos.gni")
group("video_processing_engine_packages") {
public_deps = [
"framework:videoprocessingengine",
"services:videoprocessingservice"
]
}
+177
View File
@@ -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
+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 2025 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Notes:
This is project config file for OpenHarmony OSS Audit Tool, if you have any questions or concerns, please email chenyaxun.
-->
<!-- OAT(OSS Audit Tool) configuration guide:
basedir: Root dir, the basedir + project path is the real source file location.
licensefile:
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
tasklist(only for batch mode):
1. task: Define oat check thread, each task will start a new thread.
2. task name: Only an name, no practical effect.
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
5. task project: Projects to be checked, the path field define the source root dir of the project.
policyList:
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
3. policyitem type:
"compatibility" is used to check license compatibility in the specified path;
"license" is used to check source license header in the specified path;
"copyright" is used to check source copyright header in the specified path;
"import" is used to check source dependency in the specified path, such as import ... ,include ...
"filetype" is used to check file type in the specified path, supported file types: archive, binary
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
7. policyitem filefilter: Used to bind filefilter which define filter rules.
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
Note:If the text contains special characters, please escape them according to the following rules:
" == &gt;
& == &gt;
' == &gt;
< == &gt;
> == &gt;
-->
<configuration>
<oatconfig>
<licensefile></licensefile>
<policylist>
<policy name="projectPolicy" desc="">
</policy>
</policylist>
<filefilterlist>
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies" >
<filteritem type="filepath" name="figures/.*" desc="architecture figure binary."/>
</filefilter>
<filefilter name="defaultFilter" desc="Files not to check">
<filteritem type="filepath" name="test/.*" desc="Test path"/>
</filefilter>
</filefilterlist>
</oatconfig>
</configuration>
+56 -25
View File
@@ -1,37 +1,68 @@
# multimedia_video_processing_engine
# VPE引擎
#### 介绍
针对视频、图片以及渲染的内容的HDR、清晰和流畅低功耗的用户体验,系统层提供统一的公共基础能力,实现简单、一致、高效的视频处理服务
## 简介
VPEVideo Processing Engine)引擎是处理视频和图像数据的媒体引擎,包括细节增强、对比度增强、亮度增强、动态范围增强等基础能力,为转码、分享、显示后处理等提供色彩空间转换、缩放超分、动态元数据集生成等基础算法
#### 软件架构
软件架构说明
VPE引擎的主要结构如下图所示:
![VPE引擎架构图](./figures/videoProcessingEngine_architecture.png)
#### 安装教程
## 目录
1. xxxx
2. xxxx
3. xxxx
仓目录结构如下:
#### 使用说明
```
/foundation/multimedia/video_processing_engine/
├── framework # 框架代码
│ ├── algorithm # 算法框架
│ ├── aihdr_enhancer # 图像HDR增强算法框架
│ ├── aihdr_enhancer_video # 视频HDR增强算法框架
│ ├── colorspace_converter # 图像颜色空间转换算法框架
│ ├── colorspace_converter_display # 图像颜色空间显示算法框架
│ ├── colorspace_converter_video # 视频颜色空间转换算法框架
│ ├── detail_enhancer # 图像细节增强算法框架
│ ├── detail_enhancer_video # 视频细节增强算法框架
│ ├── extension_manager # 插件管理
│ ├── metadata_generator # 图像元数据生成算法框架
│ ├── metadata_generator_video # 视频元数据生成算法框架
│ ├── video_variable_refresh_rate # 视频可变帧率算法框架
│ ├── capi # CAPI层
│ ├── image_processing # 图像CAPI
│ ├── video_processing # 视频CAPI
│ ├── dfx # dfx代码
├── interfaces # 接口层
│ ├── inner_api # 系统内部接口
│ ├── kits # 应用接口
├── services # 服务代码
├── sertestvices # 测试代码
```
1. xxxx
2. xxxx
3. xxxx
## 编译构建
#### 参与贡献
编译32位ARM系统VPE引擎
```
./build.sh --product-name {product_name} --ccache --build-target video_processing_engine
```
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
编译64位ARM系统VPE引擎
```
./build.sh --product-name {product_name} --ccache --target-cpu arm64 --build-target video_processing_engine
```
{product_name}为当前支持的平台,比如rk3568。
#### 特技
## 说明
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
### 使用说明
VPE引擎作为OpenHarmony的组件,提供系统的视频图像能力,包含色彩空间转换、动态元数据生成以及细节增强等能力,供开发者进行图像和视频处理操作。
## 相关仓
- [graphic_graphic_2d](https://gitee.com/openharmony/graphic_graphic_2d)
- [graphic_graphic_surface](https://gitee.com/openharmony/graphic_graphic_surface)
- [multimedia_image_framework](https://gitee.com/openharmony/multimedia_image_framework)
- [multimedia_media_foundation](https://gitee.com/openharmony/multimedia_media_foundation)
- [third_party_egl](https://gitee.com/openharmony/third_party_egl)
- [third_party_opengles](https://gitee.com/openharmony/third_party_opengles)
- [third_party_opencl-headers](https://gitee.com/openharmony/third_party_opencl-headers)
- [third_party_skia](https://gitee.com/openharmony/third_party_skia)
+68
View File
@@ -0,0 +1,68 @@
# VPE
## Overview
The Video Processing Engine (VPE) is a media engine for processing video and image data. It offers a range of fundamental capabilities including enhancements to details, contrast, luminance, and dynamic ranges. It also supports essential algorithms for color space conversion, scaling and upscaling, and dynamic metadata generation for transcoding, sharing, and post-processing for display.
The following figure demonstrates the VPE architecture.
![VPE architecture](./figures/videoProcessingEngine_architecture_english.png)
## Directory Structure
The structure of the repository directory is as follows:
```
/foundation/multimedia/video_processing_engine/
├── framework # Framework code
│ ├── algorithm # Algorithm framework
│ ├── aihdr_enhancer # Image HDR enhancement algorithm framework
│ ├── aihdr_enhancer_video # Video HDR enhancement algorithm framework
│ ├── colorspace_converter # Image color space conversion algorithm framework
│ ├── colorspace_converter_display # Image color space display algorithm framework
│ ├── colorspace_converter_video # Video color space conversion algorithm framework
│ ├── detail_enhancer # Image detail enhancement algorithm framework
│ ├── detail_enhancer_video # Video detail enhancement algorithm framework
│ ├── extension_manager # Plugin management
│ ├── metadata_generator # Image metadata generation algorithm framework
│ ├── metadata_generator_video # Video metadata generation algorithm framework
│ ├── video_variable_refresh_rate # Video variable frame rate algorithm framework
│ ├── capi # CAPI layer
│ ├── image_processing # Image CAPI
│ ├── video_processing # Video CAPI
│ ├── dfx # DFX code
├── interfaces # API layer
│ ├── inner_api # Internal APIs
│ ├── kits # Application APIs
├── services # Service code
├── sertestvices # Test code
```
## Build
Run the following command to build the VPE for the 32-bit ARM system:
```
./build.sh --product-name {product_name} --ccache --build-target video_processing_engine
```
Run the following command to build the VPE for the 64-bit ARM system:
```
./build.sh --product-name {product_name} --ccache --target-cpu arm64 --build-target video_processing_engine
```
**product_name** indicates the product supported, for example, **rk3568**.
## Description
### How to Use
As a component of OpenHarmony, the VPE provides video and image processing capabilities, including color space conversion, dynamic metadata generation, and detail enhancement.
## Repositories Involved
- [graphic_graphic_2d](https://gitee.com/openharmony/graphic_graphic_2d)
- [graphic_graphic_surface](https://gitee.com/openharmony/graphic_graphic_surface)
- [multimedia_image_framework](https://gitee.com/openharmony/multimedia_image_framework)
- [multimedia_media_foundation](https://gitee.com/openharmony/multimedia_media_foundation)
- [third_party_egl](https://gitee.com/openharmony/third_party_egl)
- [third_party_opengles](https://gitee.com/openharmony/third_party_opengles)
- [third_party_opencl-headers](https://gitee.com/openharmony/third_party_opencl-headers)
- [third_party_skia](https://gitee.com/openharmony/third_party_skia)
+140
View File
@@ -0,0 +1,140 @@
{
"name": "@ohos/video_processing_engine",
"description": "video_processing_engine",
"version": "4.1",
"license": "Apache License 2.0",
"publishAs": "code-segment",
"segment": {
"destPath": "foundation/multimedia/video_processing_engine"
},
"dirs": {},
"scripts": {},
"component": {
"name": "video_processing_engine",
"subsystem": "multimedia",
"syscap": [],
"features": [],
"adapted_system_type": [
"standard"
],
"rom": "10000KB",
"ram": "10000KB",
"hisysevent_config": [],
"deps": {
"components": [
"c_utils",
"graphic_2d",
"graphic_surface",
"hilog",
"hitrace",
"drivers_interface_display",
"ffrt",
"init",
"hdf_core",
"image_framework",
"media_foundation",
"napi",
"ipc",
"safwk",
"samgr",
"eventhandler"
],
"third_party": [
"skia",
"egl",
"opengles",
"bounds_checking_function",
"opencl-headers"
]
},
"build": {
"sub_component": [
"//foundation/multimedia/video_processing_engine/framework:videoprocessingengine",
"//foundation/multimedia/video_processing_engine/services:video_processing_service_group"
],
"inner_kits": [
{
"type": "so",
"name": "//foundation/multimedia/video_processing_engine/framework:videoprocessingengine",
"header": {
"header_files": [
"algorithm_common.h",
"algorithm_errors.h",
"colorspace_converter.h",
"colorspace_converter_display.h",
"metadata_generator.h",
"colorspace_converter_video.h",
"colorspace_converter_video_common.h",
"colorspace_converter_video_description.h",
"detail_enhancer_common.h",
"detail_enhancer_image.h",
"detail_enhancer_video_common.h",
"detail_enhancer_video.h"
],
"header_base": "//foundation/multimedia/video_processing_engine/interfaces/inner_api"
}
},
{
"name": "//foundation/multimedia/video_processing_engine/services:videoprocessingservice_idl_headers",
"header": {
"header_files": [
"video_processing_service_manager_proxy.h"
],
"header_base": "//foundation/multimedia/video_processing_engine/services"
}
},
{
"type": "so",
"name": "//foundation/multimedia/video_processing_engine/framework:image_processing_capi_impl",
"header":{
"header_files":[
"image_processing_capi_impl.h"
],
"header_base": "//foundation/multimedia/video_processing_engine/framework/capi/image_processing/include"
}
},
{
"type": "so",
"name": "//foundation/multimedia/video_processing_engine/framework:video_processing_capi_impl",
"header":{
"header_files":[
"video_processing_capi_impl.h"
],
"header_base": "//foundation/multimedia/video_processing_engine/framework/capi/video_processing/include"
}
},
{
"type": "so",
"name": "//foundation/multimedia/video_processing_engine/framework:detailEnhancer",
"header":{
"header_files":[
"detail_enhance_napi.h"
],
"header_base": "//foundation/multimedia/video_processing_engine/interfaces/kits/js"
}
},
{
"type": "so",
"name": "//foundation/multimedia/video_processing_engine/framework:videoprocessingenginenapi",
"header":{
"header_files":[
"detail_enhance_napi_formal.h",
"native_module_ohos_imageprocessing.h"
],
"header_base": "//foundation/multimedia/video_processing_engine/interfaces/kits/js"
}
}
],
"group_type": {
"base_group": [],
"fwk_group": [],
"service_group": []
},
"test": [
"//foundation/multimedia/video_processing_engine/test:demo_test",
"//foundation/multimedia/video_processing_engine/test:unit_test",
"//foundation/multimedia/video_processing_engine/test:module_test"
]
}
}
}
+90
View File
@@ -0,0 +1,90 @@
# 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.
VIDEO_PROCESSING_ENGINE_ROOT_DIR = "//foundation/multimedia/video_processing_engine"
FRAMEWORK_DIR = "$VIDEO_PROCESSING_ENGINE_ROOT_DIR/framework"
ALGORITHM_DIR = "$FRAMEWORK_DIR/algorithm"
CAPI_DIR = "$FRAMEWORK_DIR/capi"
COMMON_DIR = "$FRAMEWORK_DIR/common"
DFX_DIR = "$FRAMEWORK_DIR/dfx"
PLUGIN_DIR = "$FRAMEWORK_DIR/plugin"
AIHDR_ENHANCER_DIR = "$ALGORITHM_DIR/aihdr_enhancer"
AIHDR_ENHANCER_VIDEO_DIR = "$ALGORITHM_DIR/aihdr_enhancer_video"
COLORSPACE_CONVERTER_DIR = "$ALGORITHM_DIR/colorspace_converter"
COLORSPACE_CONVERTER_DISPLAY_DIR = "$ALGORITHM_DIR/colorspace_converter_display"
COLORSPACE_CONVERTER_VIDEO_DIR = "$ALGORITHM_DIR/colorspace_converter_video"
METADATA_GENERATOR_DIR = "$ALGORITHM_DIR/metadata_generator"
METADATA_GENERATOR_VIDEO_DIR = "$ALGORITHM_DIR/metadata_generator_video"
ALGORITHM_EXTENSION_MANAGER_DIR = "$ALGORITHM_DIR/extension_manager"
ALGORITHM_COMMON_DIR = "$ALGORITHM_DIR/common"
DETAIL_ENHANCER_DIR = "$ALGORITHM_DIR/detail_enhancer"
DETAIL_ENHANCER_VIDEO_DIR = "$ALGORITHM_DIR/detail_enhancer_video"
VIDEO_REFRESHRATE_PREDICTION_DIR = "$ALGORITHM_DIR/video_variable_refresh_rate"
#CAPI
CAPI_IMAGE_DIR = "$FRAMEWORK_DIR/capi/image_processing"
CAPI_COLORSPACE_CONVERTER_DIR = "$CAPI_IMAGE_DIR/colorspace_converter"
CAPI_METADATA_GENERATOR_DIR = "$CAPI_IMAGE_DIR/metadata_generator"
CAPI_IMAGE_DETAIL_ENHANCER_DIR = "$CAPI_IMAGE_DIR/detail_enhancer"
CAPI_VIDEO_DIR = "$FRAMEWORK_DIR/capi/video_processing"
CAPI_VIDEO_DETAIL_ENHANCER_DIR = "$CAPI_VIDEO_DIR/detail_enhancer"
CAPI_VIDEO_COLORSPACE_CONVERTER_DIR = "$CAPI_VIDEO_DIR/colorspace_converter"
CAPI_VIDEO_METADATA_GENERATOR_DIR = "$CAPI_VIDEO_DIR/metadata_generator"
INTERFACES_DIR = "$VIDEO_PROCESSING_ENGINE_ROOT_DIR/interfaces"
INTERFACES_INNER_API_DIR = "$INTERFACES_DIR/inner_api"
INTERFACES_CAPI_DIR = "$INTERFACES_DIR/kits/c"
INTERFACES_PLUGIN_DIR = "$INTERFACES_DIR/plugin"
SKIA_DIR = "//third_party/skia"
EGL_DIR = "//third_party/EGL"
OPENGLES_DIR = "//third_party/openGLES"
#cuva
CUVA_DIR = "$ALGORITHM_DIR/extensions/colorspace_converter_display/cuva_libs"
#detail enhancer
IMAGE_AISR_DIR = "$ALGORITHM_DIR/extensions/detail_enhancer/image/ai_super_resolution"
IMAGE_EVE_DIR = "$ALGORITHM_DIR/extensions/detail_enhancer/image/extream_vision_engine"
IMAGE_LIBYUV_DIR = "$ALGORITHM_DIR/extensions/detail_enhancer/image/libyuv"
VIDEO_AISR_DIR = "$ALGORITHM_DIR/extensions/detail_enhancer/video/ai_super_resolution"
#contrast enhancer
CONTRAST_ENHANCER_DIR = "$ALGORITHM_DIR/contrast_enhancer"
TEST_UTILS_PATH = "$VIDEO_PROCESSING_ENGINE_ROOT_DIR/test/utils"
UNIT_TEST_OUTPUT_PATH = "video_processing_engine/unittest"
MODULE_TEST_OUTPUT_PATH = "video_processing_engine/moduletest"
VIDEO_PROCESSING_ENGINE_CFLAGS = [
"-std=c++17",
"-fno-rtti",
"-fno-exceptions",
"-Wall",
"-fno-common",
"-fstack-protector-strong",
"-Wshadow",
"-FPIC",
"-FS",
"-O2",
"-D_FORTIFY_SOURCE=2",
"-Wformat=2",
"-Wdate-time",
"-Werror",
"-Wextra",
"-Wimplicit-fallthrough",
"-Wsign-compare",
"-Wunused-parameter"
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

+501
View File
@@ -0,0 +1,501 @@
# Copyright (c) 2025 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("//foundation/ability/idl_tool/idl_config.gni")
import("//foundation/multimedia/video_processing_engine/config.gni")
import("$CAPI_DIR/config.gni")
config("export_config") {
include_dirs = [
"$AIHDR_ENHANCER_DIR/include",
"$INTERFACES_INNER_API_DIR",
"$DFX_DIR/include",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services/include",
"$DETAIL_ENHANCER_DIR/include",
"$COLORSPACE_CONVERTER_DIR/include",
"$METADATA_GENERATOR_DIR/include",
"$INTERFACES_INNER_API_DIR/native/colorspace",
"$COLORSPACE_CONVERTER_DISPLAY_DIR/include",
"$VIDEO_REFRESHRATE_PREDICTION_DIR/include",
"$ALGORITHM_DIR/common/include",
]
}
config("video_process_config") {
cflags = [
"-std=c++17",
"-fno-rtti",
"-fno-exceptions",
"-Wall",
"-fno-common",
"-fstack-protector-strong",
"-Wshadow",
"-FPIC",
"-FS",
"-O2",
"-D_FORTIFY_SOURCE=2",
"-Wformat=2",
# "-Wfloat-equal",
"-Wdate-time",
"-Werror",
"-Wextra",
"-Wimplicit-fallthrough",
"-Wsign-compare",
"-Wunused-parameter",
]
include_dirs = [
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR",
"$FRAMEWORK_DIR",
"$FRAMEWORK_DIR/common/include",
"$AIHDR_ENHANCER_DIR/include",
"$AIHDR_ENHANCER_VIDEO_DIR/include",
"$ALGORITHM_DIR/common/include",
"$ALGORITHM_DIR/extension_manager/include",
"$COLORSPACE_CONVERTER_DIR/include",
"$COLORSPACE_CONVERTER_DISPLAY_DIR/include",
"$COLORSPACE_CONVERTER_VIDEO_DIR/include",
"$METADATA_GENERATOR_DIR/include",
"$METADATA_GENERATOR_VIDEO_DIR/include",
"$DETAIL_ENHANCER_VIDEO_DIR/include",
"$VIDEO_REFRESHRATE_PREDICTION_DIR/include",
"$DETAIL_ENHANCER_DIR/include",
"$DFX_DIR/include",
"$FRAMEWORK_DIR/plugin",
"$FRAMEWORK_DIR/module",
"$INTERFACES_INNER_API_DIR",
"$INTERFACES_INNER_API_DIR/module",
"$INTERFACES_DIR/plugin",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services/include",
# temporary dir
"$SKIA_DIR",
"${target_gen_dir}/../services/",
"$SKIA_DIR/include/core",
"$SKIA_DIR/include/encode",
"$SKIA_DIR",
"$SKIA_DIR/src/ports/skia_ohos",
"$SKIA_DIR/src/ports",
"$SKIA_DIR/src/images",
"$SKIA_DIR/include/private",
"$SKIA_DIR/include/effects",
"$SKIA_DIR/third_party/externals/angle2/src/common",
"$SKIA_DIR/third_party/externals/angle2/src/",
"$SKIA_DIR/third_party/externals/angle2/src/common/third_party/base/",
"//foundation/graphic/graphic_2d/utils/color_manager/export",
"//base/startup/init/interfaces/innerkits/include/syspara/",
]
}
ohos_prebuilt_shared_library("extream_vision_engine") {
if (is_asan && use_hwasan) {
source = "//binary/artifacts/display/AIPQ20/asan/libextream_vision_engine.so"
} else {
source = "//binary/artifacts/display/AIPQ20/libextream_vision_engine.so"
}
module_install_dir = "lib64/"
output = "libextream_vision_engine.so"
install_images = [ "system" ]
subsystem_name = "multimedia"
part_name = "video_processing_engine"
install_enable = true
}
ohos_prebuilt_shared_library("ai_super_resolution") {
if (is_asan && use_hwasan) {
source = "//binary/artifacts/display/AIPQ20/asan/libdisplay_aipq_imagesr.so"
} else {
source = "//binary/artifacts/display/AIPQ20/libdisplay_aipq_imagesr.so"
}
module_install_dir = "lib64/"
output = "libdisplay_aipq_imagesr.so"
install_images = [ "system" ]
subsystem_name = "multimedia"
part_name = "video_processing_engine"
install_enable = true
}
ohos_prebuilt_shared_library("aihdr_engine") {
if (is_asan && use_hwasan) {
source = "//binary/artifacts/display/AIPQ20/asan/libaihdr_engine.so"
} else {
source = "//binary/artifacts/display/AIPQ20/libaihdr_engine.so"
}
module_install_dir = "lib64/"
output = "libaihdr_engine.so"
install_images = [ "system" ]
subsystem_name = "multimedia"
part_name = "video_processing_engine"
install_enable = true
}
ohos_shared_library("videoprocessingengine") {
branch_protector_ret = "pac_ret"
install_enable = true
sanitize = {
boundary_sanitize = true
cfi = true
cfi_cross_dso = true
integer_overflow = true
ubsan = true
debug = false
}
configs = [ ":video_process_config" ]
public_configs = [ ":export_config" ]
include_dirs = []
sources = [
"$AIHDR_ENHANCER_DIR/aihdr_enhancer_fwk.cpp",
"$AIHDR_ENHANCER_VIDEO_DIR/aihdr_enhancer_video_impl.cpp",
"$ALGORITHM_DIR/common/algorithm_common.cpp",
"$ALGORITHM_DIR/common/algorithm_utils.cpp",
"$ALGORITHM_DIR/common/algorithm_video.cpp",
"$ALGORITHM_DIR/common/algorithm_video_common.cpp",
"$ALGORITHM_DIR/common/algorithm_video_impl.cpp",
"$ALGORITHM_DIR/common/frame_info.cpp",
"$ALGORITHM_DIR/common/vpe_parse_metadata.cpp",
"$ALGORITHM_DIR/extension_manager/extension_manager.cpp",
"$ALGORITHM_DIR/extension_manager/utils.cpp",
"$COLORSPACE_CONVERTER_DIR/colorspace_converter_fwk.cpp",
"$COLORSPACE_CONVERTER_VIDEO_DIR/colorspace_converter_video_impl.cpp",
"$COLORSPACE_CONVERTER_DISPLAY_DIR/colorspace_converter_display_fwk.cpp",
"$METADATA_GENERATOR_DIR/metadata_generator_fwk.cpp",
"$METADATA_GENERATOR_VIDEO_DIR/metadata_generator_video_impl.cpp",
"$DETAIL_ENHANCER_DIR/detail_enhancer_image_fwk.cpp",
"$DETAIL_ENHANCER_VIDEO_DIR/detail_enhancer_video_fwk.cpp",
"$DETAIL_ENHANCER_VIDEO_DIR/detail_enhancer_video_impl.cpp",
"$VIDEO_REFRESHRATE_PREDICTION_DIR/video_refreshrate_prediction_fwk.cpp",
"$DFX_DIR/vpe_trace.cpp",
"$DFX_DIR/vpe_log.cpp",
#client
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services/src/video_processing_client.cpp",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services/src/video_processing_load_callback.cpp",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services/src/surface_buffer_info.cpp",
"${target_gen_dir}/../services/video_processing_service_manager_proxy.cpp",
"${target_gen_dir}/../services/video_processing_service_manager_stub.cpp",
"$ALGORITHM_COMMON_DIR/image_opencl_wrapper.cpp",
"$ALGORITHM_COMMON_DIR/image_openclsetup.cpp"
]
deps = [ "//third_party/skia:skia_ohos",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services:videoprocessingservice_interface",
":aihdr_engine",
":ai_super_resolution",
":extream_vision_engine",
"//third_party/opencl-headers:libcl",
"//third_party/bounds_checking_function:libsec_static"]
external_deps = [
"c_utils:utils",
"drivers_interface_display:display_commontype_idl_headers",
"drivers_interface_display:libdisplay_commontype_proxy_2.1",
"graphic_surface:surface",
"graphic_surface:sync_fence",
"hilog:libhilog",
"hitrace:hitrace_meter",
"init:libbegetutil",
"hdf_core:libhdi",
"hdf_core:libhdf_host",
"hdf_core:libhdf_ipc_adapter",
"hdf_core:libhdf_utils",
"hdf_core:hdf_posix_osal",
"graphic_2d:2d_graphics",
"ipc:ipc_single",
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
"media_foundation:media_foundation",
"graphic_2d:EGL",
"graphic_2d:GLESv3",
]
subsystem_name = "multimedia"
part_name = "video_processing_engine"
}
config("video_processing_engine_capi_config") {
include_dirs = [
"$VIDEO_PROCESSING_ENGINE_CAPI_DIR/interface/kits/c",
"$VIDEO_PROCESSING_ENGINE_CAPI_DIR/interface/inner_api",
]
}
ohos_shared_library("image_processing_capi_impl") {
sanitize = {
boundary_sanitize = true
cfi = true
cfi_cross_dso = true
integer_overflow = true
ubsan = true
debug = false
}
stack_protector_ret = true
cflags = VIDEO_PROCESSING_ENGINE_CFLAGS
cflags += [
"-ffunction-sections",
"-fdata-sections",
"-DIMAGE_COLORSPACE_FLAG",
]
ldflags = [ "-Wl,--gc-sections" ]
configs = [ ":video_processing_engine_capi_config" ]
include_dirs = [
#Interface
"$INTERFACES_CAPI_DIR",
"$INTERFACES_INNER_API_DIR",
#Common
"$DFX_DIR/include",
"$ALGORITHM_COMMON_DIR/include",
#CAPI implementation
"$CAPI_IMAGE_DIR/include",
"$CAPI_IMAGE_DETAIL_ENHANCER_DIR/include",
"$CAPI_COLORSPACE_CONVERTER_DIR/include",
"$CAPI_METADATA_GENERATOR_DIR/include",
"$DETAIL_ENHANCER_DIR/include",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services/include",
"${target_gen_dir}/../services/",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/framework/algorithm/common/include",
]
sources = [
"$CAPI_IMAGE_DIR/image_environment_native.cpp",
"$CAPI_IMAGE_DIR/image_processing_capi_impl.cpp",
"$CAPI_IMAGE_DIR/image_processing_factory.cpp",
"$CAPI_IMAGE_DIR/image_processing_impl.cpp",
"$CAPI_IMAGE_DIR/image_processing_native_base.cpp",
"$CAPI_IMAGE_DIR/image_processing_utils.cpp",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/framework/algorithm/common/vpe_utils_common.cpp",
"$CAPI_IMAGE_DETAIL_ENHANCER_DIR/detail_enhancer_image_native.cpp",
"$CAPI_COLORSPACE_CONVERTER_DIR/colorspace_converter_image_native.cpp",
"$CAPI_METADATA_GENERATOR_DIR/metadata_generator_image_native.cpp",
]
deps = [
":videoprocessingengine",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services:videoprocessingservice_interface",
]
external_deps = [
"c_utils:utils",
"graphic_surface:surface",
"hilog:libhilog",
"graphic_2d:2d_graphics",
"media_foundation:media_foundation",
"image_framework:pixelmap",
"image_framework:image_native",
"drivers_interface_display:display_commontype_idl_headers",
"ipc:ipc_single",
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
]
output_extension = "so"
subsystem_name = "multimedia"
innerapi_tags = [ "ndk" ]
part_name = "video_processing_engine"
}
ohos_shared_library("video_processing_capi_impl") {
sanitize = {
boundary_sanitize = true
cfi = true
cfi_cross_dso = true
integer_overflow = true
ubsan = true
debug = false
}
stack_protector_ret = true
cflags = VIDEO_PROCESSING_ENGINE_CFLAGS
cflags += [
"-ffunction-sections",
"-fdata-sections",
]
ldflags = [ "-Wl,--gc-sections" ]
configs = [ ":video_processing_engine_capi_config" ]
include_dirs = [
#Interface
"$INTERFACES_CAPI_DIR",
"$INTERFACES_INNER_API_DIR",
#Common
"$DFX_DIR/include",
"$ALGORITHM_COMMON_DIR/include",
#CAPI implementation
"$CAPI_VIDEO_DIR/include/",
"$CAPI_VIDEO_DIR/aihdr_enhancer/include/",
"$CAPI_VIDEO_DETAIL_ENHANCER_DIR/include/",
"$CAPI_VIDEO_COLORSPACE_CONVERTER_DIR/include/",
"//foundation/graphic/graphic_surface/interfaces/inner_api/surface/",
"//foundation/graphic/graphic_surface/surface/include/",
"//foundation/graphic/graphic_2d/interfaces/inner_api",
"$CAPI_VIDEO_METADATA_GENERATOR_DIR/include/",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services/include",
"${target_gen_dir}/../services/",
]
sources = [
#CAPI common
"$CAPI_VIDEO_DIR/video_environment_native.cpp",
"$CAPI_VIDEO_DIR/video_processing_callback_impl.cpp",
"$CAPI_VIDEO_DIR/video_processing_callback_native.cpp",
"$CAPI_VIDEO_DIR/video_processing_capi_impl.cpp",
"$CAPI_VIDEO_DIR/video_processing_capi_capability.cpp",
"$CAPI_VIDEO_DIR/video_processing_factory.cpp",
"$CAPI_VIDEO_DIR/video_processing_impl.cpp",
"$CAPI_VIDEO_DIR/video_processing_native_base.cpp",
"$CAPI_VIDEO_DIR/video_processing_utils.cpp",
#CAPI - features
#CAPI - detail enhancement
"$CAPI_VIDEO_DETAIL_ENHANCER_DIR/detail_enhancer_video_native.cpp",
"$CAPI_VIDEO_COLORSPACE_CONVERTER_DIR/colorSpace_converter_video_native.cpp",
"$CAPI_VIDEO_METADATA_GENERATOR_DIR/metadata_generator_video_native.cpp",
"$CAPI_VIDEO_DIR/aihdr_enhancer/aihdr_enhancer_video_native.cpp"
]
deps = [
":videoprocessingengine",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/services:videoprocessingservice_interface",
]
external_deps = [
"c_utils:utils",
"graphic_surface:surface",
"hilog:libhilog",
"hitrace:hitrace_meter",
"media_foundation:media_foundation",
"drivers_interface_display:display_commontype_idl_headers",
"graphic_2d:libgraphic_utils",
"graphic_2d:librender_service_client",
"ipc:ipc_single",
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
]
output_extension = "so"
subsystem_name = "multimedia"
innerapi_tags = [ "ndk" ]
part_name = "video_processing_engine"
}
ohos_shared_library("detailEnhancer") {
sanitize = {
cfi = true
cfi_cross_dso = true
cfi_vcall_icall_only = true
debug = false
}
defines = [ "IMAGE_COLORSPACE_FLAG" ]
include_dirs = [
"$DFX_DIR/include",
"//foundation/multimedia/media_foundation/interface/kits/c",
"//foundation/multimedia/image_framework/interfaces/kits/native/include/image",
"//foundation/multimedia/image_framework/frameworks/kits/js/common/ndk/include",
"//foundation/multimedia/video_processing_engine/interfaces/kits/js",
"//foundation/multimedia/media_foundation/video_processing_engine/interface/kits/c",
"//foundation/multimedia/video_processing_engine/interfaces/inner_api",
"//foundation/multimedia/video_processing_engine/framework/capi/image_processing/include/",
]
sources = [
"//foundation/multimedia/video_processing_engine/framework/capi/image_processing/detail_enhance_napi.cpp",
"//foundation/multimedia/image_framework/frameworks/innerkitsimpl/common/src/memory_manager.cpp",
]
deps = [
":videoprocessingengine",
]
cflags = VIDEO_PROCESSING_ENGINE_CFLAGS
external_deps = [
"c_utils:utils",
"graphic_surface:surface",
"hilog:libhilog",
"hitrace:hitrace_meter",
"ipc:ipc_napi",
"media_foundation:native_media_core",
"napi:ace_napi",
"image_framework:image_utils",
"image_framework:image_native",
"image_framework:pixelmap",
"image_framework:image",
"drivers_interface_display:display_commontype_idl_headers",
]
output_name = "libdetailenhancer_napi"
subsystem_name = "multimedia"
relative_install_dir = "module/multimedia"
part_name = "video_processing_engine"
}
ohos_shared_library("videoprocessingenginenapi") {
sanitize = {
cfi = true
cfi_cross_dso = true
cfi_vcall_icall_only = true
debug = false
}
defines = [ "IMAGE_COLORSPACE_FLAG" ]
include_dirs = [
"$DFX_DIR/include",
"$INTERFACES_DIR/kits/js",
"$INTERFACES_INNER_API_DIR",
"$CAPI_DIR/image_processing/include/",
"$ALGORITHM_COMMON_DIR/include/",
]
sources = [
"$CAPI_DIR/image_processing/detail_enhance_napi_formal.cpp",
"$INTERFACES_DIR/kits/js/native_module_ohos_imageprocessing.cpp",
]
deps = [
":videoprocessingengine",
]
cflags = VIDEO_PROCESSING_ENGINE_CFLAGS
external_deps = [
"c_utils:utils",
"drivers_interface_display:display_commontype_idl_headers",
"graphic_surface:surface",
"hilog:libhilog",
"hitrace:hitrace_meter",
"image_framework:image_utils",
"image_framework:image_native",
"image_framework:pixelmap",
"image_framework:image",
"ipc:ipc_napi",
"media_foundation:native_media_core",
"media_foundation:media_foundation",
"media_foundation:image_processing",
"napi:ace_napi",
]
output_name = "libvideoprocessingengine_napi"
subsystem_name = "multimedia"
relative_install_dir = "module/multimedia"
part_name = "video_processing_engine"
}
@@ -0,0 +1,147 @@
/*
* 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 "aihdr_enhancer_fwk.h"
#include "native_buffer.h"
#include "surface_buffer.h"
#include "extension_manager.h"
#include "video_processing_client.h"
#include "vpe_log.h"
#include "vpe_trace.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
AihdrEnhancerFwk::AihdrEnhancerFwk()
{
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
AihdrEnhancerFwk::~AihdrEnhancerFwk()
{
if (impl_) {
impl_->Deinit();
impl_ = nullptr;
}
Extension::ExtensionManager::GetInstance().DecreaseInstance();
}
VPEAlgoErrCode AihdrEnhancerFwk::SetParameter(const int& parameter)
{
parameter_ = parameter;
VPE_LOGI("AihdrEnhancerFwk SetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode AihdrEnhancerFwk::GetParameter(int& parameter) const
{
parameter = parameter_;
VPE_LOGI("AihdrEnhancerFwk GetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode AihdrEnhancerFwk::Process(const sptr<SurfaceBuffer>& input)
{
CHECK_AND_RETURN_RET_LOG(input != nullptr, VPE_ALGO_ERR_INVALID_VAL, "Input is nullptr");
VPEAlgoErrCode ret = Init(input);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Init failed");
VPE_SYNC_TRACE;
ret = impl_->Process(input);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Process failed, ret: %{public}d", ret);
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode AihdrEnhancerFwk::Init(const sptr<SurfaceBuffer>& input)
{
if (initialized_) {
impl_->SetParameter(parameter_);
return VPE_ALGO_ERR_OK;
}
auto &manager = Extension::ExtensionManager::GetInstance();
VPE_SYNC_TRACE;
FrameInfo info(input);
impl_ = manager.CreateAihdrEnhancer(info, extensionInfo_);
CHECK_AND_RETURN_RET_LOG(impl_ != nullptr, VPE_ALGO_ERR_NOT_IMPLEMENTED, "Create failed");
int32_t ret = impl_->Init();
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_NOT_IMPLEMENTED, "Init failed");
impl_->SetParameter(parameter_);
initialized_ = true;
VPE_LOGI("AihdrEnhancerFwk Init Succeed");
return VPE_ALGO_ERR_OK;
}
std::shared_ptr<AihdrEnhancer> AihdrEnhancer::Create()
{
auto p = std::make_shared<AihdrEnhancerFwk>();
CHECK_AND_RETURN_RET_LOG(p != nullptr, nullptr, "Create AihdrEnhancer failed");
return std::static_pointer_cast<AihdrEnhancer>(p);
}
int32_t AihdrEnhancerCreate(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
auto p = AihdrEnhancer::Create();
CHECK_AND_RETURN_RET_LOG(p != nullptr, VPE_ALGO_ERR_INVALID_VAL, "cannot create instance");
Extension::ExtensionManager::InstanceVariableType instanceVar { p };
int32_t newId = Extension::ExtensionManager::GetInstance().NewInstanceId(instanceVar);
CHECK_AND_RETURN_RET_LOG(newId != -1, VPE_ALGO_ERR_NO_MEMORY, "cannot create more instance");
*instance = newId;
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerProcessImage(int32_t instance, OHNativeWindowBuffer* inputImage)
{
CHECK_AND_RETURN_RET_LOG((inputImage != nullptr), VPE_ALGO_ERR_INVALID_VAL,
"invalid parameters");
auto someInstance = Extension::ExtensionManager::GetInstance().GetInstance(instance);
CHECK_AND_RETURN_RET_LOG(someInstance != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
VPEAlgoErrCode ret = VPE_ALGO_ERR_INVALID_VAL;
auto visitFunc = [inputImage, &ret](auto&& var) {
using VarType = std::decay_t<decltype(var)>;
if constexpr (std::is_same_v<VarType, std::shared_ptr<AihdrEnhancer>>) {
OH_NativeBuffer* inputImageNativeBuffer = nullptr;
CHECK_AND_RETURN_LOG(
(OH_NativeBuffer_FromNativeWindowBuffer(inputImage, &inputImageNativeBuffer) == GSERROR_OK),
"invalid input image");
sptr<SurfaceBuffer> inputImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(inputImageNativeBuffer));
ret = var->Process(inputImageSurfaceBuffer);
} else {
VPE_LOGE("instance may be miss used");
}
};
std::visit(visitFunc, *someInstance);
return ret;
}
int32_t AihdrEnhancerDestroy(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "instance is null");
return Extension::ExtensionManager::GetInstance().RemoveInstanceReference(*instance);
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -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 AIHDR_ENHANCER_BASE_H
#define AIHDR_ENHANCER_BASE_H
#include <functional>
#include <memory>
#include "nocopyable.h"
#include "frame_info.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class AihdrEnhancerBase : public NoCopyable {
public:
virtual ~AihdrEnhancerBase() = default;
virtual VPEAlgoErrCode Init() = 0;
virtual VPEAlgoErrCode Deinit() = 0;
virtual VPEAlgoErrCode SetParameter(const int& parameter) = 0;
virtual VPEAlgoErrCode GetParameter(int& parameter) = 0;
virtual VPEAlgoErrCode Process(const sptr<SurfaceBuffer>& input) = 0;
};
using AihdrEnhancerCreator = std::function<std::shared_ptr<AihdrEnhancerBase>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // AIHDR_ENHANCER_BASE_H
@@ -0,0 +1,39 @@
/*
* 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 AIHDR_ENHANCER_CAPABILITY_H
#define AIHDR_ENHANCER_CAPABILITY_H
#include <functional>
#include <vector>
#include "frame_info.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
struct AihdrEnhancerCapability {
ColorSpaceDescription colorspaceDesc;
std::vector<GraphicPixelFormat> pixelFormats;
uint32_t rank;
int32_t version;
};
using AihdrEnhancerCapabilitiesBuilder = std::function<std::vector<AihdrEnhancerCapability>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // AIHDR_ENHANCER_CAPABILITY_H
@@ -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.
*/
#ifndef AIHDR_ENHANCER_FWK_H
#define AIHDR_ENHANCER_FWK_H
#include <atomic>
#include <memory>
#include <optional>
#include "aihdr_enhancer.h"
#include "aihdr_enhancer_base.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class AihdrEnhancerFwk : public AihdrEnhancer {
public:
AihdrEnhancerFwk();
~AihdrEnhancerFwk();
VPEAlgoErrCode SetParameter(const int& parameter) override;
VPEAlgoErrCode GetParameter(int& parameter) const override;
VPEAlgoErrCode Process(const sptr<SurfaceBuffer>& input) override;
private:
VPEAlgoErrCode Init(const sptr<SurfaceBuffer>& input);
std::shared_ptr<AihdrEnhancerBase> impl_ { nullptr };
int parameter_{};
std::atomic<bool> initialized_ { false };
Extension::ExtensionInfo extensionInfo_;
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // AIHDR_ENHANCER_FWK_H
@@ -0,0 +1,626 @@
/*
* 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 "aihdr_enhancer_video_impl.h"
#include <algorithm>
#include <cstring>
#include <limits>
#include <memory>
#include "native_window.h"
#include "securec.h"
#include "surface.h"
#include "algorithm_common.h"
#include "algorithm_errors.h"
#include "algorithm_utils.h"
#include "extension_manager.h"
#include "vpe_log.h"
#include "vpe_trace.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
std::shared_ptr<AihdrEnhancerVideo> AihdrEnhancerVideo::Create()
{
std::shared_ptr<AihdrEnhancerVideoImpl> impl = std::make_shared<AihdrEnhancerVideoImpl>();
int32_t ret = impl->Init();
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, nullptr, "failed to init AihdrEnhancerVideoImpl");
return impl;
}
AihdrEnhancerVideoImpl::AihdrEnhancerVideoImpl()
{
requestCfg_.timeout = 0;
requestCfg_.strideAlignment = 32; // 32 内存对齐
requestCfg_.usage = 0;
requestCfg_.format = 0;
requestCfg_.width = 0;
requestCfg_.height = 0;
flushCfg_.timestamp = 0;
flushCfg_.damage.x = 0;
flushCfg_.damage.y = 0;
flushCfg_.damage.w = 0;
flushCfg_.damage.h = 0;
}
AihdrEnhancerVideoImpl::~AihdrEnhancerVideoImpl()
{
Release();
}
int32_t AihdrEnhancerVideoImpl::Init()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::UNINITIALIZED, VPE_ALGO_ERR_INVALID_STATE,
"Init failed: not in UNINITIALIZED state");
csc_ = AihdrEnhancer::Create();
CHECK_AND_RETURN_RET_LOG(csc_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "AihdrEnhancer Create failed");
isRunning_.store(true);
taskThread_ = std::make_shared<std::thread>(&AihdrEnhancerVideoImpl::OnTriggered, this);
CHECK_AND_RETURN_RET_LOG(taskThread_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "Fatal: No memory");
state_ = VPEAlgoState::INITIALIZED;
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::SetCallback(const std::shared_ptr<AihdrEnhancerVideoCallback> &callback)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(callback != nullptr, VPE_ALGO_ERR_INVALID_VAL, "Set callback failed: callback is NULL");
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING,
VPE_ALGO_ERR_INVALID_STATE, "SetCallback failed: not in INITIALIZED or CONFIGURING state");
cb_ = callback;
state_ = VPEAlgoState::CONFIGURING;
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::AttachToNewSurface(sptr<Surface> newSurface)
{
std::lock_guard<std::mutex> lockrender(renderQueMutex_);
for (auto it = outputBufferAvilQueBak_.begin(); it != outputBufferAvilQueBak_.end(); ++it) {
auto buffer = it->second;
GSError err = newSurface->AttachBufferToQueue(buffer->memory);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "outputbuffer AttachToNewSurface fail");
}
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::GetReleaseOutBuffer()
{
std::lock_guard<std::mutex> mapLock(renderQueMutex_);
for (RenderBufferAvilMapType::iterator it = renderBufferMapBak_.begin(); it != renderBufferMapBak_.end(); ++it) {
outputBufferAvilQue_.push(it->second);
}
renderBufferMapBak_.clear();
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::SetOutputSurfaceConfig(sptr<Surface> surface)
{
GSError err = surface->RegisterReleaseListener([this](sptr<SurfaceBuffer> &buffer) {
(void)buffer;
return OnProducerBufferReleased();
});
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "RegisterReleaseListener fail");
surface->SetQueueSize(outBufferCnt_);
outputSurface_ = surface;
state_ = VPEAlgoState::CONFIGURING;
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::SetOutputSurfaceRunning(sptr<Surface> newSurface)
{
std::lock_guard<std::mutex> lockSurface(surfaceChangeMutex_);
std::lock_guard<std::mutex> lockSurface2(surfaceChangeMutex2_);
uint64_t oldId = outputSurface_->GetUniqueId();
uint64_t newId = newSurface->GetUniqueId();
CHECK_AND_RETURN_RET_LOG(oldId != newId, VPE_ALGO_ERR_OK, "SetOutputSurfaceRunning same surface");
outputSurface_->UnRegisterReleaseListener();
outputSurface_->CleanCache(true);
GSError err = newSurface->RegisterReleaseListener([this](sptr<SurfaceBuffer> &buffer) {
(void)buffer;
return OnProducerBufferReleased();
});
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "RegisterReleaseListener fail");
newSurface->SetQueueSize(outBufferCnt_);
newSurface->Connect();
newSurface->CleanCache();
GetReleaseOutBuffer();
int32_t ret = AttachToNewSurface(newSurface);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Attach new surface fail");
GraphicTransformType inTransform;
ScalingMode inScaleMode;
inTransform = inputSurface_->GetTransform();
outputSurface_ = newSurface;
err = outputSurface_->SetTransform(inTransform);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "SetTransform fail");
if (lastSurfaceSequence_ != MAX_SURFACE_SEQUENCE) {
err = inputSurface_->GetScalingMode(lastSurfaceSequence_, inScaleMode);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "GetScalingMode fail");
err = outputSurface_->SetScalingMode(inScaleMode);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "SetScalingMode fail");
}
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::SetOutputSurface(sptr<Surface> surface)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(surface != nullptr, VPE_ALGO_ERR_INVALID_VAL, "surface is nullptr");
CHECK_AND_RETURN_RET_LOG(surface->IsConsumer() == false, VPE_ALGO_ERR_INVALID_VAL, "surface is not producer");
if (state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING) {
int32_t ret = SetOutputSurfaceConfig(surface);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_INVALID_STATE, "SetOutputSurface config fail");
} else if (state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS || state_ == VPEAlgoState::FLUSHED) {
int32_t ret = SetOutputSurfaceRunning(surface);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_INVALID_STATE, "SetOutputSurface Running fail");
} else {
CHECK_AND_RETURN_RET_LOG(false, VPE_ALGO_ERR_INVALID_STATE, "surface state not support SetOutputSurface");
}
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::SetSurface(const OHNativeWindow* window)
{
CHECK_AND_RETURN_RET_LOG(window != nullptr && window->surface != nullptr, VPE_ALGO_ERR_INVALID_PARAM,
"window is null or surface buffer is null!");
return SetOutputSurface(window->surface);
}
sptr<Surface> AihdrEnhancerVideoImpl::CreateInputSurface()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING, nullptr,
"CreateInputSurface failed: not in INITIALIZED or CONFIGURING state");
CHECK_AND_RETURN_RET_LOG(inputSurface_ == nullptr, nullptr, "inputSurface already exists");
inputSurface_ = Surface::CreateSurfaceAsConsumer("ConvertInputSurface");
CHECK_AND_RETURN_RET_LOG(inputSurface_ != nullptr, nullptr, "CreateSurfaceAsConsumer fail");
sptr<IBufferConsumerListener> listener = new AihdrEnhancerBufferConsumerListener(this);
GSError err = inputSurface_->RegisterConsumerListener(listener);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, nullptr, "RegisterConsumerListener fail");
sptr<IBufferProducer> producer = inputSurface_->GetProducer();
sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(producer);
CHECK_AND_RETURN_RET_LOG(producerSurface != nullptr, nullptr, "CreateSurfaceAsProducer fail");
producerSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_HW_RENDER |
BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE);
inputSurface_->SetQueueSize(inBufferCnt_);
state_ = VPEAlgoState::CONFIGURING;
return producerSurface;
}
int32_t AihdrEnhancerVideoImpl::GetSurface(OHNativeWindow** window)
{
CHECK_AND_RETURN_RET_LOG(window != nullptr, VPE_ALGO_ERR_INVALID_VAL, "window is null!");
sptr<Surface> surface = CreateInputSurface();
CHECK_AND_RETURN_RET_LOG(surface != nullptr, VPE_ALGO_ERR_INVALID_STATE, "get surface failed!");
*window = CreateNativeWindowFromSurface(&surface);
CHECK_AND_RETURN_RET_LOG(*window != nullptr, VPE_ALGO_ERR_INVALID_STATE, "create window failed!");
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::Configure()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING || state_ ==
VPEAlgoState::STOPPED, VPE_ALGO_ERR_INVALID_STATE, "Configure failed: not in INITIALIZED or CONFIGURING state");
int32_t ret = VPE_ALGO_ERR_OK;
state_ = (ret == VPE_ALGO_ERR_OK ? VPEAlgoState::CONFIGURING : VPEAlgoState::ERROR);
return ret;
}
int32_t AihdrEnhancerVideoImpl::Prepare()
{
std::lock_guard<std::mutex> lock(mutex_);
if (state_ == VPEAlgoState::STOPPED) {
state_ = VPEAlgoState::CONFIGURED;
return VPE_ALGO_ERR_OK;
}
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::CONFIGURING, VPE_ALGO_ERR_INVALID_STATE,
"Prepare failed: not in CONFIGURING state");
CHECK_AND_RETURN_RET_LOG(cb_ != nullptr && inputSurface_ != nullptr && outputSurface_ != nullptr,
VPE_ALGO_ERR_INVALID_OPERATION, "Prepare faled: inputSurface or outputSurface or callback is null");
state_ = VPEAlgoState::CONFIGURED;
return VPE_ALGO_ERR_OK;
}
void AihdrEnhancerVideoImpl::InitBuffers()
{
flushCfg_.damage.x = 0;
flushCfg_.damage.y = 0;
flushCfg_.damage.w = requestCfg_.width;
flushCfg_.damage.h = requestCfg_.height;
for (uint32_t i = 0; i < outBufferCnt_; ++i) {
std::shared_ptr<SurfaceBufferWrapper> buffer = std::make_shared<SurfaceBufferWrapper>();
GSError err = outputSurface_->RequestBuffer(buffer->memory, buffer->fence, requestCfg_);
if (err != GSERROR_OK || buffer->memory == nullptr) {
VPE_LOGW("RequestBuffer %{public}u failed, GSError=%{public}d", i, err);
continue;
}
outputBufferAvilQue_.push(buffer);
outputBufferAvilQueBak_.insert(std::make_pair(buffer->memory->GetSeqNum(), buffer));
}
}
int32_t AihdrEnhancerVideoImpl::Start()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(
(state_ == VPEAlgoState::CONFIGURED || state_ == VPEAlgoState::STOPPED || state_ == VPEAlgoState::FLUSHED),
VPE_ALGO_ERR_INVALID_STATE,
"Start failed: not in CONFIGURED or STOPPED state");
if (isEos_.load()) {
state_ = VPEAlgoState::EOS;
} else {
state_ = VPEAlgoState::RUNNING;
}
cb_->OnState(static_cast<int32_t>(state_.load()));
cvTaskStart_.notify_all();
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::Stop()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(
state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS || state_ == VPEAlgoState::FLUSHED,
VPE_ALGO_ERR_INVALID_STATE,
"Stop failed: not in RUNNING or EOS state");
state_ = VPEAlgoState::STOPPED;
if (!isProcessing_) {
cb_->OnState(static_cast<int32_t>(state_.load()));
}
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::Reset()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(
state_ != VPEAlgoState::UNINITIALIZED, VPE_ALGO_ERR_INVALID_STATE, "Start failed: not in right state");
std::unique_lock<std::mutex> lockTask(mtxTaskDone_);
state_ = VPEAlgoState::INITIALIZED;
cvTaskDone_.wait(lockTask, [this]() { return isProcessing_.load() == false; });
csc_ = AihdrEnhancer::Create();
CHECK_AND_RETURN_RET_LOG(csc_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "ColorSpaceConverter Create failed");
isEos_.store(false);
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::Release()
{
std::lock_guard<std::mutex> lock(mutex_);
{
std::unique_lock<std::mutex> lockTask(mtxTaskDone_);
state_ = VPEAlgoState::UNINITIALIZED;
cvTaskDone_.wait(lockTask, [this]() { return isProcessing_.load() == false; });
inputSurface_ = nullptr;
std::unique_lock<std::mutex> lockSurface(surfaceChangeMutex_);
std::unique_lock<std::mutex> lockSurface2(surfaceChangeMutex2_);
if (outputSurface_ != nullptr) {
outputSurface_->UnRegisterReleaseListener();
outputSurface_->CleanCache(true);
outputSurface_ = nullptr;
}
lockSurface2.unlock();
lockSurface.unlock();
cb_ = nullptr;
csc_ = nullptr;
isRunning_.store(false);
}
if (taskThread_ != nullptr && taskThread_->joinable()) {
cvTaskStart_.notify_all();
taskThread_->join();
}
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::Flush()
{
std::lock_guard<std::mutex> lock(mutex_);
{
std::unique_lock<std::mutex> lockTask(mtxTaskDone_);
cvTaskDone_.wait(lockTask, [this]() { return isProcessing_.load() == false; });
}
{
std::unique_lock<std::mutex> lockInQue(onBqMutex_);
std::queue<std::shared_ptr<SurfaceBufferWrapper>> tempQueue;
inputBufferAvilQue_.swap(tempQueue);
for (; tempQueue.size() != 0;) {
auto buffer = tempQueue.front();
tempQueue.pop();
CHECK_AND_RETURN_RET_LOG(buffer && buffer->memory != nullptr, VPE_ALGO_ERR_UNKNOWN, "Invalid memory");
GSError err = inputSurface_->ReleaseBuffer(buffer->memory, -1);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "Release buffer failed");
}
}
std::lock_guard<std::mutex> mapLock(renderQueMutex_);
for (auto &[id, buffer] : renderBufferAvilMap_) {
VPE_LOGD("Reclaim buffer %{public}" PRIu64, id);
outputBufferAvilQue_.push(buffer);
}
renderBufferAvilMap_.clear();
state_ = VPEAlgoState::FLUSHED;
return VPE_ALGO_ERR_OK;
}
void AihdrEnhancerVideoImpl::Process(std::shared_ptr<SurfaceBufferWrapper> inputBuffer,
std::shared_ptr<SurfaceBufferWrapper> outputBuffer)
{
VPETrace videoTrace("AihdrEnhancerVideoImpl::Process");
int32_t ret = VPE_ALGO_ERR_EXTENSION_PROCESS_FAILED;
outputBuffer->timestamp = inputBuffer->timestamp;
sptr<SurfaceBuffer> surfaceInputBuffer = inputBuffer->memory;
sptr<SurfaceBuffer> surfaceOutputBuffer = outputBuffer->memory;
bool copyRet = AlgorithmUtils::CopySurfaceBufferToSurfaceBuffer(surfaceInputBuffer, surfaceOutputBuffer);
if (!copyRet) {
requestCfg_.width = surfaceInputBuffer->GetWidth();
requestCfg_.height = surfaceInputBuffer->GetHeight();
requestCfg_.format = surfaceInputBuffer->GetFormat();
surfaceOutputBuffer->EraseMetadataKey(ATTRKEY_COLORSPACE_INFO);
surfaceOutputBuffer->EraseMetadataKey(ATTRKEY_HDR_METADATA_TYPE);
if (surfaceOutputBuffer->Alloc(requestCfg_) == GSERROR_OK) {
copyRet = AlgorithmUtils::CopySurfaceBufferToSurfaceBuffer(surfaceInputBuffer, surfaceOutputBuffer);
}
}
if (copyRet) {
VPETrace cscTrace("AihdrEnhancerVideoImpl::csc_->Process");
ret = csc_->Process(surfaceOutputBuffer);
}
if (ret != 0 && cb_) {
cb_->OnError(ret);
}
inputSurface_->ReleaseBuffer(surfaceInputBuffer, -1);
if (!ret) {
std::unique_lock<std::mutex> lockOnBq(renderQueMutex_);
renderBufferAvilMap_.emplace(outputBuffer->memory->GetSeqNum(), outputBuffer);
} else {
std::lock_guard<std::mutex> renderLock(renderQueMutex_);
outputBufferAvilQue_.push(outputBuffer);
}
if (!ret && cb_) {
cb_->OnOutputBufferAvailable(surfaceOutputBuffer->GetSeqNum(), outputBuffer->bufferFlag);
}
}
bool AihdrEnhancerVideoImpl::WaitProcessing()
{
if (!isRunning_.load()) {
return false;
}
{
std::unique_lock<std::mutex> lock(mtxTaskStart_);
cvTaskStart_.wait(lock, [this]() {
std::lock_guard<std::mutex> inQueueLock(onBqMutex_);
std::lock_guard<std::mutex> outQueueLock(renderQueMutex_);
if (initBuffer_.load()) {
InitBuffers();
initBuffer_.store(false);
}
return ((inputBufferAvilQue_.size() > 0 && outputBufferAvilQue_.size() > 0) || !isRunning_.load());
});
}
return true;
}
bool AihdrEnhancerVideoImpl::AcquireInputOutputBuffers(std::shared_ptr<SurfaceBufferWrapper>& inputBuffer,
std::shared_ptr<SurfaceBufferWrapper>& outputBuffer)
{
std::lock_guard<std::mutex> lockOnBq(onBqMutex_);
std::lock_guard<std::mutex> mapLock(renderQueMutex_);
if (inputBufferAvilQue_.size() == 0 || outputBufferAvilQue_.size() == 0) {
if (state_ == VPEAlgoState::STOPPED) {
cb_->OnState(static_cast<int32_t>(state_.load()));
}
return false;
}
inputBuffer = inputBufferAvilQue_.front();
outputBuffer = outputBufferAvilQue_.front();
inputBufferAvilQue_.pop();
outputBufferAvilQue_.pop();
return inputBuffer && outputBuffer;
}
void AihdrEnhancerVideoImpl::DoTask()
{
std::shared_ptr<SurfaceBufferWrapper> inputBuffer = nullptr;
std::shared_ptr<SurfaceBufferWrapper> outputBuffer = nullptr;
while (true) {
std::lock_guard<std::mutex> lockTask(mtxTaskDone_);
if (!isRunning_.load()) {
return;
}
isProcessing_.store(true);
if (!AcquireInputOutputBuffers(inputBuffer, outputBuffer)) {
break;
}
if (inputBuffer->bufferFlag == AIHDR_ENHANCER_BUFFER_FLAG_EOS) {
{
std::unique_lock<std::mutex> lockOnBq(renderQueMutex_);
renderBufferAvilMap_.emplace(outputBuffer->memory->GetSeqNum(), outputBuffer);
}
if (cb_) {
cb_->OnOutputBufferAvailable(outputBuffer->memory->GetSeqNum(), AIHDR_ENHANCER_BUFFER_FLAG_EOS);
}
break;
}
Process(inputBuffer, outputBuffer);
}
isProcessing_.store(false);
cvTaskDone_.notify_all();
}
void AihdrEnhancerVideoImpl::OnTriggered()
{
while (true) {
if (!WaitProcessing()) {
break;
}
DoTask();
}
}
int32_t AihdrEnhancerVideoImpl::ReleaseOutputBuffer(uint32_t index, bool render)
{
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS, VPE_ALGO_ERR_INVALID_STATE,
"ReleaseOutputBuffer failed: not in RUNNING or EOS state");
std::unique_lock<std::mutex> lockRenderQue(renderQueMutex_);
auto search = renderBufferAvilMap_.find(index);
if (search == renderBufferAvilMap_.end()) {
VPE_LOGE("ReleaseOutputBuffer invalid index %{public}d ", index);
return VPE_ALGO_ERR_INVALID_PARAM;
}
auto buffer = search->second;
renderBufferAvilMap_.erase(search);
lockRenderQue.unlock();
if (render) {
flushCfg_.timestamp = buffer->timestamp;
{
std::lock_guard<std::mutex> lockSurface(surfaceChangeMutex_);
CHECK_AND_RETURN_RET_LOG(outputSurface_ != nullptr, GSERROR_OK, "outputSurface_ is nullptr");
auto ret = outputSurface_->FlushBuffer(buffer->memory, -1, flushCfg_);
if (ret != 0) {
VPE_LOGE("ReleaseOutputBuffer flushbuffer err %{public}d ", (int)ret);
return VPE_ALGO_ERR_UNKNOWN;
}
}
std::lock_guard<std::mutex> renderLock(renderQueMutex_);
renderBufferMapBak_.emplace(buffer->memory->GetSeqNum(), buffer);
} else {
std::lock_guard<std::mutex> renderLock(renderQueMutex_);
outputBufferAvilQue_.push(buffer);
}
return VPE_ALGO_ERR_OK;
}
int32_t AihdrEnhancerVideoImpl::NotifyEos()
{
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard<std::mutex> lockOnBq(onBqMutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::RUNNING, VPE_ALGO_ERR_INVALID_STATE,
"NotifyEos failed: not in RUNNING state");
state_ = VPEAlgoState::EOS;
isEos_.store(true);
std::shared_ptr<SurfaceBufferWrapper> buf = std::make_shared<SurfaceBufferWrapper>();
buf->bufferFlag = AIHDR_ENHANCER_BUFFER_FLAG_EOS;
inputBufferAvilQue_.push(buf);
cvTaskStart_.notify_all();
return VPE_ALGO_ERR_OK;
}
GSError AihdrEnhancerVideoImpl::OnProducerBufferReleased()
{
{
std::unique_lock<std::mutex> lockSurface(surfaceChangeMutex2_);
std::lock_guard<std::mutex> outQueLock(renderQueMutex_);
std::shared_ptr<SurfaceBufferWrapper> buf = std::make_shared<SurfaceBufferWrapper>();
CHECK_AND_RETURN_RET_LOG(outputSurface_ != nullptr, GSERROR_OK, "outputSurface_ is nullptr");
if (renderBufferMapBak_.empty()) {
return GSERROR_OK;
}
GSError err = outputSurface_->RequestBuffer(buf->memory, buf->fence, requestCfg_);
if (err != GSERROR_OK || buf->memory == nullptr) {
VPE_LOGE("RequestBuffer failed, GSError=%{public}d", err);
return err;
}
lockSurface.unlock();
outputBufferAvilQue_.push(buf);
auto bufSeqNum = buf->memory->GetSeqNum();
lastSurfaceSequence_ = bufSeqNum;
renderBufferMapBak_.erase(bufSeqNum);
auto it = outputBufferAvilQueBak_.find(bufSeqNum);
if (it == outputBufferAvilQueBak_.end()) {
outputBufferAvilQueBak_.insert(std::make_pair(bufSeqNum, buf));
auto firstSeqNum = renderBufferMapBak_.begin();
if (firstSeqNum != renderBufferMapBak_.end()) {
outputBufferAvilQueBak_.erase(firstSeqNum->first);
renderBufferMapBak_.erase(firstSeqNum->first);
}
}
}
if (state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS) {
cvTaskStart_.notify_all();
}
return GSERROR_OK;
}
GSError AihdrEnhancerVideoImpl::OnConsumerBufferAvailable()
{
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard<std::mutex> lockInQue(onBqMutex_);
CHECK_AND_RETURN_RET_LOG(inputSurface_ != nullptr, GSERROR_OK, "inputSurface is nullptr");
CHECK_AND_RETURN_RET_LOG(state_ != VPEAlgoState::STOPPED, GSERROR_OK, "state change to stop");
std::shared_ptr<SurfaceBufferWrapper> buffer = std::make_shared<SurfaceBufferWrapper>();
OHOS::Rect damage;
GSError err = inputSurface_->AcquireBuffer(buffer->memory, buffer->fence, buffer->timestamp, damage);
if (err != GSERROR_OK || buffer->memory == nullptr) {
VPE_LOGW("AcquireBuffer failed, GSError=%{public}d", err);
return err;
}
inputBufferAvilQue_.push(buffer);
if (!getUsage_) {
requestCfg_.usage = (buffer->memory->GetUsage() | requestCfg_.usage);
getUsage_ = true;
requestCfg_.width = buffer->memory->GetWidth();
requestCfg_.height = buffer->memory->GetHeight();
requestCfg_.format = buffer->memory->GetFormat();
initBuffer_.store(true);
}
if (state_ == VPEAlgoState::RUNNING) {
cvTaskStart_.notify_all();
}
return GSERROR_OK;
}
void AihdrEnhancerBufferConsumerListener::OnBufferAvailable()
{
if (process_ != nullptr) {
process_->OnConsumerBufferAvailable();
}
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,134 @@
/*
* 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 AIHDR_ENHANCER_VIDEO_IMPL_H
#define AIHDR_ENHANCER_VIDEO_IMPL_H
#include <functional>
#include <limits>
#include <map>
#include <mutex>
#include <queue>
#include "native_window.h"
#include "surface.h"
#include "sync_fence.h"
#include "aihdr_enhancer.h"
#include "aihdr_enhancer_video.h"
#include "aihdr_enhancer_video_common.h"
#include "algorithm_video_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class AihdrEnhancerVideoImpl : public AihdrEnhancerVideo {
public:
AihdrEnhancerVideoImpl();
~AihdrEnhancerVideoImpl();
int32_t Init();
// 北向调用接口
int32_t SetCallback(const std::shared_ptr<AihdrEnhancerVideoCallback> &callback) override;
int32_t SetOutputSurface(sptr<Surface> surface);
sptr<Surface> CreateInputSurface();
int32_t SetSurface(const OHNativeWindow* window) override;
int32_t GetSurface(OHNativeWindow** window) override;
int32_t Configure() override;
int32_t Prepare() override;
int32_t Start() override;
int32_t Stop() override;
int32_t Reset() override;
int32_t Release() override;
int32_t NotifyEos() override;
int32_t ReleaseOutputBuffer(uint32_t index, bool render) override;
int32_t Flush() override;
GSError OnConsumerBufferAvailable();
GSError OnProducerBufferReleased();
private:
struct SurfaceBufferWrapper {
public:
SurfaceBufferWrapper() = default;
~SurfaceBufferWrapper() = default;
sptr<SurfaceBuffer> memory{nullptr};
AihdrEnhancerBufferFlag bufferFlag{AIHDR_ENHANCER_BUFFER_FLAG_NONE};
sptr<SyncFence> fence{nullptr};
int64_t timestamp;
};
void InitBuffers();
bool WaitProcessing();
bool AcquireInputOutputBuffers(
std::shared_ptr<SurfaceBufferWrapper> &inputBuffer, std::shared_ptr<SurfaceBufferWrapper> &outputBuffer);
void DoTask();
void OnTriggered();
void Process(std::shared_ptr<SurfaceBufferWrapper> inputBuffer, std::shared_ptr<SurfaceBufferWrapper> outputBuffer);
int32_t AttachToNewSurface(sptr<Surface> newSurface);
int32_t SetOutputSurfaceConfig(sptr<Surface> surface);
int32_t SetOutputSurfaceRunning(sptr<Surface> newSurface);
int32_t GetReleaseOutBuffer();
std::atomic<VPEAlgoState> state_{VPEAlgoState::UNINITIALIZED};
std::shared_ptr<AihdrEnhancerVideoCallback> cb_{nullptr};
std::shared_ptr<AihdrEnhancer> csc_{nullptr};
std::mutex mutex_;
bool getUsage_{false};
std::atomic<bool> initBuffer_{false};
// task相关
std::mutex mtxTaskDone_;
std::condition_variable cvTaskDone_;
std::shared_ptr<std::thread> taskThread_{nullptr};
std::condition_variable cvTaskStart_;
std::mutex mtxTaskStart_;
std::atomic<bool> isRunning_{false};
std::atomic<bool> isProcessing_{false};
std::atomic<bool> isEos_{false};
// surface相关
std::queue<std::shared_ptr<SurfaceBufferWrapper>> outputBufferAvilQue_;
std::queue<std::shared_ptr<SurfaceBufferWrapper>> inputBufferAvilQue_;
std::queue<std::shared_ptr<SurfaceBufferWrapper>> renderBufferAvilQue_;
using RenderBufferAvilMapType = std::map<uint64_t, std::shared_ptr<SurfaceBufferWrapper>>;
RenderBufferAvilMapType renderBufferAvilMap_;
RenderBufferAvilMapType renderBufferMapBak_;
RenderBufferAvilMapType outputBufferAvilQueBak_;
std::mutex onBqMutex_; // inputsruface buffer
std::mutex renderQueMutex_; // outputsruface buffer
std::mutex surfaceChangeMutex_;
std::mutex surfaceChangeMutex2_;
sptr<Surface> inputSurface_{nullptr};
sptr<Surface> outputSurface_{nullptr};
static constexpr size_t MAX_BUFFER_CNT{5};
uint32_t outBufferCnt_{MAX_BUFFER_CNT};
uint32_t inBufferCnt_{MAX_BUFFER_CNT};
static constexpr size_t MAX_SURFACE_SEQUENCE{std::numeric_limits<uint32_t>::max()};
uint32_t lastSurfaceSequence_{MAX_SURFACE_SEQUENCE};
BufferRequestConfig requestCfg_{};
BufferFlushConfig flushCfg_{};
};
class AihdrEnhancerBufferConsumerListener : public OHOS::IBufferConsumerListener {
public:
explicit AihdrEnhancerBufferConsumerListener(AihdrEnhancerVideoImpl *process) : process_(process) {}
void OnBufferAvailable() override;
private:
AihdrEnhancerVideoImpl *process_;
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // AIHDR_ENHANCER_VIDEO_IMPL_H
@@ -0,0 +1,358 @@
/*
* 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.
*/
#include <dlfcn.h>
#include "colorspace_converter_fwk.h"
#include "extension_manager.h"
#include "native_buffer.h"
#include "surface_buffer.h"
#include "vpe_trace.h"
#include "vpe_log.h"
#include "EGL/egl.h"
#include "surface_buffer_info.h"
#include "video_processing_client.h"
#include <unistd.h>
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
ColorSpaceConverterFwk::ColorSpaceConverterFwk()
{
OpenCLInit();
OpenGLInit();
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
void ColorSpaceConverterFwk::OpenCLInit()
{
void *OpenclFoundationHandle = nullptr;
std::string path = "/sys_prod/lib64/VideoProcessingEngine/libaihdr_engine.so";
auto ret = access(path.c_str(), F_OK);
if (ret != 0) {
VPE_LOGW("access = %d path = %s", ret, path.c_str());
} else {
constexpr int DEVICE_NAME_LENGTH = 32; // 32 max name length
char deviceName[DEVICE_NAME_LENGTH];
auto status = SetupOpencl(&OpenclFoundationHandle, "HUA", deviceName);
if (status != static_cast<int>(CL_SUCCESS)) {
VPE_LOGE("%{public}s, Error: setupOpencl status=%{public}d\n", __FUNCTION__, status);
}
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Connect();
VPE_LOGI("VPE Framework connect and load SA!");
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Disconnect();
}
context.clContext = reinterpret_cast<ClContext *>(OpenclFoundationHandle);
}
void ColorSpaceConverterFwk::OpenGLInit()
{
context.glDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (context.glDisplay == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS) {
VPE_LOGE("ColorSpaceConverterFwk Get display failed!");
}
EGLint major;
EGLint minor;
if (eglInitialize(context.glDisplay, &major, &minor) == EGL_FALSE || eglGetError() != EGL_SUCCESS) {
VPE_LOGE("ColorSpaceConverterFwk eglInitialize failed!");
}
}
ColorSpaceConverterFwk::ColorSpaceConverterFwk(std::shared_ptr<OpenGLContext> openglContext,
ClContext *opengclContext)
{
if (opengclContext != nullptr) {
context.clContext = opengclContext;
}
if (openglContext != nullptr) {
if (openglContext->display != EGL_NO_DISPLAY) {
context.glDisplay = openglContext->display;
}
}
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Connect();
VPE_LOGI("VPE Framework connect and load SA!");
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Disconnect();
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
ColorSpaceConverterFwk::~ColorSpaceConverterFwk()
{
impl_ = nullptr;
for (auto it = impls_.begin(); it != impls_.end(); ++it) {
if (it->second) {
it->second->Deinit();
it->second = nullptr;
}
}
impls_.clear();
CleanOpencl(context.clContext);
Extension::ExtensionManager::GetInstance().DecreaseInstance();
}
VPEAlgoErrCode ColorSpaceConverterFwk::SetParameter(const ColorSpaceConverterParameter &parameter)
{
CHECK_AND_RETURN_RET_LOG(parameter.renderIntent == RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC,
VPE_ALGO_ERR_INVALID_VAL, "Absolute colorimetric is the only supported render intent");
parameter_ = parameter;
VPE_LOGI("ColorSpaceConverterFwk SetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ColorSpaceConverterFwk::GetParameter(ColorSpaceConverterParameter &parameter) const
{
CHECK_AND_RETURN_RET_LOG(parameter_ != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "Parameter is not set");
parameter = *parameter_;
VPE_LOGI("ColorSpaceConverterFwk GetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ColorSpaceConverterFwk::Process(const sptr<SurfaceBuffer> &input, const sptr<SurfaceBuffer> &output)
{
CHECK_AND_RETURN_RET_LOG(parameter_ != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "Parameter is not set");
CHECK_AND_RETURN_RET_LOG((input != nullptr) && (output != nullptr), VPE_ALGO_ERR_INVALID_VAL,
"Input or output is nullptr");
VPEAlgoErrCode ret;
ret = Init(input, output, context);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Init failed, ret: %{public}d", ret);
ret = impl_->SetParameter(*parameter_);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED,
"Set parameter failed, ret: %{public}d", ret);
VPE_SYNC_TRACE;
ret = impl_->Process(input, output);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Process failed, ret: %{public}d", ret);
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ColorSpaceConverterFwk::ComposeImage(const sptr<SurfaceBuffer> &inputSdrImage,
const sptr<SurfaceBuffer> &inputGainmap, const sptr<SurfaceBuffer> &outputHdrImage, bool legacy)
{
CHECK_AND_RETURN_RET_LOG(parameter_ != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "Parameter is not set");
CHECK_AND_RETURN_RET_LOG((inputSdrImage != nullptr) && (inputGainmap != nullptr) && (outputHdrImage != nullptr),
VPE_ALGO_ERR_INVALID_VAL, "Input or output is nullptr");
VPEAlgoErrCode ret = Init(inputSdrImage, outputHdrImage, context);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Init failed, ret: %{public}d", ret);
ret = impl_->SetParameter(*parameter_);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED,
"Set parameter failed, ret: %{public}d", ret);
VPE_SYNC_TRACE;
ret = impl_->ComposeImage(inputSdrImage, inputGainmap, outputHdrImage, legacy);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_UNKNOWN, "Compose image failed, ret: %{public}d",
ret);
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ColorSpaceConverterFwk::DecomposeImage(const sptr<SurfaceBuffer> &inputImage,
const sptr<SurfaceBuffer> &outputSdrImage, const sptr<SurfaceBuffer> &outputGainmap)
{
CHECK_AND_RETURN_RET_LOG(parameter_ != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "Parameter is not set");
CHECK_AND_RETURN_RET_LOG((inputImage != nullptr) && (outputSdrImage != nullptr) && (outputGainmap != nullptr),
VPE_ALGO_ERR_INVALID_VAL, "Input or output is nullptr");
VPEAlgoErrCode ret;
ret = Init(inputImage, outputSdrImage, context);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Init failed, ret: %{public}d", ret);
ret = impl_->SetParameter(*parameter_);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED,
"Set parameter failed, ret: %{public}d", ret);
VPE_SYNC_TRACE;
ret = impl_->DecomposeImage(inputImage, outputSdrImage, outputGainmap);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_UNKNOWN, "Decompose image failed, ret: %{public}d",
ret);
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ColorSpaceConverterFwk::Init(const sptr<SurfaceBuffer> &input, const sptr<SurfaceBuffer> &output,
VPEContext ctx)
{
CHECK_AND_RETURN_RET_LOG(context.clContext != nullptr || context.glDisplay != EGL_NO_DISPLAY,
VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED, "opencl or opengl is not initialized!");
auto &manager = Extension::ExtensionManager::GetInstance();
VPE_SYNC_TRACE;
FrameInfo inputInfo(input);
FrameInfo outputInfo(output);
auto currentKey =
std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat, outputInfo.colorSpace, outputInfo.pixelFormat);
auto it = impls_.find(currentKey);
if (it != impls_.end()) {
impl_ = it->second;
VPE_LOGD("ColorSpaceConverterFwk::Init find exist impl");
return VPE_ALGO_ERR_OK;
}
impl_ = manager.CreateColorSpaceConverter(inputInfo, outputInfo, extensionInfo_);
CHECK_AND_RETURN_RET_LOG(impl_ != nullptr, VPE_ALGO_ERR_NOT_IMPLEMENTED,
"Extension create failed, get a empty impl");
VPEAlgoErrCode ret = impl_->Init(inputInfo, outputInfo, ctx);
CHECK_AND_RETURN_RET_LOG(ret == 0, VPE_ALGO_ERR_EXTENSION_INIT_FAILED,
"Init failed, extension: %{public}s, version: %{public}s", extensionInfo_.name.c_str(),
extensionInfo_.version.c_str());
VPE_LOGI("Init successfully, extension: %{public}s, version: %{public}s", extensionInfo_.name.c_str(),
extensionInfo_.version.c_str());
impls_.insert(std::make_pair(currentKey, impl_));
return VPE_ALGO_ERR_OK;
}
std::shared_ptr<ColorSpaceConverter> ColorSpaceConverter::Create()
{
auto p = std::make_shared<ColorSpaceConverterFwk>();
CHECK_AND_RETURN_RET_LOG(p != nullptr, nullptr, "Create failed, maybe caused of no memory");
return std::static_pointer_cast<ColorSpaceConverter>(p);
}
std::shared_ptr<ColorSpaceConverter> ColorSpaceConverter::Create(std::shared_ptr<OpenGLContext> openglContext,
ClContext *opengclContext)
{
auto p = std::make_shared<ColorSpaceConverterFwk>(openglContext, opengclContext);
CHECK_AND_RETURN_RET_LOG(p != nullptr, nullptr, "Create failed, maybe caused of no memory");
return std::static_pointer_cast<ColorSpaceConverter>(p);
}
int32_t ColorSpaceConverterCreate(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
auto p = ColorSpaceConverter::Create();
CHECK_AND_RETURN_RET_LOG(p != nullptr, VPE_ALGO_ERR_INVALID_VAL, "cannot create instance");
Extension::ExtensionManager::InstanceVariableType instanceVar { p };
int32_t newId = Extension::ExtensionManager::GetInstance().NewInstanceId(instanceVar);
CHECK_AND_RETURN_RET_LOG(newId != -1, VPE_ALGO_ERR_NO_MEMORY, "cannot create more instance");
*instance = newId;
return VPE_ALGO_ERR_OK;
}
int32_t ColorSpaceConverterProcessImage(int32_t instance, OHNativeWindowBuffer* inputImage,
OHNativeWindowBuffer* outputImage)
{
CHECK_AND_RETURN_RET_LOG((inputImage != nullptr && outputImage != nullptr), VPE_ALGO_ERR_INVALID_VAL,
"invalid parameters");
auto someInstance = Extension::ExtensionManager::GetInstance().GetInstance(instance);
CHECK_AND_RETURN_RET_LOG(someInstance != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
VPEAlgoErrCode ret = VPE_ALGO_ERR_INVALID_VAL;
auto visitFunc = [inputImage, outputImage, &ret](auto&& var) {
using VarType = std::decay_t<decltype(var)>;
if constexpr (std::is_same_v<VarType, std::shared_ptr<ColorSpaceConverter>>) {
OH_NativeBuffer* inputImageNativeBuffer = nullptr;
OH_NativeBuffer* outputImageNativeBuffer = nullptr;
CHECK_AND_RETURN_LOG(
(OH_NativeBuffer_FromNativeWindowBuffer(inputImage, &inputImageNativeBuffer) == GSERROR_OK) &&
(OH_NativeBuffer_FromNativeWindowBuffer(outputImage, &outputImageNativeBuffer) == GSERROR_OK),
"invalid input or output image");
sptr<SurfaceBuffer> inputImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(inputImageNativeBuffer));
sptr<SurfaceBuffer> outputImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(outputImageNativeBuffer));
(void)var->SetParameter({ RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC, std::nullopt });
ret = var->Process(inputImageSurfaceBuffer, outputImageSurfaceBuffer);
} else {
VPE_LOGE("instance may be miss used");
}
};
std::visit(visitFunc, *someInstance);
return ret;
}
int32_t ColorSpaceConverterComposeImage(int32_t instance, OHNativeWindowBuffer* inputSdrImage,
OHNativeWindowBuffer* inputGainmap, OHNativeWindowBuffer* outputHdrImage, bool legacy)
{
CHECK_AND_RETURN_RET_LOG((inputSdrImage != nullptr && inputGainmap != nullptr && outputHdrImage != nullptr),
VPE_ALGO_ERR_INVALID_VAL, "invalid parameters");
auto someInstance = Extension::ExtensionManager::GetInstance().GetInstance(instance);
CHECK_AND_RETURN_RET_LOG(someInstance != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
VPEAlgoErrCode ret = VPE_ALGO_ERR_INVALID_VAL;
auto visitFunc = [inputSdrImage, inputGainmap, outputHdrImage, legacy, &ret](auto&& var) {
using VarType = std::decay_t<decltype(var)>;
if constexpr (std::is_same_v<VarType, std::shared_ptr<ColorSpaceConverter>>) {
OH_NativeBuffer* inputSdrImageNativeBuffer = nullptr;
OH_NativeBuffer* inputGainmapNativeBuffer = nullptr;
OH_NativeBuffer* outputHdrImageNativeBuffer = nullptr;
CHECK_AND_RETURN_LOG(
(OH_NativeBuffer_FromNativeWindowBuffer(inputSdrImage, &inputSdrImageNativeBuffer) == GSERROR_OK) &&
(OH_NativeBuffer_FromNativeWindowBuffer(inputGainmap, &inputGainmapNativeBuffer) == GSERROR_OK) &&
(OH_NativeBuffer_FromNativeWindowBuffer(outputHdrImage, &outputHdrImageNativeBuffer) == GSERROR_OK),
"invalid input or output image");
sptr<SurfaceBuffer> inputSdrImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(inputSdrImageNativeBuffer));
sptr<SurfaceBuffer> inputGainmapSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(inputGainmapNativeBuffer));
sptr<SurfaceBuffer> outputHdrImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(outputHdrImageNativeBuffer));
(void)var->SetParameter({ RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC, std::nullopt });
ret = var->ComposeImage(inputSdrImageSurfaceBuffer, inputGainmapSurfaceBuffer, outputHdrImageSurfaceBuffer,
legacy);
} else {
VPE_LOGE("instance may be miss used");
}
};
std::visit(visitFunc, *someInstance);
return ret;
}
int32_t ColorSpaceConverterDecomposeImage(int32_t instance, OHNativeWindowBuffer* inputImage,
OHNativeWindowBuffer* outputSdrImage, OHNativeWindowBuffer* outputGainmap)
{
CHECK_AND_RETURN_RET_LOG((inputImage != nullptr && outputSdrImage != nullptr && outputGainmap != nullptr),
VPE_ALGO_ERR_INVALID_VAL, "invalid parameters");
auto someInstance = Extension::ExtensionManager::GetInstance().GetInstance(instance);
CHECK_AND_RETURN_RET_LOG(someInstance != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
VPEAlgoErrCode ret = VPE_ALGO_ERR_INVALID_VAL;
auto visitFunc = [inputImage, outputSdrImage, outputGainmap, &ret](auto&& var) {
using VarType = std::decay_t<decltype(var)>;
if constexpr (std::is_same_v<VarType, std::shared_ptr<ColorSpaceConverter>>) {
OH_NativeBuffer* inputImageNativeBuffer = nullptr;
OH_NativeBuffer* outputSdrImageNativeBuffer = nullptr;
OH_NativeBuffer* outputGainmapNativeBuffer = nullptr;
CHECK_AND_RETURN_LOG(
(OH_NativeBuffer_FromNativeWindowBuffer(inputImage, &inputImageNativeBuffer) == GSERROR_OK) &&
(OH_NativeBuffer_FromNativeWindowBuffer(outputSdrImage, &outputSdrImageNativeBuffer) == GSERROR_OK) &&
(OH_NativeBuffer_FromNativeWindowBuffer(outputGainmap, &outputGainmapNativeBuffer) == GSERROR_OK),
"invalid input or output image");
sptr<SurfaceBuffer> inputImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(inputImageNativeBuffer));
sptr<SurfaceBuffer> outputSdrImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(outputSdrImageNativeBuffer));
sptr<SurfaceBuffer> outputGainmapSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(outputGainmapNativeBuffer));
(void)var->SetParameter({ RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC, std::nullopt });
ret = var->DecomposeImage(inputImageSurfaceBuffer, outputSdrImageSurfaceBuffer, outputGainmapSurfaceBuffer);
} else {
VPE_LOGE("instance may be miss used");
}
};
std::visit(visitFunc, *someInstance);
return ret;
}
int32_t ColorSpaceConverterDestroy(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "instance is null");
return Extension::ExtensionManager::GetInstance().RemoveInstanceReference(*instance);
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,48 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_COLORSPACE_CONVERTER_BASE_H
#define FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_COLORSPACE_CONVERTER_BASE_H
#include <functional>
#include <memory>
#include "nocopyable.h"
#include "frame_info.h"
#include "vpe_context.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class ColorSpaceConverterBase : public NoCopyable {
public:
virtual ~ColorSpaceConverterBase() = default;
virtual VPEAlgoErrCode Init(const FrameInfo &inputFrameInfo, const FrameInfo &outputFrameInfo,
VPEContext context) = 0;
virtual VPEAlgoErrCode Deinit() = 0;
virtual VPEAlgoErrCode SetParameter(const ColorSpaceConverterParameter &parameter) = 0;
virtual VPEAlgoErrCode GetParameter(ColorSpaceConverterParameter &parameter) = 0;
virtual VPEAlgoErrCode Process(const sptr<SurfaceBuffer> &input, const sptr<SurfaceBuffer> &output) = 0;
virtual VPEAlgoErrCode ComposeImage(const sptr<SurfaceBuffer> &inputSdrImage,
const sptr<SurfaceBuffer> &inputGainmap, const sptr<SurfaceBuffer> &outputHdrImage, bool legacy) = 0;
virtual VPEAlgoErrCode DecomposeImage(const sptr<SurfaceBuffer> &inputImage,
const sptr<SurfaceBuffer> &outputSdrImage, const sptr<SurfaceBuffer> &outputGainmap) = 0;
};
using ColorSpaceConverterCreator = std::function<std::shared_ptr<ColorSpaceConverterBase>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_COLORSPACE_CONVERTER_BASE_H
@@ -0,0 +1,62 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_COLORSPACE_CONVERTER_CAPABILITY_H
#define FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_COLORSPACE_CONVERTER_CAPABILITY_H
#include <functional>
#include <vector>
#include "frame_info.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
struct ColorSpaceConverterCapability {
ColorSpaceDescription inputColorSpaceDesc;
ColorSpaceDescription outputColorSpaceDesc;
/*
The key is a supported input pixel format, and the value is a supported output pixel formats' vector.
In json format:
{
supportedInputPixelFormat: [supportedOutputPixelFormat, supportedOutputPixelFormat, ...],
......
}
eg.
Supported input pixel formats are nv21, nv12 and rgba.
When the input pixel format is nv21, the supported output pixel format can be nv21, nv12.
When the input pixel format is nv12, the supported output pixel format can be nv21, nv12 and rgba.
When the input pixel format is rgba, the supported output pixel format can be rgba.
So the keys are nv21, nv12 and rgba, the corresponding value is a vector contains the supported output
pixel formats.
In json format:
{
nv21: [nv21, nv12],
nv12: [nv21, nv12, rgba],
rgba: [rgba],
......
}
*/
std::map<GraphicPixelFormat, std::vector<GraphicPixelFormat>> pixelFormatMap;
uint32_t rank;
int32_t version;
};
using ColorSpaceConverterCapabilitiesBuilder = std::function<std::vector<ColorSpaceConverterCapability>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_COLORSPACE_CONVERTER_CAPABILITY_H
@@ -0,0 +1,77 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_FWK_H
#define FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_FWK_H
#include <atomic>
#include <memory>
#include <optional>
#include "colorspace_converter.h"
#include "colorspace_converter_base.h"
#include "extension_base.h"
#include "metadata_generator.h"
#include "metadata_generator_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
/**
* Process
* 解码后的视频帧转换
* 单层hdr图片 -> sdr图片
* sdr图片 -> 单层hdr图片
* sdr图片 -> sdr图片
* ComposeImage
* 双层hdr图片 -> 单层hdr图片
* DecomposeImage
* 单层hdr图片 -> 双层hdr图片
* sdr图片 -> 双层hdr图片
*/
class ColorSpaceConverterFwk : public ColorSpaceConverter {
public:
ColorSpaceConverterFwk();
ColorSpaceConverterFwk(std::shared_ptr<OpenGLContext> openglContext,
ClContext *opengclContext = nullptr);
~ColorSpaceConverterFwk();
VPEAlgoErrCode SetParameter(const ColorSpaceConverterParameter &parameter) override;
VPEAlgoErrCode GetParameter(ColorSpaceConverterParameter &parameter) const override;
VPEAlgoErrCode Process(const sptr<SurfaceBuffer> &input, const sptr<SurfaceBuffer> &output) override;
VPEAlgoErrCode ComposeImage(const sptr<SurfaceBuffer> &inputSdrImage, const sptr<SurfaceBuffer> &inputGainmap,
const sptr<SurfaceBuffer> &outputHdrImage, bool legacy) override;
VPEAlgoErrCode DecomposeImage(const sptr<SurfaceBuffer> &inputImage, const sptr<SurfaceBuffer> &outputSdrImage,
const sptr<SurfaceBuffer> &outputGainmap) override;
private:
VPEAlgoErrCode Init(const sptr<SurfaceBuffer> &input, const sptr<SurfaceBuffer> &output, VPEContext context);
void OpenGLInit();
void OpenCLInit();
std::shared_ptr<ColorSpaceConverterBase> impl_ { nullptr };
std::optional<ColorSpaceConverterParameter> parameter_ { std::nullopt };
std::atomic<bool> initialized_ { false };
Extension::ExtensionInfo extensionInfo_;
std::map<
std::tuple<ColorSpaceDescription, GraphicPixelFormat, ColorSpaceDescription, GraphicPixelFormat>,
std::shared_ptr<ColorSpaceConverterBase>> impls_;
std::tuple<ColorSpaceDescription, GraphicPixelFormat, ColorSpaceDescription, GraphicPixelFormat>
lastFrameInfoKey_;
VPEContext context;
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_FWK_H
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "colorspace_converter_display_fwk.h"
#include "securec.h"
#include "extension_manager.h"
#include "vpe_parse_metadata.h"
#include "vpe_trace.h"
#include "vpe_log.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
ColorSpaceConverterDisplayFwk::ColorSpaceConverterDisplayFwk()
{
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
ColorSpaceConverterDisplayFwk::~ColorSpaceConverterDisplayFwk()
{
impl_.clear();
Extension::ExtensionManager::GetInstance().DecreaseInstance();
}
VPEAlgoErrCode ColorSpaceConverterDisplayFwk::Process(const std::shared_ptr<OHOS::Rosen::Drawing::ShaderEffect> &input,
std::shared_ptr<OHOS::Rosen::Drawing::ShaderEffect> &output, const ColorSpaceConverterDisplayParameter &parameter)
{
auto ret = Init();
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_INIT_FAILED, "Init failed");
VPE_LOGD("size of impl %{public}lu", impl_.size());
CHECK_AND_RETURN_RET_LOG(!impl_.empty(), VPE_ALGO_ERR_NOT_IMPLEMENTED, "Extension is not found");
DeserializedDisplayParameter localParameter;
DeserializeDisplayParameter(parameter, localParameter);
VPE_SYNC_TRACE;
for (const auto& impl : impl_) {
ret = impl->Process(input, output, localParameter);
if (ret == VPE_ALGO_ERR_OK) {
return VPE_ALGO_ERR_OK;
}
}
VPE_LOGE("The operation is not supported");
return VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED;
}
VPEAlgoErrCode ColorSpaceConverterDisplayFwk::Init()
{
if (initialized_) {
return VPE_ALGO_ERR_OK;
}
auto& manager = Extension::ExtensionManager::GetInstance();
VPE_SYNC_TRACE;
impl_ = manager.CreateColorSpaceConverterDisplay();
CHECK_AND_RETURN_RET_LOG(!impl_.empty(), VPE_ALGO_ERR_NOT_IMPLEMENTED, "Create impl failed");
initialized_ = true;
VPE_LOGI("Successed");
return VPE_ALGO_ERR_OK;
}
void ColorSpaceConverterDisplayFwk::DeserializeDisplayParameter(const ColorSpaceConverterDisplayParameter& parameter,
DeserializedDisplayParameter& deserialzed)
{
deserialzed.inputColorSpace = parameter.inputColorSpace;
deserialzed.outputColorSpace = parameter.outputColorSpace;
deserialzed.sdrNits = parameter.sdrNits;
deserialzed.tmoNits = parameter.tmoNits;
deserialzed.currentDisplayNits = parameter.currentDisplayNits;
deserialzed.disableHdrFloatHeadRoom = parameter.disableHdrFloatHeadRoom;
deserialzed.linearMatrix = parameter.layerLinearMatrix;
DeserializeStaticMetadata(parameter, deserialzed);
DeserializeDynamicMetadata(parameter, deserialzed);
}
void ColorSpaceConverterDisplayFwk::DeserializeStaticMetadata(const ColorSpaceConverterDisplayParameter& parameter,
DeserializedDisplayParameter& deserialzed)
{
if (parameter.staticMetadata.size() == 0) {
deserialzed.staticMetadata = std::nullopt;
return;
}
HdrStaticMetadata data;
errno_t ret = memcpy_s(&data, sizeof(data), parameter.staticMetadata.data(), parameter.staticMetadata.size());
if (ret != EOK) {
VPE_LOGE("memcpy_s failed, err = %d\n", ret);
return;
}
deserialzed.staticMetadata = data;
}
void ColorSpaceConverterDisplayFwk::DeserializeDynamicMetadata(const ColorSpaceConverterDisplayParameter& parameter,
DeserializedDisplayParameter& deserialzed)
{
if (parameter.dynamicMetadata.size() == 0) {
deserialzed.hdrVividMetadata = std::nullopt;
return;
}
HdrVividMetadataV1 data;
HwDisplayMeta displayMeta;
(void)PraseMetadataFromArray(parameter.dynamicMetadata, data, displayMeta);
deserialzed.hdrVividMetadata = data;
deserialzed.displayMeta = displayMeta;
}
std::shared_ptr<ColorSpaceConverterDisplay> ColorSpaceConverterDisplay::Create()
{
auto p = std::make_shared<ColorSpaceConverterDisplayFwk>();
CHECK_AND_RETURN_RET_LOG(p != nullptr, nullptr, "Create failed, maybe caused of no memory");
return std::static_pointer_cast<ColorSpaceConverterDisplay>(p);
}
struct ColorSpaceConvertDisplayHandleImpl {
std::shared_ptr<ColorSpaceConverterDisplayFwk> obj;
};
struct VPEShaderEffectHandleImpl {
std::shared_ptr<OHOS::Rosen::Drawing::ShaderEffect> obj;
};
ColorSpaceConvertDisplayHandle *ColorSpaceConvertDisplayCreate()
{
std::shared_ptr<ColorSpaceConverterDisplayFwk> impl = std::make_shared<ColorSpaceConverterDisplayFwk>();
CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr, "failed to init ColorSpaceConvertDisplayCreate");
auto handle = new ColorSpaceConvertDisplayHandleImpl;
handle->obj = impl;
return static_cast<ColorSpaceConvertDisplayHandle *>(handle);
}
void ColorSpaceConvertDisplayDestroy(ColorSpaceConvertDisplayHandle *handle)
{
VPE_LOGD("call ColorSpaceConvertDisplayDestroy");
if (handle != nullptr) {
auto p = static_cast<ColorSpaceConvertDisplayHandleImpl *>(handle);
delete p;
}
}
VPEAlgoErrCode ColorSpaceConvertDisplayProcess(ColorSpaceConvertDisplayHandle *handle, VPEShaderEffectHandle *input,
VPEShaderEffectHandle *output, const ColorSpaceConverterDisplayParameter &parameter)
{
CHECK_AND_RETURN_RET_LOG(handle != nullptr, VPE_ALGO_ERR_INVALID_PARAM, "Input DisplayHandle in null!");
VPEAlgoErrCode ret = VPE_ALGO_ERR_OK;
auto p = static_cast<ColorSpaceConvertDisplayHandleImpl *>(handle);
auto in = static_cast<VPEShaderEffectHandleImpl *>(input);
auto out = static_cast<VPEShaderEffectHandleImpl *>(output);
ret = p->obj->Process(in->obj, out->obj, parameter);
return ret;
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_BASE_H
#define FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_BASE_H
#include <functional>
#include <memory>
#include "nocopyable.h"
#include "effect/shader_effect.h"
#include "algorithm_common.h"
#include "deserialized_display_parameter.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
using namespace HDI::Display::Graphic::Common::V1_0;
class ColorSpaceConverterDisplayBase : public NoCopyable {
public:
virtual ~ColorSpaceConverterDisplayBase() = default;
virtual VPEAlgoErrCode Process(const std::shared_ptr<OHOS::Rosen::Drawing::ShaderEffect>& input,
std::shared_ptr<OHOS::Rosen::Drawing::ShaderEffect>& output,
const DeserializedDisplayParameter& parameter) = 0;
};
using ColorSpaceConverterDisplayCreator = std::function<std::shared_ptr<ColorSpaceConverterDisplayBase>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_BASE_H
@@ -0,0 +1,41 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_CAPABILITY_H
#define FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_CAPABILITY_H
#include <functional>
#include <vector>
#include "algorithm_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
struct ColorSpaceConverterDisplayCapability {
ColorSpaceDescription inputColorspaceDesc;
ColorSpaceDescription outputColorSpaceDesc;
uint32_t rank;
int32_t version;
};
using ColorSpaceConverterDisplayCapabilitiesBuilder =
std::function<std::vector<ColorSpaceConverterDisplayCapability>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_CAPABILITY_H
@@ -0,0 +1,55 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_FWK_H
#define FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_FWK_H
#include <atomic>
#include <memory>
#include <set>
#include <vector>
#include "effect/shader_effect.h"
#include "colorspace_converter_display.h"
#include "colorspace_converter_display_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class ColorSpaceConverterDisplayFwk : public ColorSpaceConverterDisplay {
public:
ColorSpaceConverterDisplayFwk();
~ColorSpaceConverterDisplayFwk();
VPEAlgoErrCode Process(const std::shared_ptr<OHOS::Rosen::Drawing::ShaderEffect>& input,
std::shared_ptr<OHOS::Rosen::Drawing::ShaderEffect>& output,
const ColorSpaceConverterDisplayParameter& parameter) override;
private:
VPEAlgoErrCode Init();
void DeserializeDisplayParameter(const ColorSpaceConverterDisplayParameter& parameter,
DeserializedDisplayParameter& deserialzed);
void DeserializeStaticMetadata(const ColorSpaceConverterDisplayParameter& parameter,
DeserializedDisplayParameter& deserialzed);
void DeserializeDynamicMetadata(const ColorSpaceConverterDisplayParameter& parameter,
DeserializedDisplayParameter& deserialzed);
std::set<std::shared_ptr<ColorSpaceConverterDisplayBase>> impl_;
std::atomic<bool> initialized_ {false};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_COLORSPACE_CONVERTER_DISPLAY_FWK_H
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef VPE_FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_DESERIALIZED_DISPLAY_PARAMETER_H
#define VPE_FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_DESERIALIZED_DISPLAY_PARAMETER_H
#include <optional>
#include "v1_0/hdr_static_metadata.h"
#include "algorithm_common.h"
#include "hdr_vivid_metadata_v1.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
using namespace HDI::Display::Graphic::Common::V1_0;
struct DeserializedDisplayParameter {
ColorSpaceDescription inputColorSpace; // 色彩空间信息
ColorSpaceDescription outputColorSpace; // 色彩空间信息
std::optional<HdrStaticMetadata> staticMetadata; // 静态元数据
std::optional<HdrVividMetadataV1> hdrVividMetadata; // 动态元数据
float sdrNits; // SDR亮度
float tmoNits; // TMO目标亮度
float currentDisplayNits; // 屏幕当前亮度,和tmoNits相除得到sdr亮度打折比
bool disableHdrFloatHeadRoom; // 不使用HDRfp16方案做额外提亮
HwDisplayMeta displayMeta; // 拍显协同元数据
int32_t width; // 宽度
int32_t height; // 高度
std::vector<float> linearMatrix; // 线性域转换矩阵,作用在原色域上
};
} // namespace VideoProcessingEngine
} // Media
} // OHOS
#endif // VPE_FRAMEWORK_ALGORITHM_COLORSPACE_CONVERTER_DISPLAY_DESERIALIZED_DISPLAY_PARAMETER_H
@@ -0,0 +1,166 @@
/*
* 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.
*/
#ifndef COLORSPACE_CONVERTER_VIDEO_IMPL_H
#define COLORSPACE_CONVERTER_VIDEO_IMPL_H
#include <functional>
#include <queue>
#include <mutex>
#include <limits>
#include <map>
#include "colorspace_converter_video.h"
#include "meta/format.h"
#include "surface.h"
#include "sync_fence.h"
#include "colorspace_converter_video_common.h"
#include "colorspace_converter.h"
#include "algorithm_video_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class ColorSpaceConverterVideoImpl : public ColorSpaceConverterVideo {
public:
ColorSpaceConverterVideoImpl();
~ColorSpaceConverterVideoImpl();
int32_t Init();
int32_t Init(std::shared_ptr<OpenGLContext> openglContext);
int32_t SetCallback(const std::shared_ptr<ColorSpaceConverterVideoCallback> &callback) override;
int32_t SetOutputSurface(sptr<Surface> surface) override;
sptr<Surface> CreateInputSurface() override;
int32_t Configure(const Format &format) override;
int32_t Prepare() override;
int32_t Start() override;
int32_t Stop() override;
int32_t Reset() override;
int32_t Release() override;
int32_t NotifyEos() override;
int32_t ReleaseOutputBuffer(uint32_t index, bool render) override;
int32_t SetParameter(const Format &parameter) override;
int32_t GetParameter(Format &parameter) override;
int32_t Flush() override;
int32_t GetOutputFormat(Format &format) override;
GSError OnConsumerBufferAvailable();
GSError OnProducerBufferReleased();
private:
struct SurfaceBufferWrapper {
public:
SurfaceBufferWrapper() = default;
~SurfaceBufferWrapper() = default;
sptr<SurfaceBuffer> memory{nullptr};
CscvBufferFlag bufferFlag{CSCV_BUFFER_FLAG_NONE};
sptr<SyncFence> fence{nullptr};
int64_t timestamp;
};
void InitBuffers();
bool WaitProcessing();
bool AcquireInputOutputBuffers(
std::shared_ptr<SurfaceBufferWrapper> &inputBuffer, std::shared_ptr<SurfaceBufferWrapper> &outputBuffer);
void DoTask();
void OnTriggered();
void Process(std::shared_ptr<SurfaceBufferWrapper> inputBuffer, std::shared_ptr<SurfaceBufferWrapper> outputBuffer);
int32_t ConfigureColorSpace(const Format &format);
int32_t AttachToNewSurface(sptr<Surface> newSurface);
int32_t SetOutputSurfaceConfig(sptr<Surface> surface);
int32_t SetOutputSurfaceRunning(sptr<Surface> newSurface);
int32_t GetReleaseOutBuffer();
std::atomic<VPEAlgoState> state_{VPEAlgoState::UNINITIALIZED};
std::shared_ptr<ColorSpaceConverterVideoCallback> cb_{nullptr};
std::shared_ptr<ColorSpaceConverter> csc_{nullptr};
std::mutex mutex_;
Format format_;
Format outputFormat_;
bool getUsage_{false};
std::atomic<bool> initBuffer_{false};
// task
std::mutex mtxTaskDone_;
std::condition_variable cvTaskDone_;
std::shared_ptr<std::thread> taskThread_{nullptr};
std::condition_variable cvTaskStart_;
std::mutex mtxTaskStart_;
std::atomic<bool> isRunning_{false};
std::atomic<bool> isProcessing_{false};
std::atomic<bool> isEos_{false};
// surface
std::queue<std::shared_ptr<SurfaceBufferWrapper>> outputBufferAvilQue_;
std::queue<std::shared_ptr<SurfaceBufferWrapper>> inputBufferAvilQue_;
std::queue<std::shared_ptr<SurfaceBufferWrapper>> renderBufferAvilQue_;
using RenderBufferAvilMapType = std::map<uint64_t, std::shared_ptr<SurfaceBufferWrapper>>;
RenderBufferAvilMapType renderBufferAvilMap_;
RenderBufferAvilMapType outputBufferAvilQueBak_;
RenderBufferAvilMapType renderBufferMapBak_;
std::mutex onBqMutex_; // inputsruface buffer
std::mutex renderQueMutex_; // outputsruface buffer
std::mutex surfaceChangeMutex_;
std::mutex surfaceChangeMutex2_;
sptr<Surface> inputSurface_{nullptr};
sptr<Surface> outputSurface_{nullptr};
static constexpr size_t MAX_BUFFER_CNT{5};
uint32_t outBufferCnt_{MAX_BUFFER_CNT};
uint32_t inBufferCnt_{MAX_BUFFER_CNT};
static constexpr size_t MAX_SURFACE_SEQUENCE{std::numeric_limits<uint32_t>::max()};
uint32_t lastSurfaceSequence_{MAX_SURFACE_SEQUENCE};
BufferRequestConfig requestCfg_{};
BufferFlushConfig flushCfg_{};
// colorsapce
std::vector<uint8_t> colorSpaceVec_;
int32_t hdrType_{0};
std::vector<uint8_t> hdrVec_;
int32_t lastOutputWidth_ = 0;
int32_t lastOutputHeight_ = 0;
};
class ImageProcessBufferConsumerListener : public OHOS::IBufferConsumerListener {
public:
explicit ImageProcessBufferConsumerListener(ColorSpaceConverterVideoImpl *process) : process_(process)
{}
void OnBufferAvailable() override;
private:
ColorSpaceConverterVideoImpl *process_;
};
class ColorSpaceConverterVideoCallbackImpl : public ColorSpaceConverterVideoCallback {
public:
struct Callback {
using OnErrorCallback = std::function<void(int32_t, ArgumentType *)>;
using OnOutputBufferAvailableCallback = std::function<void(uint32_t, int32_t, ArgumentType *)>;
using OnOutputFormatChangedCallback = std::function<void(Format, ArgumentType *)>;
OnErrorCallback onError;
OnOutputBufferAvailableCallback onOutputBufferAvailable;
OnOutputFormatChangedCallback OnOutputFormatChanged;
};
ColorSpaceConverterVideoCallbackImpl(Callback *callback, ArgumentType *userData);
void OnError(int32_t errorCode);
void OnState(int32_t state);
void OnOutputBufferAvailable(uint32_t index, CscvBufferFlag flag);
void OnOutputFormatChanged(const Format& format);
private:
std::unique_ptr<Callback> callback_{nullptr};
ArgumentType *userData_{nullptr};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // COLORSPACE_CONVERTER_VIDEO_IMPL_H
@@ -0,0 +1,107 @@
/*
* 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.
*/
#include "algorithm_common.h"
#include "securec.h"
#include "vpe_log.h"
#include "vpe_context.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
int SetupOpengl(std::shared_ptr<OpenGLContext> &openglHandle)
{
std::shared_ptr<OpenGLContext> openglContextPtr = std::make_shared<OpenGLContext>();
openglContextPtr->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (openglContextPtr->display == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS) {
VPE_LOGE("Get display failed!");
return VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED;
}
EGLint major;
EGLint minor;
if (eglInitialize(openglContextPtr->display, &major, &minor) == EGL_FALSE || eglGetError() != EGL_SUCCESS) {
VPE_LOGE("eglInitialize failed!");
return VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED;
}
openglHandle = openglContextPtr;
return static_cast<int>(VPE_ALGO_ERR_OK);
}
VPEAlgoErrCode ColorSpaceDescription::Create(const sptr<SurfaceBuffer> &buffer, ColorSpaceDescription &desc)
{
CHECK_AND_RETURN_RET_LOG(nullptr != buffer, VPE_ALGO_ERR_INVALID_VAL, "Get an invalid buffer");
std::vector<uint8_t> vec;
int32_t err = buffer->GetMetadata(ATTRKEY_COLORSPACE_INFO, vec);
CHECK_AND_RETURN_RET_LOG(GSERROR_OK == err, VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED,
"Get metadata colorspace info failed, err: %{public}d", err);
CHECK_AND_RETURN_RET_LOG(sizeof(desc.colorSpaceInfo) == (vec.size()), VPE_ALGO_ERR_INVALID_VAL,
"memcpy_s failed, desc.colorSpaceInfo size != vec size;");
errno_t ret = memcpy_s(&desc.colorSpaceInfo, sizeof(desc.colorSpaceInfo), vec.data(), vec.size());
if (ret != EOK) {
VPE_LOGE("memcpy_s failed, err = %d\n", ret);
return VPE_ALGO_ERR_INVALID_VAL;
}
vec.clear();
err = buffer->GetMetadata(ATTRKEY_HDR_METADATA_TYPE, vec);
CHECK_AND_RETURN_RET_LOG(GSERROR_OK == err, VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED,
"Get hdr metadata type failed, err: %{public}d", err);
CHECK_AND_RETURN_RET_LOG(sizeof(desc.metadataType) == (vec.size()), VPE_ALGO_ERR_INVALID_VAL,
"memcpy_s failed, desc.metadataType size != vec size;");
ret = memcpy_s(&desc.metadataType, sizeof(desc.metadataType), vec.data(), vec.size());
if (ret != EOK) {
VPE_LOGE("memcpy_s failed, err = %d\n", ret);
return VPE_ALGO_ERR_INVALID_VAL;
}
return VPE_ALGO_ERR_OK;
}
uint32_t GetColorSpaceType(const CM_ColorSpaceInfo &colorSpaceInfo)
{
CHECK_AND_LOG(colorSpaceInfo.primaries <= CM_ColorPrimaries::COLORPRIMARIES_ADOBERGB &&
colorSpaceInfo.transfunc <= CM_TransFunc::TRANSFUNC_GAMMA2_4 &&
colorSpaceInfo.matrix <= CM_Matrix::MATRIX_BT2100_ICTCP &&
colorSpaceInfo.range <= CM_Range::RANGE_EXTEND,
"Invalid colorSpaceInfo, primaries : %{public}d, transfunc: %{public}d, matrix: %{public}d, range: %{public}d",
colorSpaceInfo.primaries, colorSpaceInfo.transfunc, colorSpaceInfo.matrix, colorSpaceInfo.range);
return ((static_cast<unsigned int>(colorSpaceInfo.primaries) << COLORPRIMARIES_OFFSET) +
(static_cast<unsigned int>(colorSpaceInfo.transfunc) << TRANSFUNC_OFFSET) +
(static_cast<unsigned int>(colorSpaceInfo.matrix) << MATRIX_OFFSET) +
(static_cast<unsigned int>(colorSpaceInfo.range) << RANGE_OFFSET));
}
CM_ColorSpaceInfo GetColorSpaceInfo(const uint32_t colorSpaceType)
{
CM_ColorSpaceInfo info;
info.primaries = static_cast<CM_ColorPrimaries>((colorSpaceType & COLORPRIMARIES_MASK) >> COLORPRIMARIES_OFFSET);
info.transfunc = static_cast<CM_TransFunc>((colorSpaceType & TRANSFUNC_MASK) >> TRANSFUNC_OFFSET);
info.matrix = static_cast<CM_Matrix>((colorSpaceType & MATRIX_MASK) >> MATRIX_OFFSET);
info.range = static_cast<CM_Range>((colorSpaceType & RANGE_MASK) >> RANGE_OFFSET);
return info;
}
bool ColorSpaceDescription::operator < (const ColorSpaceDescription &desc) const
{
uint32_t thisColorSpaceType = GetColorSpaceType(colorSpaceInfo);
uint32_t descColorSpaceType = GetColorSpaceType(desc.colorSpaceInfo);
return (thisColorSpaceType < descColorSpaceType ||
((thisColorSpaceType == descColorSpaceType) && (metadataType < desc.metadataType)));
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -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.
*/
#include "algorithm_utils.h"
#include <unordered_map>
#include "vpe_log.h"
using namespace OHOS::Media::VideoProcessingEngine;
namespace {
const std::unordered_map<VPEAlgoErrCode, std::string> ERROR_STR_MAP = {
{ VPE_ALGO_ERR_OK, VPE_TO_STR(VPE_ALGO_ERR_OK) },
{ VPE_ALGO_ERR_NO_MEMORY, VPE_TO_STR(VPE_ALGO_ERR_NO_MEMORY) },
{ VPE_ALGO_ERR_INVALID_OPERATION, VPE_TO_STR(VPE_ALGO_ERR_INVALID_OPERATION) },
{ VPE_ALGO_ERR_INVALID_VAL, VPE_TO_STR(VPE_ALGO_ERR_INVALID_VAL) },
{ VPE_ALGO_ERR_UNKNOWN, VPE_TO_STR(VPE_ALGO_ERR_UNKNOWN) },
{ VPE_ALGO_ERR_INIT_FAILED, VPE_TO_STR(VPE_ALGO_ERR_INIT_FAILED) },
{ VPE_ALGO_ERR_EXTENSION_NOT_FOUND, VPE_TO_STR(VPE_ALGO_ERR_EXTENSION_NOT_FOUND) },
{ VPE_ALGO_ERR_EXTENSION_INIT_FAILED, VPE_TO_STR(VPE_ALGO_ERR_EXTENSION_INIT_FAILED) },
{ VPE_ALGO_ERR_EXTENSION_PROCESS_FAILED, VPE_TO_STR(VPE_ALGO_ERR_EXTENSION_PROCESS_FAILED) },
{ VPE_ALGO_ERR_NOT_IMPLEMENTED, VPE_TO_STR(VPE_ALGO_ERR_NOT_IMPLEMENTED) },
{ VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED, VPE_TO_STR(VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED) },
{ VPE_ALGO_ERR_INVALID_STATE, VPE_TO_STR(VPE_ALGO_ERR_INVALID_STATE) },
{ VPE_ALGO_ERR_EXTEND_START, VPE_TO_STR(VPE_ALGO_ERR_EXTEND_START) },
};
const std::unordered_map<VPEAlgoState, std::string> STATE_STR_MAP = {
{ VPEAlgoState::UNINITIALIZED, VPE_TO_STR(VPEAlgoState::UNINITIALIZED) },
{ VPEAlgoState::INITIALIZED, VPE_TO_STR(VPEAlgoState::INITIALIZED) },
{ VPEAlgoState::CONFIGURING, VPE_TO_STR(VPEAlgoState::CONFIGURING) },
{ VPEAlgoState::CONFIGURED, VPE_TO_STR(VPEAlgoState::CONFIGURED) },
{ VPEAlgoState::STOPPED, VPE_TO_STR(VPEAlgoState::STOPPED) },
{ VPEAlgoState::RUNNING, VPE_TO_STR(VPEAlgoState::RUNNING) },
{ VPEAlgoState::EOS, VPE_TO_STR(VPEAlgoState::EOS) },
{ VPEAlgoState::ERROR, VPE_TO_STR(VPEAlgoState::ERROR) },
};
}
std::string AlgorithmUtils::ToString(VPEAlgoErrCode errorCode)
{
auto it = ERROR_STR_MAP.find(errorCode);
if (it == ERROR_STR_MAP.end()) [[unlikely]] {
VPE_LOGE("Invalid error code:%{public}d", errorCode);
return "Unsupported error:" + std::to_string(static_cast<int>(errorCode));
}
return it->second;
}
std::string AlgorithmUtils::ToString(VPEAlgoState state)
{
auto it = STATE_STR_MAP.find(state);
if (it == STATE_STR_MAP.end()) [[unlikely]] {
VPE_LOGE("Invalid state:%{public}d", state);
return "Unsupported state:" + std::to_string(static_cast<int>(state));
}
return it->second;
}
bool AlgorithmUtils::CopySurfaceBufferToSurfaceBuffer(const sptr<SurfaceBuffer>& srcBuffer,
sptr<SurfaceBuffer>& destBuffer)
{
CHECK_AND_RETURN_RET_LOG(srcBuffer != nullptr && destBuffer != nullptr, false,
"srcBuffer or destBuffer is nullptr");
CHECK_AND_RETURN_RET_LOG(srcBuffer->GetFormat() == destBuffer->GetFormat(), false, "buffer format is not same."\
"input format:%{public}d,output format:%{public}d", srcBuffer->GetFormat(), destBuffer->GetFormat());
CHECK_AND_RETURN_RET_LOG((srcBuffer->GetStride() == destBuffer->GetStride()) &&
(srcBuffer->GetHeight() == destBuffer->GetHeight()) && (srcBuffer->GetWidth() == destBuffer->GetWidth()),
false, "buffer stride and height is not same. input height:%{public}d,output height:%{public}d,"\
"input width:%{public}d,output width:%{public}d,input stride:%{public}d,output stride:%{public}d",
srcBuffer->GetHeight(), destBuffer->GetHeight(), srcBuffer->GetWidth(), destBuffer->GetWidth(),
srcBuffer->GetStride(), destBuffer->GetStride());
CHECK_AND_RETURN_RET_LOG(srcBuffer->GetSize() == destBuffer->GetSize(), false, "buffer size is not same."\
"input size:%{public}u,output size:%{public}u", srcBuffer->GetSize(), destBuffer->GetSize());
if (memcpy_s(static_cast<uint8_t*>(destBuffer->GetVirAddr()), destBuffer->GetSize(),
static_cast<uint8_t*>(srcBuffer->GetVirAddr()), srcBuffer->GetSize()) != EOK) {
VPE_LOGE("Fail to copy surfaceBuffer to surfaceBuffer!");
return false;
}
std::vector<uint8_t> attrInfo{};
std::vector<uint32_t> keys{};
GSError ret;
if (srcBuffer->ListMetadataKeys(keys) == GSERROR_OK && !keys.empty()) {
for (size_t i = 0; i < keys.size(); i++) {
if (srcBuffer->GetMetadata(keys[i], attrInfo) == GSERROR_OK && !attrInfo.empty()) {
ret = destBuffer->SetMetadata(keys[i], attrInfo);
CHECK_AND_RETURN_RET_LOG(ret == GSERROR_OK, false, "Fail to set metadata.");
}
attrInfo.clear();
}
}
return true;
}
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "algorithm_video.h"
#include <functional>
#include <unordered_map>
#include "vpe_log.h"
// NOTE: Add feature altorithm header files here
// Feature altorithm header files begin
#include "detail_enhancer_video_fwk.h"
// Feature altorithm header files end
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
namespace {
std::unordered_map<uint32_t, std::function<std::shared_ptr<VpeVideo>(void)>> g_creators = {
// NOTE: Add feature altorithm creator here
// Feature altorithm header creator begin
{ VIDEO_TYPE_DETAIL_ENHANCER, &DetailEnhancerVideoFwk::Create },
// Feature altorithm header creator end
};
}
std::shared_ptr<VpeVideo> VpeVideo::Create(uint32_t type)
{
auto it = g_creators.find(type);
if (it == g_creators.end()) {
VPE_LOGE("Unsupported type: 0x%{public}x", type);
return nullptr;
}
return it->second();
}
VPEAlgoErrCode VpeVideo::RegisterCallback([[maybe_unused]] const std::shared_ptr<VpeVideoCallback>& callback)
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::SetOutputSurface([[maybe_unused]] const sptr<Surface>& surface)
{
return VPE_ALGO_ERR_OK;
}
sptr<Surface> VpeVideo::GetInputSurface()
{
return nullptr;
}
VPEAlgoErrCode VpeVideo::SetParameter([[maybe_unused]] const Format& parameter)
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::GetParameter([[maybe_unused]] Format& parameter)
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::Start()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::Stop()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::Release()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::Flush()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::Enable()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::Disable()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::NotifyEos()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::ReleaseOutputBuffer([[maybe_unused]] uint32_t index, [[maybe_unused]] bool render)
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideo::RenderOutputBufferAtTime([[maybe_unused]] uint32_t index,
[[maybe_unused]] int64_t renderTimestamp)
{
return VPE_ALGO_ERR_OK;
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "algorithm_video_common.h"
#include "vpe_log.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
void VpeVideoCallback::OnError([[maybe_unused]] VPEAlgoErrCode errorCode)
{
}
void VpeVideoCallback::OnState([[maybe_unused]] VPEAlgoState state)
{
}
void VpeVideoCallback::OnOutputFormatChanged([[maybe_unused]] const Format& format)
{
}
void VpeVideoCallback::OnEffectChange([[maybe_unused]] uint32_t type)
{
}
void VpeVideoCallback::OnOutputBufferAvailable([[maybe_unused]] uint32_t index, [[maybe_unused]] VpeBufferFlag flag)
{
}
void VpeVideoCallback::OnOutputBufferAvailable(uint32_t index, const VpeBufferInfo& info)
{
VPE_LOGD("Call OnOutputBufferAvailable(%{public}u,%{public}d)", index, info.flag);
OnOutputBufferAvailable(index, info.flag);
}
@@ -0,0 +1,843 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "algorithm_video_impl.h"
#include <chrono>
#include <sstream>
#include "vpe_log.h"
#include "vpe_trace.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
using namespace std::chrono_literals;
namespace {
constexpr uint32_t BUFFER_QUEUE_SIZE = 5;
std::string ToString(const sptr<SurfaceBuffer>& buffer)
{
if (buffer == nullptr) {
return "null";
}
std::stringstream stream;
stream << "id:" << buffer->GetSeqNum() << " " << buffer->GetWidth() << "x" << buffer->GetHeight() <<
" format:" << buffer->GetFormat() << " usage:0x" << std::hex << buffer->GetUsage();
return stream.str();
}
std::string ToString(const BufferRequestConfig& requestCfg)
{
std::stringstream stream;
stream << requestCfg.width << "x" << requestCfg.height << " format:" << requestCfg.format <<
" usage:0x" << std::hex << requestCfg.usage;
return stream.str();
}
} // namespace
VpeVideoImpl::~VpeVideoImpl()
{
VPE_LOGD("Step in");
Deinitialize();
}
VPEAlgoErrCode VpeVideoImpl::RegisterCallback(const std::shared_ptr<VpeVideoCallback>& callback)
{
CHECK_AND_RETURN_RET_LOG(callback != nullptr, VPE_ALGO_ERR_INVALID_VAL, "Invalid input: callback is null!");
return ExecuteWhenIdle(
[this, callback]() {
cb_ = callback;
return VPE_ALGO_ERR_OK;
}, "Registration of callbacks during running is not allowed!");
}
VPEAlgoErrCode VpeVideoImpl::SetOutputSurface(const sptr<Surface>& surface)
{
CHECK_AND_RETURN_RET_LOG(surface != nullptr, VPE_ALGO_ERR_INVALID_VAL, "Invalid input: surface is null!");
CHECK_AND_RETURN_RET_LOG(!surface->IsConsumer(), VPE_ALGO_ERR_INVALID_VAL,
"Invalid input: surface is NOT producer!");
CHECK_AND_RETURN_RET_LOG(IsProducerSurfaceValid(surface), VPE_ALGO_ERR_INVALID_VAL,
"Invalid input: surface is invalid!");
std::lock_guard<std::mutex> lock(lock_);
if (producer_ == surface) {
VPE_LOGD("Oops! The same surface!");
return VPE_ALGO_ERR_OK;
}
if (producer_ != nullptr) {
producer_->UnRegisterReleaseListener();
producer_->CleanCache(true);
}
surface->UnRegisterReleaseListener();
surface->CleanCache(true);
GSError err = surface->RegisterReleaseListener([this](sptr<SurfaceBuffer>&) { return OnProducerBufferReleased(); });
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "RegisterReleaseListener failed!");
VPE_LOGI("Set output buffer queue size to %{public}u", BUFFER_QUEUE_SIZE);
surface->SetQueueSize(BUFFER_QUEUE_SIZE);
surface->Connect();
AttachBuffers(surface);
if (state_.load() != VPEState::IDLE) {
cvTrigger_.notify_one();
}
producer_ = surface;
VPEAlgoErrCode ret = VPE_ALGO_ERR_OK;
if (isEnable_.load()) {
ret = UpdateRequestCfg(surface, requestCfg_);
}
VPE_LOGD("requestCfg_({ %{public}s })", ToString(requestCfg_).c_str());
return ret;
}
sptr<Surface> VpeVideoImpl::GetInputSurface()
{
sptr<Surface> producerSurface;
if (ExecuteWhenIdle([this, &producerSurface]() {
producerSurface = CreateConsumerSurfaceLocked();
return VPE_ALGO_ERR_OK;
}, "Getting a surface during running is not allowed!") != VPE_ALGO_ERR_OK) {
return nullptr;
}
return producerSurface;
}
VPEAlgoErrCode VpeVideoImpl::Start()
{
return ExecuteWhenIdle(
[this]() {
if (consumer_ == nullptr || producer_ == nullptr || cb_ == nullptr) {
VPE_LOGE("The input surface, output surface or callback is NOT ready!");
return VPE_ALGO_ERR_INVALID_OPERATION;
}
state_ = VPEState::RUNNING;
OnStateLocked(VPEAlgoState::RUNNING);
return VPE_ALGO_ERR_OK;
}, "Already start!");
}
VPEAlgoErrCode VpeVideoImpl::Stop()
{
auto err = ExecuteWhenRunning([this]() {
state_ = VPEState::STOPPING;
cvTrigger_.notify_one();
return VPE_ALGO_ERR_OK;
}, "Already stop!");
return err;
}
VPEAlgoErrCode VpeVideoImpl::Release()
{
return Deinitialize();
}
VPEAlgoErrCode VpeVideoImpl::Flush()
{
std::unique_lock<std::mutex> lock(lock_);
cvDone_.wait(lock, [this]() { return !isProcessing_.load(); });
std::queue<SurfaceBufferInfo> tempQueue1;
std::queue<SurfaceBufferInfo> tempQueue2;
{
std::lock_guard<std::mutex> bufferLock(bufferLock_);
consumerBufferQueue_.swap(tempQueue1);
while (!renderBufferQueue_.empty()) {
producerBufferQueue_.push(renderBufferQueue_.front());
renderBufferQueue_.pop();
}
attachBufferQueue_.swap(tempQueue2);
attachBufferIDs_.clear();
}
ClearConsumerLocked(tempQueue1);
ClearConsumerLocked(tempQueue2);
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideoImpl::Enable()
{
CHECK_AND_RETURN_RET_LOG(!isEnable_.load(), VPE_ALGO_ERR_INVALID_OPERATION, "Already enabled!");
std::lock_guard<std::mutex> lock(lock_);
isEnable_ = true;
isEnableChange_ = true;
if (producer_ == nullptr) {
return VPE_ALGO_ERR_OK;
}
auto ret = UpdateRequestCfg(producer_, requestCfg_);
VPE_LOGD("requestCfg_({ %{public}s })", ToString(requestCfg_).c_str());
if (requestCfg_.usage == orgRequestCfg_.usage &&
requestCfg_.format == orgRequestCfg_.format &&
requestCfg_.width == orgRequestCfg_.width &&
requestCfg_.height == orgRequestCfg_.height) {
producer_->CleanCache(false);
ClearBufferQueues();
}
return ret;
}
VPEAlgoErrCode VpeVideoImpl::Disable()
{
CHECK_AND_RETURN_RET_LOG(isEnable_.load(), VPE_ALGO_ERR_INVALID_OPERATION, "Already disabled!");
std::lock_guard<std::mutex> lock(lock_);
isEnable_ = false;
isEnableChange_ = true;
VPE_LOGD("requestCfg_({ %{public}s })", ToString(requestCfg_).c_str());
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideoImpl::NotifyEos()
{
return ExecuteWhenNotIdle(
[this]() {
{
std::lock_guard<std::mutex> buffferlock(bufferLock_);
SurfaceBufferInfo bufferInfo{};
bufferInfo.bufferFlag = VPE_BUFFER_FLAG_EOS;
consumerBufferQueue_.push(bufferInfo);
}
cvTrigger_.notify_one();
return VPE_ALGO_ERR_OK;
}, "Notify EOS must be called during running!");
}
VPEAlgoErrCode VpeVideoImpl::ReleaseOutputBuffer(uint32_t index, bool render)
{
return ExecuteWhenNotIdle(
[this, index, render]() { return RenderOutputBufferLocked(index, -1, render); },
"Release output buffer must be called during running!");
}
VPEAlgoErrCode VpeVideoImpl::RenderOutputBufferAtTime(uint32_t index, int64_t renderTimestamp)
{
return ExecuteWhenNotIdle(
[this, index, renderTimestamp]() { return RenderOutputBufferLocked(index, renderTimestamp, true); },
"Render output buffer must be called during running!");
}
bool VpeVideoImpl::IsInitialized() const
{
return isInitialized_.load();
}
VPEAlgoErrCode VpeVideoImpl::Initialize()
{
std::lock_guard<std::mutex> lock(lock_);
if (isInitialized_.load()) {
VPE_LOGD("Already initialize!");
return VPE_ALGO_ERR_OK;
}
VPE_LOGD("Start to initializing...");
isRunning_ = true;
worker_ = std::thread([this]() {
while (isRunning_.load()) {
{
std::unique_lock<std::mutex> bufferLock(bufferLock_);
if (!cvTrigger_.wait_for(bufferLock, 200s, [this] {
VPE_LOGD("run:%d stopping:%d consumerBQ:%{public}zu producerBQ:%{public}zu "
"renderBQ:%{public}zu flushBQ:%{public}zu attachBQ:%{public}zu",
isRunning_.load(), state_.load() == VPEState::STOPPING,
consumerBufferQueue_.size(), producerBufferQueue_.size(),
renderBufferQueue_.size(), flushBufferQueue_.size(), attachBufferQueue_.size());
return !isRunning_.load() || state_.load() == VPEState::STOPPING ||
(!producerBufferQueue_.empty() && !consumerBufferQueue_.empty());
})) {
VPE_LOGI("Video processing timeout.");
continue;
}
if (!isRunning_.load()) {
VPE_LOGI("Video processing clear.");
break;
}
if (producerBufferQueue_.empty() || consumerBufferQueue_.empty()) {
CheckSpuriousWakeup();
VPE_LOGD("Empty! consumerBQ:%{public}zu producerBQ:%{public}zu", consumerBufferQueue_.size(),
producerBufferQueue_.size());
continue;
}
}
VPE_LOGD("ProcessBuffers");
ProcessBuffers();
CheckStopping();
};
});
auto errorCode = OnInitialize();
isInitialized_ = true;
VPE_LOGD("OnInitialize() return %{public}d. this:%{public}p", errorCode, this);
return errorCode;
}
VPEAlgoErrCode VpeVideoImpl::Deinitialize()
{
std::unique_lock<std::mutex> lock(lock_);
VPE_LOGD("Start to deinitializing... this:%{public}p", this);
cvDone_.wait(lock, [this]() { return !isProcessing_.load(); });
if (!isInitialized_.load()) {
VPE_LOGD("Already deinitialize!");
return VPE_ALGO_ERR_OK;
}
isInitialized_ = false;
VPEAlgoErrCode errorCode = OnDeinitialize();
if (state_.load() == VPEState::RUNNING) {
state_ = VPEState::STOPPING;
}
isRunning_ = false;
cvTrigger_.notify_one();
if (worker_.joinable()) {
worker_.join();
}
CheckStoppingLocked();
cb_ = nullptr;
ClearBufferQueues();
if (consumer_ != nullptr) {
consumer_->UnregisterConsumerListener();
consumer_ = nullptr;
}
if (producer_ != nullptr) {
producer_->UnRegisterReleaseListener();
producer_->CleanCache(true);
producer_ = nullptr;
}
VPE_LOGD("OnDeinitialize() return %{public}d. this:%{public}p", errorCode, this);
return errorCode;
}
void VpeVideoImpl::RefreshBuffers()
{
std::lock_guard<std::mutex> lock(lock_);
if (state_.load() != VPEState::RUNNING) {
VPE_LOGD("Skip refreshing during Non-Running.");
return;
}
if (!isEnable_.load()) {
VPE_LOGD("Skip refreshing when it is disabled.");
return;
}
if (!isBufferQueueReady_) {
VPE_LOGD("Skip refreshing when buffer queue is not ready.");
return;
}
VPE_LOGD("Clear all buffer queues.");
ClearBufferQueues();
}
void VpeVideoImpl::OnOutputFormatChanged(const Format& format)
{
std::lock_guard<std::mutex> lock(lock_);
if (cb_ != nullptr) {
VPE_LOGD("OnOutputFormatChanged()");
cb_->OnOutputFormatChanged(format);
}
}
VPEAlgoErrCode VpeVideoImpl::OnInitialize()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideoImpl::OnDeinitialize()
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VpeVideoImpl::Process([[maybe_unused]] const sptr<SurfaceBuffer>& sourceImage,
[[maybe_unused]] sptr<SurfaceBuffer>& destinationImage)
{
return VPE_ALGO_ERR_OK;
}
bool VpeVideoImpl::IsProducerSurfaceValid([[maybe_unused]] const sptr<Surface>& surface)
{
return true;
}
VPEAlgoErrCode VpeVideoImpl::UpdateRequestCfg([[maybe_unused]] const sptr<Surface>& surface,
[[maybe_unused]] BufferRequestConfig& requestCfg)
{
return VPE_ALGO_ERR_OK;
}
void VpeVideoImpl::UpdateRequestCfg([[maybe_unused]] const sptr<SurfaceBuffer>& consumerBuffer,
[[maybe_unused]] BufferRequestConfig& requestCfg)
{
}
void VpeVideoImpl::OnErrorLocked(VPEAlgoErrCode errorCode)
{
if (cb_ != nullptr) {
VPE_LOGD("OnError(%{public}d)", errorCode);
cb_->OnError(errorCode);
}
}
void VpeVideoImpl::OnStateLocked(VPEAlgoState state)
{
if (cb_ != nullptr) {
VPE_LOGD("OnState(%{public}d)", state);
cb_->OnState(state);
}
}
void VpeVideoImpl::OnEffectChange(uint32_t type)
{
if (cb_ != nullptr) {
VPE_LOGD("OnEffectChange(0x%{public}x)", type);
cb_->OnEffectChange(type);
}
}
void VpeVideoImpl::OnOutputBufferAvailable(uint32_t index, const VpeBufferInfo& info)
{
if (cb_ != nullptr) {
cb_->OnOutputBufferAvailable(index, info);
}
}
GSError VpeVideoImpl::OnConsumerBufferAvailable()
{
std::lock_guard<std::mutex> lock(lock_);
if (state_.load() != VPEState::RUNNING) {
VPE_LOGD("NOT running now!");
return GSERROR_INVALID_OPERATING;
}
SurfaceBufferInfo bufferInfo{};
int releaseFence = -1;
OHOS::Rect damage;
GSError err = consumer_->AcquireBuffer(bufferInfo.buffer, releaseFence, bufferInfo.timestamp, damage);
if (err != GSERROR_OK || bufferInfo.buffer == nullptr) {
VPE_LOGE("Failed to acquire buffer!");
return err;
}
VPE_LOGD("consumer_->AcquireBuffer({ %{public}s })", ToString(bufferInfo.buffer).c_str());
{
std::lock_guard<std::mutex> buffferlock(bufferLock_);
if (!isBufferQueueReady_) {
isBufferQueueReady_ = true;
requestCfg_.usage = bufferInfo.buffer->GetUsage();
requestCfg_.timeout = 0;
requestCfg_.strideAlignment = 32; // 32 bits align
UpdateRequestCfg(bufferInfo.buffer, requestCfg_);
VPE_LOGD("Use requestCfg_({ %{public}s }) to prepare buffers.", ToString(requestCfg_).c_str());
PrepareBuffers();
}
consumerBufferQueue_.push(bufferInfo);
}
cvTrigger_.notify_one();
return GSERROR_OK;
}
GSError VpeVideoImpl::OnProducerBufferReleased()
{
VPE_LOGD("step in");
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(consumer_ != nullptr || producer_ != nullptr, GSERROR_OK,
"Input or output surface is null!");
{
std::lock_guard<std::mutex> bufferLock(bufferLock_);
if (flushBufferQueue_.empty()) {
VPE_LOGD("NO flush buffer!");
return GSERROR_OK;
}
GSError err = GSERROR_OK;
SurfaceBufferInfo bufferInfo{};
CHECK_AND_RETURN_RET_LOG(RequestBuffer(bufferInfo, err), err, "Failed to request buffer!");
PopBuffer(flushBufferQueue_, bufferInfo.buffer->GetSeqNum(), bufferInfo,
[this](sptr<SurfaceBuffer>& buffer) {
CHECK_AND_RETURN_LOG(buffer != nullptr, "OnProducerBufferReleased: Flush buffer is null!");
VPE_LOGD("OnProducerBufferReleased: Pop flush buffer { %{public}s } flushBQ=%{public}zu",
ToString(buffer).c_str(), flushBufferQueue_.size());
});
}
if (state_.load() != VPEState::IDLE) {
cvTrigger_.notify_one();
}
VPE_LOGD("step out");
return GSERROR_OK;
}
VPEAlgoErrCode VpeVideoImpl::RenderOutputBufferLocked(uint32_t index, int64_t renderTimestamp, bool render)
{
std::unique_lock<std::mutex> bufferLock(bufferLock_);
SurfaceBufferInfo bufferInfo{};
bool isFound = PopBuffer(renderBufferQueue_, index, bufferInfo, [](sptr<SurfaceBuffer>&) {});
bufferLock.unlock();
CHECK_AND_RETURN_RET_LOG(isFound, VPE_ALGO_ERR_INVALID_PARAM, "Invalid input: index=%{public}u!", index);
if (render) {
BufferFlushConfig flushcfg{};
flushcfg.damage.w = bufferInfo.buffer->GetWidth();
flushcfg.damage.h = bufferInfo.buffer->GetHeight();
flushcfg.timestamp = (renderTimestamp == -1) ? bufferInfo.timestamp : renderTimestamp;
auto ret = producer_->FlushBuffer(bufferInfo.buffer, -1, flushcfg);
VPE_LOGD("producer_->FlushBuffer({ %{public}s })=%{public}d flushBQ=%{public}zu",
ToString(bufferInfo.buffer).c_str(), ret, flushBufferQueue_.size() + 1);
bufferLock.lock();
flushBufferQueue_.push(bufferInfo);
} else {
VPE_LOGD("reback { %{public}s } producerBQ=%{public}zu",
ToString(bufferInfo.buffer).c_str(), producerBufferQueue_.size() + 1);
bufferLock.lock();
producerBufferQueue_.push(bufferInfo);
bufferLock.unlock();
if (state_.load() != VPEState::IDLE) {
cvTrigger_.notify_one();
}
}
return VPE_ALGO_ERR_OK;
}
sptr<Surface> VpeVideoImpl::CreateConsumerSurfaceLocked()
{
CHECK_AND_RETURN_RET_LOG(consumer_ == nullptr, nullptr, "input surface already exists!");
consumer_ = Surface::CreateSurfaceAsConsumer("VideoProcessingSurface");
CHECK_AND_RETURN_RET_LOG(consumer_ != nullptr, nullptr, "Failed to create consumer surface!");
sptr<IBufferConsumerListener> listener = new(std::nothrow) ConsumerListener(shared_from_this());
CHECK_AND_RETURN_RET_LOG(listener != nullptr, nullptr, "Failed to create consumer surface listener!");
CHECK_AND_RETURN_RET_LOG(consumer_->RegisterConsumerListener(listener) == GSERROR_OK, nullptr,
"Failed to register consumer surface listener!");
sptr<IBufferProducer> producer = consumer_->GetProducer();
sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(producer);
CHECK_AND_RETURN_RET_LOG(producerSurface != nullptr, nullptr, "Failed to create producer surface!");
producerSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE |
BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE | BUFFER_USAGE_HW_COMPOSER);
consumer_->SetQueueSize(BUFFER_QUEUE_SIZE);
VPE_LOGI("Set input buffer queue size to %{public}u", BUFFER_QUEUE_SIZE);
return producerSurface;
}
bool VpeVideoImpl::RequestBuffer(SurfaceBufferInfo& bufferInfo, GSError& errorCode)
{
int releaseFence = -1;
errorCode = producer_->RequestBuffer(bufferInfo.buffer, releaseFence, requestCfg_);
if (errorCode != GSERROR_OK || bufferInfo.buffer == nullptr) {
VPE_LOGW("Failed to producer_->RequestBuffer(requestCfg={ %{public}s })", ToString(requestCfg_).c_str());
return false;
}
producerBufferQueue_.push(bufferInfo);
if (!isEnable_.load()) {
VPE_LOGD("producer_->RequestBuffer({ %{public}s }) and try to release.", ToString(bufferInfo.buffer).c_str());
auto it = attachBufferIDs_.find(bufferInfo.buffer->GetSeqNum());
if (it != attachBufferIDs_.end()) {
PopBuffer(attachBufferQueue_, bufferInfo.buffer->GetSeqNum(), bufferInfo,
[this](sptr<SurfaceBuffer>& buffer) {
CHECK_AND_RETURN_LOG(buffer != nullptr, "Attach buffer is null!");
attachBufferIDs_.erase(buffer->GetSeqNum());
auto ret = consumer_->ReleaseBuffer(buffer, -1);
VPE_LOGD("consumer_->ReleaseBuffer({ %{public}s })=%{public}d cache=%{public}zu",
ToString(buffer).c_str(), ret, attachBufferQueue_.size());
});
}
} else {
VPE_LOGD("producer_->RequestBuffer({ %{public}s })", ToString(bufferInfo.buffer).c_str());
if (attachBufferQueue_.empty()) {
return true;
}
bufferInfo = attachBufferQueue_.front();
attachBufferQueue_.pop();
if (bufferInfo.buffer != nullptr) {
attachBufferIDs_.erase(bufferInfo.buffer->GetSeqNum());
auto ret = consumer_->ReleaseBuffer(bufferInfo.buffer, -1);
VPE_LOGD("consumer_->ReleaseBuffer({ %{public}s })=%{public}d cache->%{public}zu",
ToString(bufferInfo.buffer).c_str(), ret, attachBufferQueue_.size());
}
}
return true;
}
void VpeVideoImpl::PrepareBuffers()
{
for (uint32_t i = 0; i < producer_->GetQueueSize(); i++) {
GSError errorCode;
SurfaceBufferInfo bufferInfo{};
RequestBuffer(bufferInfo, errorCode);
VPE_LOGD("<%{public}u> RequestBuffer({ %{public}s })=%{public}d", i, ToString(requestCfg_).c_str(), errorCode);
}
}
void VpeVideoImpl::AttachBuffers(const sptr<Surface>& producer)
{
std::lock_guard<std::mutex> bufferLock(bufferLock_);
std::queue<SurfaceBufferInfo> tempQueue;
producerBufferQueue_.swap(tempQueue);
AttachBuffers(producer, tempQueue);
AttachBuffers(producer, flushBufferQueue_);
}
void VpeVideoImpl::AttachBuffers(const sptr<Surface>& producer, std::queue<SurfaceBufferInfo>& bufferQueue)
{
for (; !bufferQueue.empty(); bufferQueue.pop()) {
auto bufferInfo = bufferQueue.front();
if (bufferInfo.buffer == nullptr) {
VPE_LOGW("buffer is null!");
continue;
}
auto errorCode = producer->AttachBufferToQueue(bufferInfo.buffer);
if (errorCode != GSERROR_OK) {
VPE_LOGW("Failed to producer->AttachBufferToQueue({ %{public}s })=%{public}d",
ToString(bufferInfo.buffer).c_str(), errorCode);
continue;
}
producerBufferQueue_.push(bufferInfo);
}
}
void VpeVideoImpl::ProcessBuffers()
{
sptr<Surface> consumer;
{
std::lock_guard<std::mutex> lock(lock_);
if (consumer_ == nullptr) {
return;
}
consumer = consumer_;
isProcessing_ = true;
}
while (isRunning_.load()) {
SurfaceBufferInfo srcBufferInfo;
SurfaceBufferInfo dstBufferInfo;
{
std::lock_guard<std::mutex> bufferLock(bufferLock_);
if (producerBufferQueue_.empty() || consumerBufferQueue_.empty()) {
break;
}
srcBufferInfo = consumerBufferQueue_.front();
dstBufferInfo = producerBufferQueue_.front();
if (srcBufferInfo.buffer == nullptr) {
consumerBufferQueue_.pop();
continue;
}
if (dstBufferInfo.buffer == nullptr) {
producerBufferQueue_.pop();
continue;
}
consumerBufferQueue_.pop();
producerBufferQueue_.pop();
}
if (isEnable_.load()) {
if (!ProcessBuffer(consumer, srcBufferInfo, dstBufferInfo)) {
continue;
}
} else {
BypassBuffer(srcBufferInfo, dstBufferInfo);
}
}
VPE_LOGD("consumerBQ:%{public}zu producerBQ:%{public}zu renderBQ:%{public}zu flushBQ:%{public}zu "
"attachBQ:%{public}zu", consumerBufferQueue_.size(), producerBufferQueue_.size(), renderBufferQueue_.size(),
flushBufferQueue_.size(), attachBufferQueue_.size());
{
std::lock_guard<std::mutex> lock(lock_);
isProcessing_ = false;
}
cvDone_.notify_all();
}
bool VpeVideoImpl::ProcessBuffer(sptr<Surface>& consumer, SurfaceBufferInfo& srcBufferInfo,
SurfaceBufferInfo& dstBufferInfo)
{
if (srcBufferInfo.bufferFlag != VPE_BUFFER_FLAG_EOS) {
dstBufferInfo.timestamp = srcBufferInfo.timestamp;
auto errorCode = Process(srcBufferInfo.buffer, dstBufferInfo.buffer);
auto ret = consumer->ReleaseBuffer(srcBufferInfo.buffer, -1);
VPE_LOGD("consumer_->ReleaseBuffer({ %{public}s })=%{public}d",
ToString(srcBufferInfo.buffer).c_str(), ret);
if (errorCode != VPE_ALGO_ERR_OK) {
OnErrorLocked(errorCode);
std::lock_guard<std::mutex> bufferLock(bufferLock_);
producerBufferQueue_.push(dstBufferInfo);
VPE_LOGW("Failed to process({ %{public}s },{ %{public}s })=%{public}d",
ToString(srcBufferInfo.buffer).c_str(), ToString(dstBufferInfo.buffer).c_str(), errorCode);
return false;
}
}
OutputBuffer(srcBufferInfo, dstBufferInfo, true, [] {});
return true;
}
void VpeVideoImpl::BypassBuffer(SurfaceBufferInfo& srcBufferInfo, SurfaceBufferInfo& dstBufferInfo)
{
{
std::lock_guard<std::mutex> lock(lock_);
auto ret1 = producer_->DetachBufferFromQueue(dstBufferInfo.buffer);
auto ret2 = producer_->AttachBufferToQueue(srcBufferInfo.buffer);
SetRequestCfgLocked(srcBufferInfo.buffer);
VPE_LOGD("producer_->DetachBufferFromQueue({ %{public}s })=%{public}d, "
"AttachBufferToQueue({ %{public}s })=%{public}d requestCfg:{ %{public}s }",
ToString(dstBufferInfo.buffer).c_str(), ret1,
ToString(srcBufferInfo.buffer).c_str(), ret2, ToString(requestCfg_).c_str());
}
OutputBuffer(srcBufferInfo, srcBufferInfo, false, [this, &srcBufferInfo] {
attachBufferIDs_.insert(srcBufferInfo.buffer->GetSeqNum());
attachBufferQueue_.push(srcBufferInfo);
});
VPE_LOGD("cache(%{public}s)->%{public}zu/%{public}zu", ToString(srcBufferInfo.buffer).c_str(),
attachBufferIDs_.size(), attachBufferIDs_.size());
}
void VpeVideoImpl::OutputBuffer(const SurfaceBufferInfo& bufferInfo, const SurfaceBufferInfo& bufferImage,
bool isProcessed, std::function<void(void)>&& getReadyToRender)
{
{
std::lock_guard<std::mutex> bufferLock(bufferLock_);
renderBufferQueue_.push(bufferImage);
getReadyToRender();
}
VpeBufferInfo info {
.flag = bufferInfo.bufferFlag,
.presentationTimestamp = bufferInfo.timestamp,
};
OnOutputBufferAvailable(bufferImage.buffer->GetSeqNum(), info);
if (!isEnableChange_.load()) {
VPE_LOGD("no enable change");
return;
}
std::lock_guard<std::mutex> lock(lock_);
if (isEnable_.load() && !isProcessed) {
VPE_LOGD("No frame is processed after enabling.");
return;
}
OnEffectChange(isEnable_.load() ? type_ : 0);
isEnableChange_ = false;
}
bool VpeVideoImpl::PopBuffer(std::queue<SurfaceBufferInfo>& bufferQueue, uint32_t index, SurfaceBufferInfo& bufferInfo,
std::function<void(sptr<SurfaceBuffer>&)>&& func)
{
bool isFound = false;
while (!bufferQueue.empty()) {
bufferInfo = bufferQueue.front();
bufferQueue.pop();
func(bufferInfo.buffer);
if (bufferInfo.buffer != nullptr && bufferInfo.buffer->GetSeqNum() == index) {
isFound = true;
break;
}
}
return isFound;
}
void VpeVideoImpl::SetRequestCfgLocked(const sptr<SurfaceBuffer>& buffer)
{
requestCfg_.usage = buffer->GetUsage();
requestCfg_.format = buffer->GetFormat();
requestCfg_.width = buffer->GetWidth();
requestCfg_.height = buffer->GetHeight();
orgRequestCfg_ = requestCfg_;
}
void VpeVideoImpl::CheckSpuriousWakeup()
{
if (!CheckStopping()) {
VPE_LOGD("Video processing spurious wakeup.");
}
}
bool VpeVideoImpl::CheckStopping()
{
std::lock_guard<std::mutex> lock(lock_);
return CheckStoppingLocked();
}
bool VpeVideoImpl::CheckStoppingLocked()
{
if (state_.load() == VPEState::STOPPING) {
state_ = VPEState::IDLE;
OnStateLocked(VPEAlgoState::STOPPED);
return true;
}
return false;
}
void VpeVideoImpl::ClearQueue(std::queue<SurfaceBufferInfo>& bufferQueue)
{
if (bufferQueue.empty()) {
return;
}
bufferQueue = std::queue<SurfaceBufferInfo>();
}
void VpeVideoImpl::ClearConsumerLocked(std::queue<SurfaceBufferInfo>& bufferQueue)
{
while (!bufferQueue.empty()) {
auto bufferInfo = bufferQueue.front();
consumer_->ReleaseBuffer(bufferInfo.buffer, -1);
bufferQueue.pop();
}
}
void VpeVideoImpl::ClearBufferQueues()
{
std::queue<SurfaceBufferInfo> tempQueue1;
std::queue<SurfaceBufferInfo> tempQueue2;
{
std::lock_guard<std::mutex> bufferLock(bufferLock_);
isBufferQueueReady_ = false;
consumerBufferQueue_.swap(tempQueue1);
ClearQueue(producerBufferQueue_);
ClearQueue(renderBufferQueue_);
attachBufferQueue_.swap(tempQueue2);
attachBufferIDs_.clear();
}
ClearConsumerLocked(tempQueue1);
ClearConsumerLocked(tempQueue2);
}
VPEAlgoErrCode VpeVideoImpl::ExecuteWhenIdle(std::function<VPEAlgoErrCode(void)>&& operation,
const std::string& errorMessage)
{
return ExecuteWithCheck([this] { return state_.load() == VPEState::IDLE; }, std::move(operation), errorMessage);
}
VPEAlgoErrCode VpeVideoImpl::ExecuteWhenNotIdle(std::function<VPEAlgoErrCode(void)>&& operation,
const std::string& errorMessage)
{
return ExecuteWithCheck([this] { return state_.load() != VPEState::IDLE; }, std::move(operation), errorMessage);
}
VPEAlgoErrCode VpeVideoImpl::ExecuteWhenRunning(std::function<VPEAlgoErrCode(void)>&& operation,
const std::string& errorMessage)
{
return ExecuteWithCheck([this] { return state_.load() == VPEState::RUNNING; }, std::move(operation), errorMessage);
}
VPEAlgoErrCode VpeVideoImpl::ExecuteWithCheck(std::function<bool(void)>&& checker,
std::function<VPEAlgoErrCode(void)>&& operation, const std::string& errorMessage)
{
std::lock_guard<std::mutex> lock(lock_);
if (checker()) {
return operation();
}
VPE_LOGW("%{public}s", errorMessage.c_str());
return VPE_ALGO_ERR_INVALID_OPERATION;
}
void VpeVideoImpl::ConsumerListener::OnBufferAvailable()
{
std::shared_ptr<VpeVideoImpl> owner = owner_.lock();
if (owner == nullptr) {
VPE_LOGE("Video processing is null!");
return;
}
owner->OnConsumerBufferAvailable();
}
+74
View File
@@ -0,0 +1,74 @@
/*
* 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.
*/
#include "frame_info.h"
#include "vpe_log.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
FrameInfo::FrameInfo(const sptr<SurfaceBuffer> &buffer)
{
CHECK_AND_RETURN_LOG(nullptr != buffer, "Get an invalid buffer");
width = static_cast<uint32_t>(buffer->GetWidth());
height = static_cast<uint32_t>(buffer->GetHeight());
widthStride = static_cast<uint32_t>(buffer->GetStride());
// 10 bit sample might be as 2bytes, so stride is 2 * (width + padding)
pixelFormat = static_cast<GraphicPixelFormat>(buffer->GetFormat());
bitDepth = BitDepth::BIT_DEPTH_8;
int numTwo = 2;
int numThree = 3;
int numFour = 4;
OH_NativeBuffer_Planes *planes = nullptr;
if ((pixelFormat == GRAPHIC_PIXEL_FMT_RGBA_8888) || (pixelFormat == GRAPHIC_PIXEL_FMT_BGRA_8888)) {
// RGBA8 has 4 channel per pixel which cost 4*8bit. // GetStride = w * sizeof(uint32)
widthStride = static_cast<uint32_t>(buffer->GetStride() / numFour);
heightStride = buffer->GetSize() / static_cast<uint32_t>(numFour) / widthStride;
} else if ((pixelFormat == GRAPHIC_PIXEL_FMT_YCBCR_420_SP) || (pixelFormat == GRAPHIC_PIXEL_FMT_YCRCB_420_SP)
|| (pixelFormat == GRAPHIC_PIXEL_FMT_YCBCR_420_P) || (pixelFormat == GRAPHIC_PIXEL_FMT_YCRCB_420_P)) {
// GetStride = w * sizeof(uint8) // yuv420(totalsize=3/2*h*w) calculate height stride
widthStride = static_cast<uint32_t>(buffer->GetStride());
heightStride = buffer->GetSize() * static_cast<uint32_t>(numTwo) /
static_cast<uint32_t>(numThree) / widthStride;
if ((buffer->GetPlanesInfo(reinterpret_cast<void**>(&planes)) == OHOS::SURFACE_ERROR_OK) &&
(planes != nullptr)) {
if (planes->planeCount > 1) {
heightStride = planes->planes[1].offset / planes->planes[0].columnStride;
}
}
} else if (pixelFormat == GRAPHIC_PIXEL_FMT_RGBA_1010102) {
// RGBA8 has 4 channel // GetStride = w * sizeof(uint8) (Get wByte nums) 4 channel
bitDepth = BitDepth::BIT_DEPTH_10;
widthStride = static_cast<uint32_t>(buffer->GetStride() / numFour);
heightStride = buffer->GetSize() / static_cast<uint32_t>(numFour) / widthStride;
} else if ((pixelFormat == GRAPHIC_PIXEL_FMT_YCBCR_P010) || (pixelFormat == GRAPHIC_PIXEL_FMT_YCRCB_P010)) {
// 2 bit GetStride = w * sizeof(uint8) (Get wByte nums) // yuv420(totalsize=3*h*w) calculate height stride
bitDepth = BitDepth::BIT_DEPTH_10;
widthStride = static_cast<uint32_t>(buffer->GetStride() / numTwo);
heightStride = buffer->GetSize() / static_cast<uint32_t>(numThree) / widthStride;
if ((buffer->GetPlanesInfo(reinterpret_cast<void**>(&planes)) == OHOS::SURFACE_ERROR_OK) &&
(planes != nullptr)) {
if (planes->planeCount > 1) {
heightStride = planes->planes[1].offset / planes->planes[0].columnStride;
}
}
} else {
heightStride = height;
}
ColorSpaceDescription::Create(buffer, colorSpace);
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,125 @@
/*
* 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.
*/
#define USE_OPENCL_WRAPPER
#ifdef USE_OPENCL_WRAPPER
#include "image_opencl_wrapper.h"
#include <algorithm>
#include <dlfcn.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include <iostream>
#include "vpe_log.h"
namespace OHOS {
namespace Media {
// default opencl library path
static const std::vector<std::string> g_opencl_library_paths = {
#if defined(__APPLE__) || defined(__MACOSX)
"libOpenCL.so", "/System/Library/Frameworks/OpenCL.framework/OpenCL"
#else
"/vendor/lib64/chipsetsdk/libGLES_mali.so",
"/system/lib64/libGLES_mali.so",
"libGLES_mali.so",
"/vendor/lib64/chipsetsdk/libhvgr_v200.so",
"/vendor/lib64/chipsetsdk/libEGL_impl.so",
#endif
};
static std::mutex g_initMutex;
static bool g_isInit = false;
static bool g_loadSuccess = false;
static void *g_handle{nullptr};
// load default library path
static bool LoadLibraryFromPath(const std::string &libraryPath, void **handlePtr)
{
CHECK_AND_RETURN_RET_LOG(handlePtr != nullptr, false, "handlePtr null!");
char path[PATH_MAX] = "";
if (realpath(libraryPath.c_str(), path) == nullptr) {
return false;
}
if (strcmp(path, "") == 0) {
return false;
}
*handlePtr = dlopen(path, RTLD_NOW | RTLD_LOCAL);
CHECK_AND_RETURN_RET_LOG(*handlePtr != nullptr, false, "*handlePtr null!");
// load function ptr use dlopen and dlsym.
clImportMemory = reinterpret_cast<clImportMemoryFunc>(dlsym(*handlePtr, "clImportMemoryARM"));
CHECK_AND_RETURN_RET_LOG(clImportMemory != nullptr, false, "clImportMemory null!");
return true;
}
bool LoadOpenCLLibrary(void **handlePtr)
{
CHECK_AND_RETURN_RET_LOG(handlePtr != nullptr, false, "handlePtr null!");
auto it =
std::find_if(g_opencl_library_paths.begin(), g_opencl_library_paths.end(),
[&](const std::string &lib_path) {
return OHOS::Media::LoadLibraryFromPath(lib_path, handlePtr);
});
CHECK_AND_RETURN_RET_LOG(it == g_opencl_library_paths.end(), true, "LoadOpenCLLibrary true!");
return false;
}
bool InitOpenCL()
{
std::lock_guard <std::mutex> lock(g_initMutex);
CHECK_AND_RETURN_RET_LOG(!g_isInit, g_loadSuccess, "InitOpenCL g_loadSuccess!");
g_isInit = true;
g_loadSuccess = LoadOpenCLLibrary(&g_handle);
return g_loadSuccess;
}
void DeInitOpenCL()
{
std::lock_guard <std::mutex> lock(g_initMutex);
if (g_handle != nullptr) {
dlclose(g_handle);
g_handle = nullptr;
}
}
clImportMemoryFunc clImportMemory = nullptr;
} // namespace Media
} // namespace OHOS
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
// clImportMemory wrapper, use OpenCLWrapper function.
cl_mem ClImportMemory(ClImportMemoryParam clImportMemoryParam)
{
auto status = OHOS::Media::InitOpenCL();
CHECK_AND_RETURN_RET_LOG(status, nullptr, "clImportMemory InitOpenCL null!");
auto func = OHOS::Media::clImportMemory;
MS_ASSERT(func != nullptr);
return func(clImportMemoryParam.context, clImportMemoryParam.flags, clImportMemoryParam.properties,
clImportMemoryParam.fd, clImportMemoryParam.size, clImportMemoryParam.errcode_ret);
}
void ClDeInitOpenCL()
{
OHOS::Media::DeInitOpenCL();
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // USE_OPENCL_WRAPPER
@@ -0,0 +1,295 @@
/*
* 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.
*/
#include "image_openclsetup.h"
#include "image_opencl_wrapper.h"
#include <cstdio>
#include <cstring>
#include "vpe_log.h"
// OpenCL Init
// Enable MY_DEBUG to support printf in kernel.
#define MY_TUNING
#ifdef MY_DEBUG
static void printf_callback(const char *buffer, size_t len, size_t complete, void *usr_data)
{
VPE_LOGI("output length: %{public}d\noutput data: \n%{public}s\n", (cl_uint)len, buffer);
}
#endif
static cl_int InitContext(ClContext *pCtx)
{
cl_int status = CL_SUCCESS;
// Get platform number
pCtx->numPlatforms = 0;
status = clGetPlatformIDs(0, nullptr, &pCtx->numPlatforms); // ~{DZ4fP9B)~}
CHECK_AND_RETURN_RET_LOG(!((status != CL_SUCCESS) || (pCtx->numPlatforms == 0)), status,
"[GPU]: Fail to get platform IDs1. (clGetPlatformIDs).");
VPE_LOGI("(clGetPlatformIDs). status = %{public}d, numPlatforms = %{public}d\n", status, pCtx->numPlatforms);
// Allocate tables for platform IDs, devices list header, devices number and device index
cl_uint numValue = pCtx->numPlatforms;
pCtx->platforms = reinterpret_cast<cl_platform_id *>(malloc(pCtx->numPlatforms * sizeof(cl_platform_id)));
CHECK_AND_RETURN_RET_LOG(pCtx->platforms != nullptr, CL_INVALID_VALUE, "pCtx platforms null!");
CHECK_AND_LOG(memset_sp(pCtx->platforms, numValue * sizeof(cl_platform_id), 0,
numValue * sizeof(cl_platform_id)) == 0, "memsetFail");
pCtx->numDevices = reinterpret_cast<cl_uint *>(malloc(pCtx->numPlatforms * sizeof(cl_uint)));
CHECK_AND_RETURN_RET_LOG(pCtx->numDevices != nullptr, CL_INVALID_VALUE, "pCtx numDevices null!");
CHECK_AND_LOG(memset_sp(pCtx->numDevices, numValue * sizeof(cl_uint), 0, numValue * sizeof(cl_uint)) == 0,
"memsetFail");
pCtx->idxDevices = reinterpret_cast<cl_uint *>(malloc(pCtx->numPlatforms * sizeof(cl_uint)));
CHECK_AND_RETURN_RET_LOG(pCtx->idxDevices != nullptr, CL_INVALID_VALUE, "pCtx idxDevices null!");
CHECK_AND_LOG(memset_sp(pCtx->idxDevices, numValue * sizeof(cl_uint), 0, numValue * sizeof(cl_uint)) == 0,
"memsetFail");
pCtx->devices = reinterpret_cast<cl_device_id **>(malloc(pCtx->numPlatforms * sizeof(cl_device_id *)));
CHECK_AND_RETURN_RET_LOG(pCtx->devices != nullptr, CL_INVALID_VALUE, "pCtx devices null!");
CHECK_AND_LOG(memset_sp(pCtx->devices, numValue * sizeof(cl_device_id *), 0,
numValue * sizeof(cl_device_id *)) == 0, "memsetFail");
for (cl_uint i = 0; i < pCtx->numPlatforms; i++) {
pCtx->devices[i] = nullptr;
}
return status;
}
static cl_int GetDevice(ClContext *pCtx)
{
cl_int status = CL_SUCCESS;
// Get platforms
status = clGetPlatformIDs(pCtx->numPlatforms, pCtx->platforms, nullptr);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status,
"[GPU]: Fail to get platform IDs2. (clGetPlatformIDs).");
// Get all devices for each of platform
for (cl_uint i = 0; i < pCtx->numPlatforms; i++) {
cl_uint numDevices = 0;
status = clGetDeviceIDs(pCtx->platforms[i], CL_DEVICE_TYPE_ALL, 0, nullptr, &numDevices);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status,
"[GPU]: Fail to get device IDs3. (clGetDeviceIDs).");
pCtx->numDevices[i] = numDevices;
pCtx->idxDevices[i] = (cl_uint)(-1);
if (numDevices == 0) {
pCtx->devices[i] = nullptr;
continue;
}
pCtx->devices[i] = reinterpret_cast<cl_device_id *>(malloc(numDevices * sizeof(cl_device_id)));
CHECK_AND_RETURN_RET_LOG(pCtx->devices[i] != nullptr, -1, "pCtx devices[i] null!");
status = clGetDeviceIDs(pCtx->platforms[i], CL_DEVICE_TYPE_ALL, numDevices, pCtx->devices[i], nullptr);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status,
"[GPU]: Fail to get device IDs4. (clGetDeviceIDs).");
}
return status;
}
static cl_int ChoosePlatform(ClContext *pCtx, cl_uchar infoBuf[], size_t lenInfoBuf, const char *vendorName)
{
cl_int status = CL_SUCCESS;
CHECK_AND_RETURN_RET_LOG(lenInfoBuf <= INFO_BUFFER_LENGTH, CL_DEVICE_NOT_FOUND, "lenInfoBuf>128!");
// Choose vendorName platform to work
pCtx->idxPlatforms = (cl_uint)(-1);
if (pCtx->numPlatforms == 1) {
pCtx->idxPlatforms = 0;
} else {
for (cl_uint i = 0; i < pCtx->numPlatforms; i++) {
// Get vendor name
status = clGetPlatformInfo(pCtx->platforms[i], CL_PLATFORM_VENDOR, INFO_BUFFER_LENGTH, infoBuf, nullptr);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status,
"[GPU]: Fail to get platform Info. (clGetPlatformInfo). ");
if (!strcmp(static_cast<const char *>(static_cast<void *>(infoBuf)), vendorName)) {
pCtx->idxPlatforms = i;
break;
}
}
}
// exit to host program if no vendorName is found.
if ((cl_uint)(-1) == pCtx->idxPlatforms) {
VPE_LOGE("[GPU]: There is no platform to use. exit.\n");
status = CL_DEVICE_NOT_AVAILABLE;
return status;
}
return status;
}
static cl_int ChooseDevice(ClContext *pCtx, cl_device_id *targetDevice, cl_uchar infoBuf[], size_t lenInfoBuf,
char *deviceName)
{
cl_int status = CL_SUCCESS;
CHECK_AND_RETURN_RET_LOG(lenInfoBuf <= INFO_BUFFER_LENGTH, CL_DEVICE_NOT_FOUND, "lenInfoBuf>128!");
// Choose GPU device to work
pCtx->idxDevices[pCtx->idxPlatforms] = (cl_uint)(-1);
for (cl_uint i = 0; i < pCtx->numDevices[pCtx->idxPlatforms]; i++) {
status =
clGetDeviceInfo(pCtx->devices[pCtx->idxPlatforms][i], CL_DEVICE_TYPE, INFO_BUFFER_LENGTH, infoBuf, nullptr);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status,
"[GPU]: Fail to get device Info. (clGetDeviceInfo).");
{
*targetDevice = pCtx->devices[pCtx->idxPlatforms][i];
pCtx->idxDevices[pCtx->idxPlatforms] = i;
break;
}
}
if (deviceName != nullptr) {
constexpr int deviceLength = 32;
status = clGetDeviceInfo(pCtx->devices[pCtx->idxPlatforms][pCtx->idxDevices[pCtx->idxPlatforms]],
CL_DEVICE_NAME,
deviceLength,
deviceName,
nullptr);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status,
"[GPU]: Fail to get device Info. (clGetDeviceInfo).");
deviceName[strlen(deviceName)] = '\0';
}
// exit to host program if no GPU device of vendorName is found.
CHECK_AND_RETURN_RET_LOG(!((cl_uint)(-1) == pCtx->idxDevices[pCtx->idxPlatforms]), CL_DEVICE_NOT_FOUND,
"[GPU]: There is no GPU to use. exit.");
return status;
}
static cl_int CreateContext(ClContext *pCtx, cl_device_id targetDevice)
{
cl_int status = CL_SUCCESS;
pCtx->context = clCreateContext(
nullptr, pCtx->numDevices[pCtx->idxPlatforms], pCtx->devices[pCtx->idxPlatforms], nullptr, nullptr, &status);
CHECK_AND_RETURN_RET_LOG(((status == CL_SUCCESS) || (pCtx->context == nullptr)), status,
"Error: Fail to create CL context.");
const cl_bitfield props[] = {CL_QUEUE_PRIORITY_KHR, CL_QUEUE_PRIORITY_LOW_KHR, 0};
pCtx->cmdQueueGPU = clCreateCommandQueueWithProperties(pCtx->context, targetDevice, props, &status);
CHECK_AND_RETURN_RET_LOG(!((status != CL_SUCCESS) || (pCtx->cmdQueueGPU == nullptr)), status,
"Error: Fail to create CL cmdQueueGPU.");
return status;
}
// These code need to be modified in the future if there are more platforms and devices
// and need other platform/device select policies.
static cl_int InitOpenCL(ClContext *pCtx, const char *vendorName, char *deviceName)
{
cl_uchar infoBuf[INFO_BUFFER_LENGTH] = {0};
cl_int status;
cl_device_id targetDevice = (cl_device_id)0;
status = InitContext(pCtx);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status, "InitContext fail!");
status = GetDevice(pCtx);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status, "GetDevice fail!");
status = ChoosePlatform(pCtx, infoBuf, sizeof(infoBuf), vendorName);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status, "ChoosePlatform fail!");
status = ChooseDevice(pCtx, &targetDevice, infoBuf, sizeof(infoBuf), deviceName);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status, "ChooseDevice fail!");
// Create context
status = CreateContext(pCtx, targetDevice);
CHECK_AND_RETURN_RET_LOG(status == CL_SUCCESS, status, "CreateContext fail!");
return status;
}
static void CleanDevice(ClContext *pCtx)
{
if (pCtx->cmdQueueGPU) {
// Get cmd queue ref count to ensure no memory leak.
cl_uchar infoBuf[INFO_BUFFER_LENGTH] = {0};
int status =
clGetCommandQueueInfo(pCtx->cmdQueueGPU, CL_QUEUE_REFERENCE_COUNT, sizeof(infoBuf), infoBuf, nullptr);
CHECK_AND_LOG(status == CL_SUCCESS, "[GPU] clGetCommandQueueInfo Failed!");
cl_int *infoBufTmp = reinterpret_cast<cl_int *>(infoBuf);
VPE_LOGI("[GPU]: cmd Queue ref count before release it : %{public}d\n", *infoBufTmp);
status = clReleaseCommandQueue(pCtx->cmdQueueGPU);
CHECK_AND_LOG(status == CL_SUCCESS, "[GPU] clReleaseCommandQueue Failed!");
}
if (pCtx->context) {
cl_uchar infoBuf[INFO_BUFFER_LENGTH] = {0};
// Get context ref count to ensure no memory leak.
int status = clGetContextInfo(pCtx->context, CL_CONTEXT_REFERENCE_COUNT, sizeof(infoBuf), infoBuf, nullptr);
CHECK_AND_LOG(status == CL_SUCCESS, "[GPU] clGetContextInfo Failed!");
cl_int *infoBufTmp = reinterpret_cast<cl_int *>(infoBuf);
VPE_LOGI("[GPU]: Context ref count before release it : %{public}d\n", *infoBufTmp);
status = clReleaseContext(pCtx->context);
CHECK_AND_LOG(status == CL_SUCCESS, "[GPU] clReleaseContext Failed!");
}
if (pCtx->devices != nullptr) {
for (cl_uint i = 0; i < pCtx->numPlatforms; i++) {
if (pCtx->devices[i] != nullptr) {
free(pCtx->devices[i]);
pCtx->devices[i] = nullptr;
}
}
free(pCtx->devices);
pCtx->devices = nullptr;
}
if (pCtx->idxDevices != nullptr) {
free(pCtx->idxDevices);
pCtx->idxDevices = nullptr;
}
if (pCtx->numDevices != nullptr) {
free(pCtx->numDevices);
pCtx->numDevices = nullptr;
}
if (pCtx->platforms != nullptr) {
free(pCtx->platforms);
pCtx->platforms = nullptr;
}
if (pCtx != nullptr) {
free(pCtx);
pCtx = nullptr;
}
}
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
void CleanOpencl(ClContext *pCtx)
{
if (pCtx == nullptr) {
VPE_LOGI("[GPU]: WARNING: ClneanOpencl input hadle is nullptr.\n");
} else {
// Release infrastructure like CmdQ/context. Show ref count to see if there is memory leak.
// Free the whole clContext created by setupOpencl.
CleanDevice(pCtx);
}
OHOS::Media::VideoProcessingEngine::ClDeInitOpenCL();
}
int SetupOpencl(void **pHandle, const char *vendorName, char *deviceName)
{
ClContext *pCtx = reinterpret_cast<ClContext *>(calloc(1, sizeof(ClContext)));
if (pCtx == nullptr) {
VPE_LOGE("[GPU]: SetupOpencl FAIL to allocate OpenCL Foundation context.\n");
*pHandle = nullptr;
return CL_MEM_OBJECT_ALLOCATION_FAILURE;
}
// Init CL infrastructure
cl_int status = InitOpenCL(pCtx, vendorName, deviceName);
if (status != CL_SUCCESS) {
CleanOpencl(pCtx);
*pHandle = nullptr;
return status;
}
*(reinterpret_cast<ClContext **>(pHandle)) = pCtx;
return static_cast<int>(status);
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,41 @@
/*
* 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.
*/
#ifndef INTERFACES_INNER_API_ALGORITHM_ALGORITHM_UTILS_H
#define INTERFACES_INNER_API_ALGORITHM_ALGORITHM_UTILS_H
#include <string>
#include "algorithm_errors.h"
#include "algorithm_video_common.h"
#include "surface_buffer.h"
#define VPE_TO_STR(val) (std::string(#val) + "(" + std::to_string(static_cast<int>(val)) + ")")
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class AlgorithmUtils {
public:
static std::string ToString(VPEAlgoErrCode errorCode);
static std::string ToString(VPEAlgoState state);
static bool CopySurfaceBufferToSurfaceBuffer(const sptr<SurfaceBuffer>& srcBuffer,
sptr<SurfaceBuffer>& destBuffer);
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // INTERFACES_INNER_API_ALGORITHM_ALGORITHM_UTILS_H
@@ -0,0 +1,176 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ALGORITHM_VIDEO_IMPL_H
#define ALGORITHM_VIDEO_IMPL_H
#include <atomic>
#include <cinttypes>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <set>
#include <string>
#include <thread>
#include "refbase.h"
#include "surface.h"
#include "algorithm_errors.h"
#include "algorithm_video.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class VpeVideoImpl : public VpeVideo, public std::enable_shared_from_this<VpeVideoImpl> {
public:
VPEAlgoErrCode RegisterCallback(const std::shared_ptr<VpeVideoCallback>& callback) override;
VPEAlgoErrCode SetOutputSurface(const sptr<Surface>& surface) override;
sptr<Surface> GetInputSurface() override;
VPEAlgoErrCode Start() override;
VPEAlgoErrCode Stop() override;
VPEAlgoErrCode Release() override;
VPEAlgoErrCode Flush() override;
VPEAlgoErrCode Enable() override;
VPEAlgoErrCode Disable() override;
VPEAlgoErrCode NotifyEos() override;
VPEAlgoErrCode ReleaseOutputBuffer(uint32_t index, bool render) override;
VPEAlgoErrCode RenderOutputBufferAtTime(uint32_t index, int64_t renderTimestamp) override;
protected:
explicit VpeVideoImpl(uint32_t type) : type_(type) {}
virtual ~VpeVideoImpl();
VpeVideoImpl(const VpeVideoImpl&) = delete;
VpeVideoImpl& operator=(const VpeVideoImpl&) = delete;
VpeVideoImpl(VpeVideoImpl&&) = delete;
VpeVideoImpl& operator=(VpeVideoImpl&&) = delete;
bool IsInitialized() const;
VPEAlgoErrCode Initialize();
VPEAlgoErrCode Deinitialize();
void RefreshBuffers();
void OnOutputFormatChanged(const Format& format);
virtual VPEAlgoErrCode OnInitialize();
virtual VPEAlgoErrCode OnDeinitialize();
virtual VPEAlgoErrCode Process(const sptr<SurfaceBuffer>& sourceImage, sptr<SurfaceBuffer>& destinationImage);
virtual bool IsProducerSurfaceValid(const sptr<Surface>& surface);
virtual VPEAlgoErrCode UpdateRequestCfg(const sptr<Surface>& surface, BufferRequestConfig& requestCfg);
virtual void UpdateRequestCfg(const sptr<SurfaceBuffer>& consumerBuffer, BufferRequestConfig& requestCfg);
private:
enum class VPEState : int {
IDLE = 0,
RUNNING,
STOPPING
};
struct SurfaceBufferInfo {
sptr<SurfaceBuffer> buffer{};
VpeBufferFlag bufferFlag{VPE_BUFFER_FLAG_NONE};
int64_t timestamp{};
};
class ConsumerListener : public IBufferConsumerListener {
public:
explicit ConsumerListener(const std::shared_ptr<VpeVideoImpl>& owner) : owner_(owner) {}
virtual ~ConsumerListener() = default;
ConsumerListener(const ConsumerListener&) = delete;
ConsumerListener& operator=(const ConsumerListener&) = delete;
ConsumerListener(ConsumerListener&&) = delete;
ConsumerListener& operator=(ConsumerListener&&) = delete;
void OnBufferAvailable() final;
private:
std::weak_ptr<VpeVideoImpl> owner_;
};
void OnErrorLocked(VPEAlgoErrCode errorCode);
void OnStateLocked(VPEAlgoState state);
void OnEffectChange(uint32_t type);
void OnOutputBufferAvailable(uint32_t index, const VpeBufferInfo& info);
GSError OnConsumerBufferAvailable();
GSError OnProducerBufferReleased();
VPEAlgoErrCode RenderOutputBufferLocked(uint32_t index, int64_t renderTimestamp, bool render);
sptr<Surface> CreateConsumerSurfaceLocked();
bool RequestBuffer(SurfaceBufferInfo& bufferInfo, GSError& errorCode);
void PrepareBuffers();
void AttachBuffers(const sptr<Surface>& producer);
void AttachBuffers(const sptr<Surface>& producer, std::queue<SurfaceBufferInfo>& bufferQueue);
void ProcessBuffers();
bool ProcessBuffer(sptr<Surface>& consumer, SurfaceBufferInfo& srcBufferInfo, SurfaceBufferInfo& dstBufferInfo);
void BypassBuffer(SurfaceBufferInfo& srcBufferInfo, SurfaceBufferInfo& dstBufferInfo);
void OutputBuffer(const SurfaceBufferInfo& bufferInfo, const SurfaceBufferInfo& bufferImage, bool isProcessed,
std::function<void(void)>&& getReadyToRender);
bool PopBuffer(std::queue<SurfaceBufferInfo>& bufferQueue, uint32_t index, SurfaceBufferInfo& bufferInfo,
std::function<void(sptr<SurfaceBuffer>&)>&& func);
void SetRequestCfgLocked(const sptr<SurfaceBuffer>& buffer);
void CheckSpuriousWakeup();
bool CheckStopping();
bool CheckStoppingLocked();
void ClearQueue(std::queue<SurfaceBufferInfo>& bufferQueue);
void ClearConsumerLocked(std::queue<SurfaceBufferInfo>& bufferQueue);
void ClearBufferQueues();
VPEAlgoErrCode ExecuteWhenIdle(std::function<VPEAlgoErrCode(void)>&& operation, const std::string& errorMessage);
VPEAlgoErrCode ExecuteWhenNotIdle(std::function<VPEAlgoErrCode(void)>&& operation, const std::string& errorMessage);
VPEAlgoErrCode ExecuteWhenRunning(std::function<VPEAlgoErrCode(void)>&& operation, const std::string& errorMessage);
VPEAlgoErrCode ExecuteWithCheck(std::function<bool(void)>&& checker,
std::function<VPEAlgoErrCode(void)>&& operation, const std::string& errorMessage);
// Common
uint32_t type_{};
// For thread control
std::condition_variable cvTrigger_{};
std::condition_variable cvDone_{};
mutable std::mutex lock_{};
// Guarded by lock_ begin
std::atomic<bool> isInitialized_{false};
std::atomic<bool> isRunning_{false};
std::atomic<bool> isProcessing_{false};
std::atomic<bool> isEnable_{true};
std::atomic<bool> isEnableChange_{true};
std::atomic<VPEState> state_{VPEState::IDLE};
std::thread worker_{};
std::shared_ptr<VpeVideoCallback> cb_{};
sptr<Surface> consumer_{};
sptr<Surface> producer_{};
BufferRequestConfig requestCfg_{};
BufferRequestConfig orgRequestCfg_{};
// Guarded by lock_ end
mutable std::mutex bufferLock_{};
// Guarded by bufferLock_ begin
bool isBufferQueueReady_{};
std::queue<SurfaceBufferInfo> consumerBufferQueue_{};
std::queue<SurfaceBufferInfo> producerBufferQueue_{};
std::queue<SurfaceBufferInfo> renderBufferQueue_{};
std::queue<SurfaceBufferInfo> flushBufferQueue_{};
std::queue<SurfaceBufferInfo> attachBufferQueue_{};
std::set<uint32_t> attachBufferIDs_{};
// Guarded by bufferLock_ end
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // ALGORITHM_VIDEO_IMPL_H
@@ -0,0 +1,52 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COMMON_FRAME_INFO_H
#define FRAMEWORK_ALGORITHM_COMMON_FRAME_INFO_H
#include <stdint.h>
#include "algorithm_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
enum class BitDepth {
BIT_DEPTH_8, // 8bit位深
BIT_DEPTH_10, // 10bit位深
BIT_DEPTH_FP16 // 16bit位深,fp16格式
};
struct FrameInfo {
uint32_t width = 0; // 输入输出最大图像宽
uint32_t height = 0; // 输入输出最大图像高
uint32_t widthStride = 0; // input and output img width stride(padding at the end of the lines)
uint32_t heightStride = 0; // input and output img height stride
BitDepth bitDepth = BitDepth::BIT_DEPTH_8; // 输入图像位宽
GraphicPixelFormat pixelFormat = GRAPHIC_PIXEL_FMT_RGBA_8888; // 像素格式
ColorSpaceDescription colorSpace = {GetColorSpaceInfo(CM_SRGB_FULL), CM_METADATA_NONE};
FrameInfo() = default;
explicit FrameInfo(const sptr<SurfaceBuffer> &buffer);
};
struct ColorSpaceInfo {
GraphicPixelFormat pixelFormat = GRAPHIC_PIXEL_FMT_RGBA_8888; // 像素格式
CM_ColorSpaceType colorSpace = CM_SRGB_FULL; // 颜色空间
CM_HDR_Metadata_Type metadataType = CM_METADATA_NONE; // 颜色空间标志
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COMMON_FRAME_INFO_H
@@ -0,0 +1,92 @@
/*
* 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.
*/
#ifndef VPE_FRAMEWORK_ALGORITHM_COMMON_HDR_VIVID_METADATA_V1_H
#define VPE_FRAMEWORK_ALGORITHM_COMMON_HDR_VIVID_METADATA_V1_H
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
struct HdrVividMetadataV1 {
unsigned int systemStartCode; // 表示系统版本号
// minimum_maxrgb_pq,表示显示内容的最小亮度,pq域,范围从0~4095
unsigned int minimumMaxRgbPq;
unsigned int averageMaxRgbPq; // average_maxrgb_pq,表示显示内容的平均亮度,pq域,范围从0.0~4095
// variance_maxrgb_pq,表示显示内容的变化范围,pq域,范围从0.0~4095
unsigned int varianceMaxRgbPq;
unsigned int maximumMaxRgbPq; // maximum_maxrgb_pq,表示显示内容的最大亮度,pq域,范围从0.0~4095
// tone_mapping_enable_mode_flag,取值为0或1,若为0,则不传曲线参数,否则传输参数
unsigned int toneMappingMode;
// tone_mapping_para_enable_num,表示当前色调映射参数组的数目减1,
// 为0时色调映射参数组的数目为1,为1时色调映射参数组的数目为2
unsigned int toneMappingParamNum;
// targeted_system_display_maximum_luminancePq,参考目标显示器最高亮度,范围从0.0~4095,
// 数组长度为2说明有2组参数,tone_mapping_param_num
unsigned int targetedSystemDisplayMaximumLuminance[2];
// base_enable_flag,基础曲线标识,取值为0或1,为0则不传输基础曲线参数,为1则传输参数
unsigned int baseFlag[4];
unsigned int baseParamMp[2]; // 范围0~16383
unsigned int baseParamMm[2]; // 范围0~63
unsigned int baseParamMa[2]; // 范围0~1023
unsigned int baseParamMb[2]; // 范围0~1023
unsigned int baseParamMn[2]; // 范围0~63
unsigned int baseParamK1[2]; // 分小于等于1 和 大于1两种情况
unsigned int baseParamK2[2]; // 分小于等于1 和 大于1两种情况
unsigned int baseParamK3[2]; // 分小于等于1 和 1~2 和 大于2两种情况
// base_param_delta_enable_mode,标识当前基础曲线映射参数的调整系数模式
unsigned int baseParamDeltaMode[2];
// base_param_enable_delta,标识当前基础曲线映射参数的调整系数值,范围0~127
unsigned int baseParamDelta[2];
// 3Spline_enable_flag,二值变量,为1时标识传输三次样条参数,为0时不传
unsigned int threeSplineFlag[2];
unsigned int threeSplineNum[2]; // 3Spline_enable_num,标识三次样条区间数量,取值为0和1
// 3Spline_TH_enable_mode,标识色调映射的三次样条模式,范围为0~3,
// 这里数组长度4是由于P3Spline_num
unsigned int threeSplineThMode[2][4];
// 3Spline_TH_enable_MB,指示色调映射的三次样条区间参数的斜率和暗区偏移量
unsigned int threeSplineThMb[2][4];
// 3Spline_TH_enable, 指示色调映射的三次样条区间参数,范围0~4095,第三维度表示三次样
// 条区间参数(0~4095)、三次样条区间1偏移量(0~1023)和三次样条区间2偏移量(0~1023)
unsigned int threeSplineTh[2][4][3];
// 3Spline_enable_Strength,指示色调映射的三次样条区间的修正幅度参数,范围0~255
unsigned int threeSplineStrength[2][4];
unsigned int colorSaturationMappingFlag; // 对应标准中color_saturation_mapping_enable_flag
unsigned int colorSaturationNum; // 对应标准中color_saturation_enable_num
unsigned int colorSaturationGain[16]; // 对应标准中color_saturation_enable_gain
std::vector<uint8_t> gtmLut; // 存储aihdr生成的lut
};
// C-Link paramter
typedef struct HwDisplayMeta {
unsigned int type; // 0x03
unsigned int size; // meta大小
unsigned int startX;
unsigned int startY;
unsigned int endX;
unsigned int endY;
unsigned int lutMap[17];
unsigned int averageLuma;
unsigned int scene; // 0 风景 1 人像
unsigned int expo;
unsigned int iso;
unsigned int flash;
unsigned int hdrHistgram[32];
unsigned int noiseLevel;
unsigned int apetureValue;
unsigned int aelv;
unsigned int maxHeadroom;
} HwDisplayMeta;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // VPE_FRAMEWORK_ALGORITHM_COMMON_HDR_VIVID_METADATA_V1_H
@@ -0,0 +1,54 @@
/*
* 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.
*/
#ifndef IMAGE_OPENCL_WRAPPER_H_
#define IMAGE_OPENCL_WRAPPER_H_
#include <memory>
#include <string>
#define CL_TARGET_OPENCL_VERSION 300
#include <CL/cl.h>
#include <CL/cl_ext.h>
#define MS_ASSERT(f) ((void)0)
namespace OHOS {
// This is a opencl function wrapper.
namespace Media {
using clImportMemoryFunc = cl_mem (*)(cl_context, cl_mem_flags, const cl_import_properties_arm *, void *, size_t,
cl_int *);
extern clImportMemoryFunc clImportMemory;
} // namespace Media
} // namespace OHOS
struct ClImportMemoryParam {
cl_context context;
cl_mem_flags flags;
const cl_import_properties_arm* properties;
void* fd;
size_t size;
cl_int* errcode_ret;
};
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
extern cl_mem ClImportMemory(ClImportMemoryParam clImportMemoryParam);
extern void ClDeInitOpenCL();
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // IMAGE_OPENCL_WRAPPER_H_
@@ -0,0 +1,53 @@
/*
* 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.
*/
#ifndef IMAGE_OPENCL_SETUP_H
#define IMAGE_OPENCL_SETUP_H
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <CL/opencl.h>
#include <CL/cl_egl.h>
struct ClContext {
// Platform and device
cl_platform_id *platforms{};
cl_uint numPlatforms{}; // Total platforms
cl_uint idxPlatforms{}; // Current platform
cl_device_id **devices{}; // Devices[idxPlatforms] is link list header of platform[idxPlatforms]
cl_uint *numDevices{}; // each numDevices[i] record device number of each platform.
cl_uint *idxDevices{}; // Current device under current platform
// CL Context and Command queue
cl_context context{};
cl_command_queue cmdQueueGPU{};
cl_command_queue cmdQueueCPU{};
cl_command_queue cmdQueueDSP{};
cl_command_queue cmdQueueOther{};
};
#define INFO_BUFFER_LENGTH 128
extern "C" {
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
int SetupOpencl(void **pHandle, const char *vendorName, char *deviceName);
void CleanOpencl(ClContext *pCtx);
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
}
#endif // IMAGE_OPENCL_SETUP_H
@@ -0,0 +1,43 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_COMMON_CREAT_CONTEXT_H
#define FRAMEWORK_ALGORITHM_COMMON_CREAT_CONTEXT_H
#include <stdint.h>
#include "algorithm_common.h"
#include "image_openclsetup.h"
#include "EGL/egl.h"
typedef void *EGLDisplay;
struct OpenGLContext {
EGLDisplay display {EGL_NO_DISPLAY};
EGLContext context {EGL_NO_CONTEXT};
};
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
typedef void *EGLDisplay;
struct VPEContext {
ClContext *clContext {nullptr};
EGLDisplay glDisplay {EGL_NO_DISPLAY};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_COMMON_FRAME_INFO_H
@@ -0,0 +1,76 @@
/*
* 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.
*/
#ifndef VPE_FRAMEWORK_ALGORITHM_COMMON_PARSE_METADATA_H
#define VPE_FRAMEWORK_ALGORITHM_COMMON_PARSE_METADATA_H
#include <vector>
#include "hdr_vivid_metadata_v1.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
constexpr int METADATA_MAX_LENGTH = 512;
constexpr int AIHDR_METADATA_MAX_LENGTH = 128;
// 以下变量根据CUVA标准7.4确定了每个元数据所占用的bit数
using CuvaMetadataBitNum = enum {
SYSTEM_START_CODE_BIT = 8,
MINIMUM_MAXRGB_BIT = 12,
AVERAGE_MAXRGB_BIT = 12,
VARIANCE_MAXRGB_BIT = 12,
MAXIMUM_MAXRGB_BIT = 12,
TONE_MAPPING_MODE_BIT = 1,
TONE_MAPPING_PARAM_NUM_BIT = 1,
TARGETED_SYSTEM_DISPLAY_BIT = 12,
BASE_FLAG_BIT = 1,
BASE_PARAM_MP_BIT = 14,
BASE_PARAM_MM_BIT = 6,
BASE_PARAM_MA_BIT = 10,
BASE_PARAM_MB_BIT = 10,
BASE_PARAM_MN_BIT = 6,
BASE_PARAM_K1_BIT = 2,
BASE_PARAM_K2_BIT = 2,
BASE_PARAM_K3_BIT = 4,
BASE_PARAM_DELTA_MODE_BIT = 3,
BASE_PARAM_DELTA_BIT = 7,
P3SPLINE_FLAG_BIT = 1,
P3SPLINE_NUM_BIT = 1,
P3SPLINE_TH_MODE_BIT = 2,
P3SPLINE_TH_MB_BIT = 8,
P3SPLINE_TH_OFFSET_BIT = 2,
P3SPLINE_TH1_BIT = 12,
P3SPLINE_TH2_BIT = 10,
P3SPLINE_TH3_BIT = 10,
P3SPLINE_STRENGTH_BIT = 8,
COLOR_SATURATION_BIT = 1,
COLOR_SATURATION_NUM_BIT = 3,
COLOR_SATURATION_GAIN_BIT = 8,
CUVA_TWELVE_BIT_NUM = 4095,
CUVA_LOW_AREA_CURVE = 0,
CUVA_SPLINE_AREA_CURVE = 1,
CUVA_HIGH_AREA_CURVE = 2,
CUVA_TYPE_BIT = 4,
MARKERBIT_BIT = 1,
DISPLAY_3BIT = 3,
DISPLAY_8BIT = 8,
DISPLAY_MARKERBIT = 1,
DISPLAY_16BIT = 16
};
int PraseMetadataFromArray(const std::vector<uint8_t> &cuvaInfo, HdrVividMetadataV1 &tmoCuvaMetadata,
HwDisplayMeta &displayMeta);
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // VPE_FRAMEWORK_ALGORITHM_COMMON_PARSE_METADATA_H
@@ -0,0 +1,47 @@
/*
* 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 IMAGE_PROCESSING_UTILS_IMPL_H
#define IMAGE_PROCESSING_UTILS_IMPL_H
#include "pixelmap_native_impl.h"
#include "surface_buffer.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class VpeUtils {
public:
static sptr<SurfaceBuffer> GetSurfaceBufferFromPixelMap(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap);
static bool ConvertPixelmapToSurfaceBuffer(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap, sptr<SurfaceBuffer> bufferImpl);
static bool ConvertSurfaceBufferToPixelmap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap);
static bool SetSurfaceBufferToPixelMap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap);
static bool CopyRGBASurfaceBufferToPixelmap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap);
static bool CopyRGBAPixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap,
sptr<SurfaceBuffer>& buffer);
static bool CopyNV12SurfaceBufferToPixelmap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap);
static bool CopyNV12PixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap,
sptr<SurfaceBuffer>& buffer);
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // IMAGE_PROCESSING_UTILS_IMPL_H
@@ -0,0 +1,25 @@
/*
* 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.
*/
#include "vpe_context.h"
#include "vpe_log.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
CreatContext::VPEContext() {}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,312 @@
/*
* 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.
*/
#include "vpe_parse_metadata.h"
#include <cstdint>
#include <vector>
#include "vpe_log.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
// 做了字节颠倒ˇ把4个字节逆序排列
static inline uint32_t ConvertEndian(uint32_t x)
{
// 8 & 24: bit offset; 0x0000ff00 & 0x00ff0000 & 0x000000ff: bit mask
return ((x << 24) | ((x & 0x0000ff00) << 8) | ((x & 0x00ff0000) >> 8) | ((x >> 24) & 0x000000ff));
}
struct BsInfo {
uint8_t *head;
uint8_t *tail;
uint32_t bufA;
uint32_t bufB;
int32_t bsLen;
int32_t bufPos;
uint32_t totalPos;
};
static void InitBs(BsInfo *bs, const uint8_t *input, int32_t length)
{
uint32_t data;
uint64_t alignWord = 0x3; // 使首地址4字节对齐
bs->head = reinterpret_cast<uint8_t *>(reinterpret_cast<uintptr_t>(input) & ~alignWord);
bs->tail = bs->head + 8; // 8 :将尾地址初始化为首地址8字节之后
bs->bsLen = length;
data = *reinterpret_cast<uint32_t *>(bs->head);
bs->bufA = ConvertEndian(data);
// 4 :读取后4个字节的值传给bufBˇ当要取的元数据跨越两段4字节时会用到
data = *reinterpret_cast<uint32_t *>(bs->head + 4);
bs->bufB = ConvertEndian(data);
// 3 is bit ofsˇ记录对齐地址和实际地址的偏差量
bs->bufPos = (reinterpret_cast<uintptr_t>(input) & 0x3) << 3;
bs->totalPos = 0;
return;
}
static int32_t ShowBs(const BsInfo *bs, int32_t currentBitNum)
{
uint32_t pos = static_cast<uint32_t>(bs->bufPos);
// 0x20:4字节ˇ如果对齐后和实际地址的偏差量大于4字节ˇ或要读取的位数为0
// 或要取的位数大于4字节ˇ直接返回0
if (pos >= 0x20 || currentBitNum == 0 || currentBitNum > 0x20) {
return 0;
}
// 要读取的位数超出剩余码流的位数时,直接返回0
// 8 :一个字节占8位ˇ当前读取位小于传入数组总位数才合理
if (static_cast<uint32_t>(bs->totalPos + currentBitNum) > static_cast<uint32_t>(bs->bsLen * 8)) {
return 0;
}
// 0x20ˇ32ˇ如果要取的元数据要跨越两段4个字节ˇ则要取两次值进行拼接。
uint32_t data = 0;
int32_t abPos = currentBitNum + bs->bufPos;
if (abPos > 0x20) {
data = bs->bufA << pos;
// 0x20-pos为高四节数值和低四节数值的位偏移量ˇ移位后data1和data对齐
uint32_t data1 = (pos == 0) ? 0 : (bs->bufB >> (0x20 - pos));
data |= data1;
data >>= static_cast<uint32_t>(0x20 - currentBitNum); // 0x20:4字节
} else { // 如果要取的元数据没有跨越两个4字节ˇ则直接读取bufA移位后的值。0x20:4字节
data = (bs->bufA << pos) >> static_cast<uint32_t>(0x20 - currentBitNum);
}
return static_cast<int32_t>(data);
}
static int32_t SkipBs(BsInfo *bs, int32_t currentBitNum)
{
bs->totalPos += static_cast<uint32_t>(currentBitNum);
// 8 :一个字节占8位ˇ当前读取位小于传入数组总位数才合理
if (bs->totalPos < static_cast<uint32_t>(bs->bsLen * 8)) {
int32_t abPos = currentBitNum + bs->bufPos;
if (abPos >= 32) { // 32 :如果ˇ地址偏移量+读取位数ˇ大于4字节
bs->bufPos = abPos - 32; // 32 :则更新偏移量为(地址偏移量+读取位数)%32
bs->bufA = bs->bufB; // 前四字节的buf更新为后4字节的buf
uint32_t data = *reinterpret_cast<uint32_t *>(bs->tail);
bs->bufB = ConvertEndian(data);
bs->tail += 4; // 4 :整体ˇ后移4字节
} else {
bs->bufPos += currentBitNum;
}
}
return currentBitNum;
}
static __inline int32_t GetBs(BsInfo *bs, int32_t currentBitNum)
{
uint32_t data = static_cast<uint32_t>(ShowBs(bs, currentBitNum));
SkipBs(bs, currentBitNum);
return static_cast<int32_t>(data);
}
static uint32_t HevcUv(BsInfo *bsPtr, int32_t bitNum)
{
uint32_t code = static_cast<uint32_t>(GetBs(bsPtr, bitNum));
return code;
}
void SetThreeSpline(BsInfo *bsPtr, HdrVividMetadataV1 &tmoCuvaMetadata, int index)
{
for (unsigned int mode_i = 0; mode_i < tmoCuvaMetadata.threeSplineNum[index]; mode_i++) {
tmoCuvaMetadata.threeSplineThMode[index][mode_i] = HevcUv(bsPtr, P3SPLINE_TH_MODE_BIT);
// 对应标准7.3
if ((tmoCuvaMetadata.threeSplineThMode[index][mode_i] == 0) ||
(tmoCuvaMetadata.threeSplineThMode[index][mode_i] == 2)) { // 2:
tmoCuvaMetadata.threeSplineThMb[index][mode_i] = HevcUv(bsPtr, P3SPLINE_TH_MB_BIT);
}
tmoCuvaMetadata.threeSplineTh[index][mode_i][0] = HevcUv(bsPtr, P3SPLINE_TH1_BIT);
tmoCuvaMetadata.threeSplineTh[index][mode_i][1] = HevcUv(bsPtr, P3SPLINE_TH2_BIT);
tmoCuvaMetadata.threeSplineTh[index][mode_i][2] = HevcUv(bsPtr, P3SPLINE_TH3_BIT); // 2:
tmoCuvaMetadata.threeSplineStrength[index][mode_i] = HevcUv(bsPtr, P3SPLINE_STRENGTH_BIT);
}
}
int SetToneMappingMode(BsInfo *bsPtr, HdrVividMetadataV1 &tmoCuvaMetadata)
{
if (!tmoCuvaMetadata.toneMappingMode) {
return 0;
}
tmoCuvaMetadata.toneMappingParamNum = HevcUv(bsPtr, TONE_MAPPING_PARAM_NUM_BIT);
// test
tmoCuvaMetadata.toneMappingParamNum++;
// For Memory Safety
// tone_mapping_param_num占用1bitˇ最大为1ˇ加1后最大为2
if (tmoCuvaMetadata.toneMappingParamNum > 2) {
VPE_LOGE("ToneMappingParamNum Out Of Range, value: %i", tmoCuvaMetadata.toneMappingParamNum);
return 1;
}
for (unsigned int j = 0; j < tmoCuvaMetadata.toneMappingParamNum; j++) {
tmoCuvaMetadata.targetedSystemDisplayMaximumLuminance[j] = HevcUv(bsPtr, TARGETED_SYSTEM_DISPLAY_BIT);
tmoCuvaMetadata.baseFlag[j] = HevcUv(bsPtr, BASE_FLAG_BIT);
if (tmoCuvaMetadata.baseFlag[j]) {
tmoCuvaMetadata.baseParamMp[j] = HevcUv(bsPtr, BASE_PARAM_MP_BIT);
tmoCuvaMetadata.baseParamMm[j] = HevcUv(bsPtr, BASE_PARAM_MM_BIT);
tmoCuvaMetadata.baseParamMa[j] = HevcUv(bsPtr, BASE_PARAM_MA_BIT);
tmoCuvaMetadata.baseParamMb[j] = HevcUv(bsPtr, BASE_PARAM_MB_BIT);
tmoCuvaMetadata.baseParamMn[j] = HevcUv(bsPtr, BASE_PARAM_MN_BIT);
tmoCuvaMetadata.baseParamK1[j] = HevcUv(bsPtr, BASE_PARAM_K1_BIT);
tmoCuvaMetadata.baseParamK2[j] = HevcUv(bsPtr, BASE_PARAM_K2_BIT);
tmoCuvaMetadata.baseParamK3[j] = HevcUv(bsPtr, BASE_PARAM_K3_BIT);
tmoCuvaMetadata.baseParamDeltaMode[j] = HevcUv(bsPtr, BASE_PARAM_DELTA_MODE_BIT);
tmoCuvaMetadata.baseParamDelta[j] = HevcUv(bsPtr, BASE_PARAM_DELTA_BIT);
}
tmoCuvaMetadata.threeSplineFlag[j] = HevcUv(bsPtr, P3SPLINE_FLAG_BIT);
if (tmoCuvaMetadata.threeSplineFlag[j]) {
tmoCuvaMetadata.threeSplineNum[j] = HevcUv(bsPtr, P3SPLINE_NUM_BIT);
tmoCuvaMetadata.threeSplineNum[j]++;
// For Memory Safety
// p3SplineNum占用1bitˇ最大为1ˇ加1后最大为2
if (tmoCuvaMetadata.threeSplineNum[j] > 2) {
VPE_LOGE("ThreeSplineNum Out Of Range, value: %i", tmoCuvaMetadata.threeSplineNum[j]);
return 1;
}
SetThreeSpline(bsPtr, tmoCuvaMetadata, j);
}
}
return 0;
}
int SetcolorSaturationMapping(BsInfo *bsPtr, HdrVividMetadataV1 &tmoCuvaMetadata)
{
if (tmoCuvaMetadata.colorSaturationMappingFlag) {
tmoCuvaMetadata.colorSaturationNum = HevcUv(bsPtr, COLOR_SATURATION_NUM_BIT);
// For Memory Safety
if (tmoCuvaMetadata.colorSaturationNum > 8) { // 8:
VPE_LOGE("ColorSaturationNum Out Of Range, value: %i", tmoCuvaMetadata.colorSaturationNum);
return 1;
}
for (unsigned int mode_i = 0; mode_i < tmoCuvaMetadata.colorSaturationNum; mode_i++) {
tmoCuvaMetadata.colorSaturationGain[mode_i] = HevcUv(bsPtr, COLOR_SATURATION_GAIN_BIT);
}
}
return 0;
}
void PraseDisplayMetadataFromArray(BsInfo *bsPtr, HwDisplayMeta &displayMeta)
{
// HwDisplayMeta displayMeta;
displayMeta.type = HevcUv(bsPtr, DISPLAY_3BIT);
VPE_LOGD("displayMeta type = %{public}d", displayMeta.type);
if (displayMeta.type > 0) {
displayMeta.size = HevcUv(bsPtr, DISPLAY_16BIT);
auto markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.startX = HevcUv(bsPtr, DISPLAY_16BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.startY = HevcUv(bsPtr, DISPLAY_16BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.endX = HevcUv(bsPtr, DISPLAY_16BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.endY = HevcUv(bsPtr, DISPLAY_16BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
for (int i = 0; i < 17; i++) { // 17
displayMeta.lutMap[i] = HevcUv(bsPtr, DISPLAY_8BIT);
if (i % 2 == 1) { // 2
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
}
}
displayMeta.averageLuma = HevcUv(bsPtr, DISPLAY_16BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.scene = HevcUv(bsPtr, DISPLAY_8BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.expo = HevcUv(bsPtr, DISPLAY_16BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.iso = HevcUv(bsPtr, DISPLAY_16BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.flash = HevcUv(bsPtr, DISPLAY_8BIT);
for (int i = 0; i < 32; i++) { // 32
displayMeta.hdrHistgram[i] = HevcUv(bsPtr, DISPLAY_8BIT);
if (i % 2 == 0) { // 2
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
}
}
displayMeta.noiseLevel = HevcUv(bsPtr, DISPLAY_8BIT);
markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.apetureValue = HevcUv(bsPtr, DISPLAY_8BIT);
displayMeta.aelv = HevcUv(bsPtr, DISPLAY_8BIT);
displayMeta.maxHeadroom = 5115; // 5115 = 5 * 1023;
VPE_LOGD("CLink displayMeta.markerbit = %{public}d\n", markerbit);
}
if (displayMeta.type > 1) {
auto markerbit = HevcUv(bsPtr, DISPLAY_MARKERBIT);
displayMeta.maxHeadroom = HevcUv(bsPtr, DISPLAY_16BIT);
VPE_LOGD("CLink displayMeta.markerbit = %{public}d\n", markerbit);
VPE_LOGD("CLink displayMeta.maxHeadroom = %{public}d\n", displayMeta.maxHeadroom);
}
return;
}
uint32_t PraseMatadataType(BsInfo *bsPtr)
{
HevcUv(bsPtr, MARKERBIT_BIT);
uint32_t type = HevcUv(bsPtr, CUVA_TYPE_BIT);
VPE_LOGD("HDR: extension metadata type = %{public}d", type);
return type;
}
int PraseMetadataFromArray(const std::vector<uint8_t> &cuvaInfo, HdrVividMetadataV1 &tmoCuvaMetadata,
HwDisplayMeta &displayMeta)
{
BsInfo bs {};
BsInfo *bsPtr = &bs;
int cuvaInfoSize = static_cast<int>(cuvaInfo.size());
if (cuvaInfoSize == AIHDR_METADATA_MAX_LENGTH) {
tmoCuvaMetadata.gtmLut = cuvaInfo;
}
VPE_LOGD("cuvaInfoSize = %{public}d\n", cuvaInfoSize);
std::vector<uint8_t> cuvaInfoCopy;
if (cuvaInfoSize > METADATA_MAX_LENGTH) { // 最大metadata长度512
cuvaInfoSize = METADATA_MAX_LENGTH;
}
cuvaInfoCopy.resize(METADATA_MAX_LENGTH); // 最大metadata长度512
errno_t res = memcpy_s(cuvaInfoCopy.data(), cuvaInfoCopy.size(), cuvaInfo.data(), cuvaInfo.size());
CHECK_AND_RETURN_RET_LOG(res == EOK, res, "memcpy_s failed");
InitBs(bsPtr, &cuvaInfoCopy[0], cuvaInfoSize);
tmoCuvaMetadata.systemStartCode = HevcUv(bsPtr, SYSTEM_START_CODE_BIT);
int numWindows = 0;
if (tmoCuvaMetadata.systemStartCode == 1) {
numWindows = 1;
}
for (int i = 0; i < numWindows; i++) {
tmoCuvaMetadata.minimumMaxRgbPq = HevcUv(bsPtr, MINIMUM_MAXRGB_BIT);
tmoCuvaMetadata.averageMaxRgbPq = HevcUv(bsPtr, AVERAGE_MAXRGB_BIT);
tmoCuvaMetadata.varianceMaxRgbPq = HevcUv(bsPtr, VARIANCE_MAXRGB_BIT);
tmoCuvaMetadata.maximumMaxRgbPq = HevcUv(bsPtr, MAXIMUM_MAXRGB_BIT);
tmoCuvaMetadata.toneMappingMode = HevcUv(bsPtr, TONE_MAPPING_MODE_BIT);
int ret = SetToneMappingMode(bsPtr, tmoCuvaMetadata);
if (ret != 0) { return ret; }
tmoCuvaMetadata.colorSaturationMappingFlag = HevcUv(bsPtr, COLOR_SATURATION_BIT);
ret = SetcolorSaturationMapping(bsPtr, tmoCuvaMetadata);
if (ret != 0) { return ret; }
}
// 8 :一个字节占8位ˇ当前读取位小于传入数组总位数才合理
while (bsPtr->totalPos + 8 < static_cast<uint32_t>(bsPtr->bsLen * 8)) { // 存在后续元数据内容
uint32_t metadataType = PraseMatadataType(bsPtr);
if ((metadataType & 0x3) == 1) {
// ToDo: Prase LocalToneMapping Metadata
VPE_LOGD("LTM Metadata Prase!");
} else if ((metadataType & 0x3) == 3) { // 3 拍显元数据标志位
VPE_LOGD("CLink Metadata Prase!");
PraseDisplayMetadataFromArray(bsPtr, displayMeta);
} else {
VPE_LOGD("Unknown Extension Metadata type!");
break;
}
}
return 0;
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,265 @@
/*
* 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 "vpe_utils_common.h"
#include <unordered_map>
#include "algorithm_utils.h"
#include "surface_buffer_impl.h"
#include "surface_type.h"
#include "vpe_log.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
namespace {
const std::map<OHOS::Media::PixelFormat, GraphicPixelFormat> FORMAT_MAP = {
{ OHOS::Media::PixelFormat::RGBA_8888, GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888 },
{ OHOS::Media::PixelFormat::BGRA_8888, GraphicPixelFormat::GRAPHIC_PIXEL_FMT_BGRA_8888 },
{ OHOS::Media::PixelFormat::NV21, GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCRCB_420_SP },
{ OHOS::Media::PixelFormat::NV12, GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_420_SP },
};
float GetPixelFormatCoefficient(OHOS::Media::PixelFormat format)
{
float coefficient;
switch (format) {
case OHOS::Media::PixelFormat::RGBA_8888:
case OHOS::Media::PixelFormat::BGRA_8888:
coefficient = 4.0; // 4.0 size coefficient
break;
case OHOS::Media::PixelFormat::NV12:
case OHOS::Media::PixelFormat::NV21:
coefficient = 1.0; // 1.0 size coefficient
break;
default:
coefficient = 3.0; // 3.0 size coefficient
break;
}
return coefficient;
}
}
sptr<SurfaceBuffer> VpeUtils::GetSurfaceBufferFromPixelMap(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
if (pixelmap->GetAllocatorType() == AllocatorType::DMA_ALLOC) {
return reinterpret_cast<SurfaceBuffer*>(pixelmap->GetFd());
}
auto buffer = SurfaceBuffer::Create();
CHECK_AND_RETURN_RET_LOG(buffer != nullptr, nullptr, "get surface buffer failed!");
CHECK_AND_RETURN_RET_LOG(ConvertPixelmapToSurfaceBuffer(pixelmap, buffer), nullptr,
"get surface buffer failed!");
return buffer;
}
bool VpeUtils::ConvertPixelmapToSurfaceBuffer(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap, sptr<SurfaceBuffer> bufferImpl)
{
auto it = FORMAT_MAP.find(pixelmap->GetPixelFormat());
if (it == FORMAT_MAP.end()) [[unlikely]] {
VPE_LOGE("unsupported format: %{public}d", pixelmap->GetPixelFormat());
return false;
}
BufferRequestConfig bfConfig = {};
bfConfig.width = pixelmap->GetWidth();
bfConfig.height = pixelmap->GetHeight();
bfConfig.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE;
bfConfig.strideAlignment = bfConfig.width;
bfConfig.format = it->second;
bfConfig.timeout = 0;
bfConfig.colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB;
bfConfig.transform = GraphicTransformType::GRAPHIC_ROTATE_NONE;
CHECK_AND_RETURN_RET_LOG((bufferImpl->Alloc(bfConfig) == GSERROR_OK), false, "invalid OH_PixelmapNative image");
bool ret;
switch (pixelmap->GetPixelFormat()) {
case OHOS::Media::PixelFormat::RGBA_8888:
case OHOS::Media::PixelFormat::BGRA_8888:
ret = CopyRGBAPixelmapToSurfaceBuffer(pixelmap, bufferImpl);
break;
case OHOS::Media::PixelFormat::NV12:
case OHOS::Media::PixelFormat::NV21:
ret = CopyNV12PixelmapToSurfaceBuffer(pixelmap, bufferImpl);
break;
default:
ret = false;
break;
}
return ret;
}
bool VpeUtils::ConvertSurfaceBufferToPixelmap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
bool ret;
switch (pixelmap->GetPixelFormat()) {
case OHOS::Media::PixelFormat::RGBA_8888:
case OHOS::Media::PixelFormat::BGRA_8888:
ret = CopyRGBASurfaceBufferToPixelmap(buffer, pixelmap);
break;
case OHOS::Media::PixelFormat::NV12:
case OHOS::Media::PixelFormat::NV21:
ret = CopyNV12SurfaceBufferToPixelmap(buffer, pixelmap);
break;
default:
ret = false;
break;
}
return ret;
}
bool VpeUtils::CopyRGBASurfaceBufferToPixelmap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
int32_t pixelmapStride = pixelmap->GetRowStride() > 1.5 * buffer->GetStride() ? // 1.5
pixelmap->GetRowStride() / 2 : pixelmap->GetRowStride(); // 2
int rowSize = std::min(buffer->GetStride(), pixelmapStride);
for (int i = 0; i < buffer->GetHeight(); ++i) {
if (memcpy_s(static_cast<uint8_t*>(pixelmap->GetWritablePixels()) + i * pixelmapStride, rowSize,
static_cast<uint8_t*>(buffer->GetVirAddr()) + i * buffer->GetStride(), rowSize) != EOK) {
VPE_LOGE("Failed to copy image buffer!");
return false;
}
}
return true;
}
bool VpeUtils::CopyRGBAPixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap,
sptr<SurfaceBuffer>& buffer)
{
int32_t rowBufferSize = pixelmap->GetWidth() * GetPixelFormatCoefficient(pixelmap->GetPixelFormat());
int32_t pixelmapStride = pixelmap->GetRowStride() > 1.5 * buffer->GetStride() ? // 1.5
pixelmap->GetRowStride() / 2 : pixelmap->GetRowStride(); // 2
for (int i = 0; i < pixelmap->GetHeight(); ++i) {
if (memcpy_s(static_cast<uint8_t*>(buffer->GetVirAddr()) + i * buffer->GetStride(),
rowBufferSize, pixelmap->GetPixels() + i * pixelmapStride, rowBufferSize) != EOK) {
VPE_LOGE("copy data failed!");
return false;
}
}
return true;
}
bool VpeUtils::CopyNV12SurfaceBufferToPixelmap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
YUVDataInfo yuvInfo;
pixelmap->GetImageYUVInfo(yuvInfo);
int32_t pixelmapStride = pixelmap->GetRowStride() > 1.5 * buffer->GetStride() ? // 1.5
pixelmap->GetRowStride() / 2 : pixelmap->GetRowStride(); // 2
int32_t pixelmapUvStride = static_cast<int32_t>((yuvInfo.uvStride > 0) ?
static_cast<int32_t>(yuvInfo.uvStride) : pixelmapStride);
int32_t pixelmapUvOffset = static_cast<int32_t>((yuvInfo.uvOffset > 0) ?
static_cast<int32_t>(yuvInfo.uvOffset) : pixelmapStride * pixelmap->GetHeight());
int32_t pixelmapUvHeight = static_cast<int32_t>((yuvInfo.uvHeight > 0) ?
static_cast<int32_t>(yuvInfo.uvHeight) : (pixelmap->GetHeight() + 1) / 2); // 2
int32_t bufferUvStride = buffer->GetStride();
int32_t bufferUvOffset = buffer->GetStride() * buffer->GetHeight();
int32_t bufferUvHeight = (buffer->GetHeight() + 1) / 2;
void *planesInfoPtr = nullptr;
buffer->GetPlanesInfo(&planesInfoPtr);
auto planesInfo = static_cast<OH_NativeBuffer_Planes*>(planesInfoPtr);
if (planesInfo != nullptr) {
int idx = (pixelmap->GetPixelFormat() == OHOS::Media::PixelFormat::NV12) ? 1 : 2; // 1 NV12, 2 NV21
bufferUvStride = static_cast<int32_t>(planesInfo->planes[idx].columnStride);
bufferUvOffset = static_cast<int32_t>(planesInfo->planes[idx].offset);
if (bufferUvStride != 0) {
bufferUvHeight = static_cast<int32_t>(planesInfo->planes[idx].offset) / bufferUvStride;
}
}
int32_t yStride = std::min(pixelmapStride, buffer->GetStride());
for (int i = 0; i < pixelmap->GetHeight(); ++i) {
if (memcpy_s(static_cast<uint8_t*>(pixelmap->GetWritablePixels()) + i * pixelmapStride, yStride,
static_cast<uint8_t*>(buffer->GetVirAddr()) + i * buffer->GetStride(), yStride) != EOK) {
VPE_LOGE("Failed to copy NV12 buffer to pixelmap!");
return false;
}
}
int32_t uvStride = std::min(pixelmapUvStride, bufferUvStride);
int32_t uvHeight = std::min(pixelmapUvHeight, bufferUvHeight);
for (int i = 0; i < uvHeight; ++i) {
if (memcpy_s(static_cast<uint8_t*>(pixelmap->GetWritablePixels()) + pixelmapUvOffset + i * pixelmapUvStride,
uvStride, static_cast<uint8_t*>(buffer->GetVirAddr()) + bufferUvOffset + i * bufferUvStride,
uvStride) != EOK) {
VPE_LOGE("Failed to copy NV12 buffer to pixelmap!");
return false;
}
}
return true;
}
bool VpeUtils::CopyNV12PixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap,
sptr<SurfaceBuffer>& buffer)
{
YUVDataInfo yuvInfo;
pixelmap->GetImageYUVInfo(yuvInfo);
int32_t pixelmapStride = pixelmap->GetRowStride() > 1.5 * buffer->GetStride() ? // 1.5
pixelmap->GetRowStride() / 2 : pixelmap->GetRowStride(); // 2
int32_t pixelmapUvStride = static_cast<int32_t>((yuvInfo.uvStride > 0) ?
static_cast<int32_t>(yuvInfo.uvStride) : pixelmapStride);
int32_t pixelmapUvOffset = static_cast<int32_t>((yuvInfo.uvOffset > 0) ?
static_cast<int32_t>(yuvInfo.uvOffset) : pixelmapStride * pixelmap->GetHeight());
int32_t pixelmapUvHeight = static_cast<int32_t>((yuvInfo.uvHeight > 0) ?
static_cast<int32_t>(yuvInfo.uvHeight) : (pixelmap->GetHeight() + 1) / 2);
int32_t bufferUvStride = buffer->GetStride();
int32_t bufferUvOffset = buffer->GetStride() * buffer->GetHeight();
int32_t bufferUvHeight = (buffer->GetHeight() + 1) / 2; // 2
void *planesInfoPtr = nullptr;
buffer->GetPlanesInfo(&planesInfoPtr);
auto planesInfo = static_cast<OH_NativeBuffer_Planes*>(planesInfoPtr);
if (planesInfo != nullptr) {
int idx = (pixelmap->GetPixelFormat() == OHOS::Media::PixelFormat::NV12) ? 1 : 2; // 1 NV12, 2 NV21
bufferUvStride = static_cast<int32_t>(planesInfo->planes[idx].columnStride);
bufferUvOffset = static_cast<int32_t>(planesInfo->planes[idx].offset);
if (bufferUvStride != 0) {
bufferUvHeight = static_cast<int32_t>(planesInfo->planes[idx].offset) / bufferUvStride;
}
}
int32_t yStride = std::min(pixelmapStride, buffer->GetStride());
for (int i = 0; i < pixelmap->GetHeight(); ++i) {
if (memcpy_s(static_cast<uint8_t*>(buffer->GetVirAddr()) + i * buffer->GetStride(), yStride,
static_cast<uint8_t*>(pixelmap->GetWritablePixels()) + i * pixelmapStride, yStride) != EOK) {
VPE_LOGE("Failed to copy NV12 buffer to pixelmap!");
return false;
}
}
int32_t uvStride = std::min(pixelmapUvStride, bufferUvStride);
int32_t uvHeight = std::min(pixelmapUvHeight, bufferUvHeight);
for (int i = 0; i < uvHeight; ++i) {
if (memcpy_s(static_cast<uint8_t*>(buffer->GetVirAddr()) + bufferUvOffset + i * bufferUvStride, uvStride,
static_cast<uint8_t*>(pixelmap->GetWritablePixels()) + pixelmapUvOffset + i * pixelmapUvStride,
uvStride) != EOK) {
VPE_LOGE("Failed to copy NV12 buffer to pixelmap!");
return false;
}
}
return true;
}
bool VpeUtils::SetSurfaceBufferToPixelMap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
if (pixelmap->GetAllocatorType() == AllocatorType::DMA_ALLOC) {
return true;
}
return ConvertSurfaceBufferToPixelmap(buffer, pixelmap);
}
@@ -0,0 +1,54 @@
/*
* 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 CONTRAST_ENHANCER_BASE_H
#define CONTRAST_ENHANCER_BASE_H
#include "algorithm_errors.h"
#include "refbase.h"
#include "surface_buffer.h"
#include "contrast_enhancer_image.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class ContrastEnhancerBase {
public:
ContrastEnhancerBase() = default;
virtual ~ContrastEnhancerBase() = default;
ContrastEnhancerBase(const ContrastEnhancerBase&) = delete;
ContrastEnhancerBase& operator=(const ContrastEnhancerBase&) = delete;
ContrastEnhancerBase(ContrastEnhancerBase&&) = delete;
ContrastEnhancerBase& operator=(ContrastEnhancerBase&&) = delete;
virtual VPEAlgoErrCode Init() = 0;
virtual VPEAlgoErrCode Deinit() = 0;
virtual VPEAlgoErrCode SetParameter(const ContrastEnhancerParameters& parameter, int type, bool flag) = 0;
virtual VPEAlgoErrCode GetRegionHist(const sptr<SurfaceBuffer>& input) = 0;
virtual bool UpdateMetadataBasedOnLcd(OHOS::Rect rect, int lcdWidth, int lcdHeight,
sptr<SurfaceBuffer> surfaceBuffer) = 0;
virtual bool UpdateMetadataBasedOnDetail(OHOS::Rect displayArea, OHOS::Rect curPixelmapArea,
OHOS::Rect completePixelmapArea, sptr<SurfaceBuffer> surfaceBuffer, float fullRatio) = 0;
};
using ContrastEnhancerCreator = std::function<std::shared_ptr<ContrastEnhancerBase>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif /* CONTRAST_ENHANCER_BASE_H */
@@ -0,0 +1,38 @@
/*
* 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 FRAMEWORK_ALGORITHM_CONTRAST_ENHANCER_CAPABILITY_H
#define FRAMEWORK_ALGORITHM_CONTRAST_ENHANCER_CAPABILITY_H
#include <functional>
#include <vector>
#include "algorithm_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
struct ContrastEnhancerCapability {
std::vector<uint32_t> levels;
uint32_t rank;
int32_t version;
};
using ContrastEnhancerCapabilitiesBuilder = std::function<ContrastEnhancerCapability()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_CONTRAST_ENHANCER_CAPABILITY_H
@@ -0,0 +1,57 @@
/*
* 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 CONTRAST_ENHANCER_IMAGE_FWK_H
#define CONTRAST_ENHANCER_IMAGE_FWK_H
#include <unordered_set>
#include "contrast_enhancer_image.h"
#include "contrast_enhancer_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class ContrastEnhancerImageFwk : public ContrastEnhancerImage {
public:
explicit ContrastEnhancerImageFwk();
~ContrastEnhancerImageFwk() override;
ContrastEnhancerImageFwk(const ContrastEnhancerImageFwk&) = delete;
ContrastEnhancerImageFwk& operator=(const ContrastEnhancerImageFwk&) = delete;
ContrastEnhancerImageFwk(ContrastEnhancerImageFwk&&) = delete;
ContrastEnhancerImageFwk& operator=(ContrastEnhancerImageFwk&&) = delete;
VPEAlgoErrCode SetParameter(const ContrastEnhancerParameters& parameter) override;
VPEAlgoErrCode GetParameter(ContrastEnhancerParameters& parameter) const override;
VPEAlgoErrCode GetRegionHist(const sptr<SurfaceBuffer>& input) override;
VPEAlgoErrCode UpdateMetadataBasedOnLcd(OHOS::Rect displayArea, int lcdWidth, int lcdHeight,
sptr<SurfaceBuffer> surfaceBuffer) override;
VPEAlgoErrCode UpdateMetadataBasedOnDetail(OHOS::Rect displayArea, OHOS::Rect curPixelmapArea,
OHOS::Rect completePixelmapArea, sptr<SurfaceBuffer> surfaceBuffer, float fullRatio) override;
private:
std::shared_ptr<ContrastEnhancerBase> GetAlgorithm(int feature);
std::shared_ptr<ContrastEnhancerBase> CreateAlgorithm(int feature);
bool IsValidProcessedObject(const sptr<SurfaceBuffer>& buffer);
ContrastEnhancerParameters parameter_{};
mutable std::mutex lock_{};
std::mutex getAlgoLock_{};
std::unordered_map<int, std::shared_ptr<ContrastEnhancerBase>> algorithms_{};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // CONTRAST_ENHANCER_IMAGE_IMPL_H
@@ -0,0 +1,341 @@
/*
* 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 "detail_enhancer_image_fwk.h"
#include <dlfcn.h>
#include "detail_enhancer_common.h"
#include "extension_manager.h"
#include "native_buffer.h"
#include "surface_buffer.h"
#include "video_processing_client.h"
#include "vpe_log.h"
#include "vpe_trace.h"
namespace {
enum RectLevelItem {
RECT_LEVEL_INVALID = -1,
RECT_MIN_WIDTH,
RECT_MAX_WIDTH,
RECT_MIN_HEIGHT,
RECT_MAX_HEIGHT,
RECT_LEVEL_NUM,
};
constexpr float EPSILON = 1e-6; // extremely small value
const int MAX_URL_LENGTH = 100;
const int SUPPORTED_MIN_WIDTH = 32;
const int SUPPORTED_MIN_HEIGHT = 32;
const int SUPPORTED_MAX_WIDTH = 8192;
const int SUPPORTED_MAX_HEIGHT = 8192;
const int TIMEOUT_THRESHOLD = 10; // 10 millisecond
const std::unordered_set<int32_t> SUPPORTED_FORMATS = {
OHOS::GRAPHIC_PIXEL_FMT_BGRA_8888, // BGRA
OHOS::GRAPHIC_PIXEL_FMT_RGBA_8888, // RGBA
OHOS::GRAPHIC_PIXEL_FMT_YCBCR_420_SP, // NV12
OHOS::GRAPHIC_PIXEL_FMT_YCRCB_420_SP, // NV21
OHOS::GRAPHIC_PIXEL_FMT_YCBCR_420_P, // YU12
OHOS::GRAPHIC_PIXEL_FMT_YCRCB_420_P, // YV12
OHOS::GRAPHIC_PIXEL_FMT_RGBA_1010102, // RGBA_1010102
};
const std::vector<std::array<int, RECT_LEVEL_NUM>> SUPER_LEVEL_TARGET_RECT = {
{1, 1104, 1, 848},
{1, 1104, 1, 1488},
{1, 1488, 1, 1104},
{1, 1872, 1, 1360},
};
inline bool IsValidSurfaceBuffer(const OHOS::sptr<OHOS::SurfaceBuffer>& buffer)
{
CHECK_AND_RETURN_RET_LOG(buffer != nullptr, false, "buffer is nullptr!!");
return SUPPORTED_FORMATS.find(buffer->GetFormat()) != SUPPORTED_FORMATS.end() &&
buffer->GetWidth() > SUPPORTED_MIN_WIDTH && buffer->GetHeight() > SUPPORTED_MIN_HEIGHT &&
buffer->GetWidth() <= SUPPORTED_MAX_WIDTH && buffer->GetHeight() <= SUPPORTED_MAX_HEIGHT;
}
std::atomic<int32_t> g_instanceId = -1;
std::timed_mutex g_externLock{};
}
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
DetailEnhancerImageFwk::DetailEnhancerImageFwk(int type)
{
type_ = (type >= IMAGE && type <= VIDEO) ? type : IMAGE;
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
DetailEnhancerImageFwk::~DetailEnhancerImageFwk()
{
algorithms_.clear();
Extension::ExtensionManager::GetInstance().DecreaseInstance();
}
std::shared_ptr<DetailEnhancerImage> DetailEnhancerImage::Create(int type)
{
CHECK_AND_RETURN_RET_LOG(type <= VIDEO && type >= IMAGE, nullptr, "type is invalid!!");
std::shared_ptr<DetailEnhancerImage> impl = std::make_shared<DetailEnhancerImageFwk>(type);
CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr, "failed to init DetailEnhancerImage");
return impl;
}
std::shared_ptr<DetailEnhancerBase> DetailEnhancerImageFwk::GetAlgorithm(int level)
{
if (level < DETAIL_ENH_LEVEL_NONE || level > DETAIL_ENH_LEVEL_VIDEO) {
VPE_LOGE("Invalid level:%{public}d", level);
return nullptr;
}
std::lock_guard<std::mutex> lock(lock_);
auto createdImpl = algorithms_.find(level);
if (createdImpl != algorithms_.end()) [[likely]] {
return createdImpl->second;
}
algorithms_[level] = CreateAlgorithm(level);
return algorithms_[level];
}
std::shared_ptr<DetailEnhancerBase> DetailEnhancerImageFwk::CreateAlgorithm(int level)
{
auto& manager = Extension::ExtensionManager::GetInstance();
VPE_SYNC_TRACE;
std::shared_ptr<DetailEnhancerBase> algoImpl = manager.CreateDetailEnhancer(level);
if (algoImpl == nullptr) {
VPE_LOGE("Extension create failed, get a empty impl, level: %{public}d", level);
return nullptr;
}
if (algoImpl->Init() != VPE_ALGO_ERR_OK) {
VPE_LOGE("Init failed, extension level: %{public}d", level);
return nullptr;
}
return algoImpl;
}
VPEAlgoErrCode DetailEnhancerImageFwk::SetParameter(const DetailEnhancerParameters& parameter)
{
CHECK_AND_RETURN_RET_LOG(parameter.level >= DETAIL_ENH_LEVEL_NONE && parameter.level <= DETAIL_ENH_LEVEL_HIGH &&
parameter.uri.length() < MAX_URL_LENGTH, VPE_ALGO_ERR_INVALID_VAL, "Invalid parameter");
std::lock_guard<std::mutex> lock(lock_);
parameter_ = parameter;
parameterUpdated = true;
VPE_LOGI("DetailEnhancerImageFwk SetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode DetailEnhancerImageFwk::GetParameter(DetailEnhancerParameters& parameter) const
{
std::lock_guard<std::mutex> lock(lock_);
parameter = parameter_;
VPE_LOGI("DetailEnhancerImageFwk SetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
bool DetailEnhancerImageFwk::IsValidProcessedObject(const sptr<SurfaceBuffer>& input,
const sptr<SurfaceBuffer>& output)
{
CHECK_AND_RETURN_RET_LOG((input != nullptr) && (output != nullptr),
false, "Input or output is nullptr");
CHECK_AND_RETURN_RET_LOG(input->GetFormat() == output->GetFormat(), false,
"The input format and output format need to be consistent");
CHECK_AND_RETURN_RET_LOG(IsValidSurfaceBuffer(input) && IsValidSurfaceBuffer(output), false, "Invalid buffer");
return true;
}
int DetailEnhancerImageFwk::EvaluateTargetLevel(const sptr<SurfaceBuffer>& input,
const sptr<SurfaceBuffer>& output, float widthRatio, float heightRatio) const
{
CHECK_AND_RETURN_RET_LOG((input != nullptr) && (output != nullptr), false, "Input or output is nullptr");
if (parameter_.level == DETAIL_ENH_LEVEL_HIGH) {
int inputW = input->GetWidth();
int inputH = input->GetHeight();
if (widthRatio < 1.0 && heightRatio < 1.0 && // 1.0 means zoom out
// 0.5 means rounding, 2 means two pixels
std::abs(static_cast<int>(widthRatio * inputW + 0.5) - static_cast<int>(heightRatio * inputW + 0.5)) <= 2 &&
// 0.5 means rounding, 2 means two pixels
std::abs(static_cast<int>(widthRatio * inputH + 0.5) - static_cast<int>(heightRatio * inputH + 0.5)) <= 2) {
VPE_LOGI("Prioritize using extream vision algo when scaling down scenes");
return DETAIL_ENH_LEVEL_HIGH;
}
return DETAIL_ENH_LEVEL_HIGH_AISR;
}
return parameter_.level;
}
VPEAlgoErrCode DetailEnhancerImageFwk::ProcessVideo(const sptr<SurfaceBuffer>& input,
const sptr<SurfaceBuffer>& output, bool flag)
{
auto algoImpl = GetAlgorithm(DETAIL_ENH_LEVEL_VIDEO);
if (algoImpl == nullptr) {
VPE_LOGE("Get Algorithm impl for video failed!");
return VPE_ALGO_ERR_UNKNOWN;
}
if (parameterUpdated.load() && (algoImpl->SetParameter(parameter_, type_, flag) != VPE_ALGO_ERR_OK)) {
VPE_LOGE("set parameter failed!");
return VPE_ALGO_ERR_UNKNOWN;
} else {
parameterUpdated = false;
}
if (algoImpl->Process(input, output) != VPE_ALGO_ERR_OK) {
VPE_LOGE("process video failed");
return VPE_ALGO_ERR_UNKNOWN;
}
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode DetailEnhancerImageFwk::Process(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output,
bool flag)
{
CHECK_AND_RETURN_RET_LOG(IsValidProcessedObject(input, output), VPE_ALGO_ERR_INVALID_VAL,
"Invalid processd object");
VPE_SYNC_TRACE;
if (parameter_.forceEve) {
auto algoImpl = GetAlgorithm(DETAIL_ENH_LEVEL_HIGH);
CHECK_AND_RETURN_RET_LOG(algoImpl != nullptr && algoImpl->SetParameter(parameter_, type_, flag) ==
VPE_ALGO_ERR_OK, VPE_ALGO_ERR_UNKNOWN, "set parameter failed!");
return algoImpl->Process(input, output);
}
if (type_ == VIDEO) {
return ProcessVideo(input, output, flag);
}
float widthRatio = static_cast<float>(output->GetWidth()) / static_cast<float>(input->GetWidth());
float heightRatio = static_cast<float>(output->GetHeight()) / static_cast<float>(input->GetHeight());
int targetLevel = EvaluateTargetLevel(input, output, widthRatio, heightRatio);
if (targetLevel < DETAIL_ENH_LEVEL_HIGH_AISR &&
std::fabs(widthRatio - 1.0f) < EPSILON && std::fabs(heightRatio - 1.0f) < EPSILON) {
VPE_LOGI("The current scaling ratio is 1.0, and the algorithm is not AISR, so copy it directly.");
return (memcpy_s(output->GetVirAddr(), output->GetSize(), input->GetVirAddr(), input->GetSize()) == EOK) ?
VPE_ALGO_ERR_OK : VPE_ALGO_ERR_UNKNOWN;
}
bool processSuccessfully = false;
for (int level = targetLevel; level >= DETAIL_ENH_LEVEL_NONE; level--) {
auto algoImpl = GetAlgorithm(level);
if (algoImpl == nullptr) {
VPE_LOGE("Get Algorithm impl for %{public}d failed!", level);
continue;
}
parameter_.level = static_cast<DetailEnhancerLevel>((level == DETAIL_ENH_LEVEL_HIGH_AISR) ?
DETAIL_ENH_LEVEL_HIGH : level); // map level
if (algoImpl->SetParameter(parameter_, type_, flag) != VPE_ALGO_ERR_OK) {
VPE_LOGE("set parameter failed!");
return VPE_ALGO_ERR_UNKNOWN;
}
if (algoImpl->Process(input, output) == VPE_ALGO_ERR_OK) {
processSuccessfully = true;
break;
} else if (level == DETAIL_ENH_LEVEL_HIGH_AISR) {
VPE_LOGD("AISR processed failed, try to process by EVE");
} else if (level > DETAIL_ENH_LEVEL_NONE) {
VPE_LOGW("Failed to process with level %{public}d", level);
} else {
VPE_LOGE("Failed to process with detail enhancer");
return VPE_ALGO_ERR_UNKNOWN;
}
}
return processSuccessfully ? VPE_ALGO_ERR_OK : VPE_ALGO_ERR_INVALID_VAL;
}
int32_t DetailEnhancerCreate(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(g_externLock.try_lock_for(std::chrono::milliseconds(TIMEOUT_THRESHOLD)),
VPE_ALGO_ERR_INVALID_VAL, "get lock timeout");
if (instance == nullptr) {
VPE_LOGE("invalid instance");
g_externLock.unlock();
return VPE_ALGO_ERR_INVALID_VAL;
}
if (g_instanceId != -1) {
// if there is an instance, return it
*instance = g_instanceId;
g_externLock.unlock();
return VPE_ALGO_ERR_OK;
}
auto detailEnh = DetailEnhancerImage::Create();
if (detailEnh == nullptr) {
VPE_LOGE("cannot create instance");
g_externLock.unlock();
return VPE_ALGO_ERR_INVALID_VAL;
}
Extension::ExtensionManager::InstanceVariableType instanceVar { detailEnh };
int32_t newId = Extension::ExtensionManager::GetInstance().NewInstanceId(instanceVar);
if (newId == -1) {
VPE_LOGE("cannot create more instance");
g_externLock.unlock();
return VPE_ALGO_ERR_NO_MEMORY;
}
*instance = newId;
g_instanceId = newId;
g_externLock.unlock();
return VPE_ALGO_ERR_OK;
}
sptr<SurfaceBuffer> CreateSurfaceBufFromNativeWindow(OHNativeWindowBuffer* image)
{
OH_NativeBuffer* imageNativeBuffer = nullptr;
CHECK_AND_RETURN_RET_LOG(OH_NativeBuffer_FromNativeWindowBuffer(image, &imageNativeBuffer) == GSERROR_OK,
nullptr, "invalid input or output image");
sptr<SurfaceBuffer> imageSurfaceBuffer(SurfaceBuffer::NativeBufferToSurfaceBuffer(imageNativeBuffer));
return imageSurfaceBuffer;
}
int32_t DetailEnhancerProcessImage(int32_t instance, OHNativeWindowBuffer* inputImage,
OHNativeWindowBuffer* outputImage, int32_t level)
{
CHECK_AND_RETURN_RET_LOG(g_externLock.try_lock_for(std::chrono::milliseconds(TIMEOUT_THRESHOLD)),
VPE_ALGO_ERR_INVALID_VAL, "get lock timeout");
if (inputImage == nullptr || outputImage == nullptr) {
VPE_LOGE("invalid parameters");
g_externLock.unlock();
return VPE_ALGO_ERR_INVALID_VAL;
}
auto someInstance = Extension::ExtensionManager::GetInstance().GetInstance(instance);
if (someInstance == std::nullopt) {
VPE_LOGE("invalid instance");
g_externLock.unlock();
return VPE_ALGO_ERR_INVALID_VAL;
}
VPEAlgoErrCode ret = VPE_ALGO_ERR_INVALID_VAL;
auto visitFunc = [inputImage, outputImage, &ret, &level](auto&& var) {
using VarType = std::decay_t<decltype(var)>;
if constexpr (std::is_same_v<VarType, std::shared_ptr<DetailEnhancerImage>>) {
sptr<SurfaceBuffer> inputImageSurfaceBuffer = CreateSurfaceBufFromNativeWindow(inputImage);
sptr<SurfaceBuffer> outputImageSurfaceBuffer = CreateSurfaceBufFromNativeWindow(outputImage);
DetailEnhancerParameters param {
.uri = "",
.level = static_cast<DetailEnhancerLevel>(level),
};
var->SetParameter(param);
ret = var->Process(inputImageSurfaceBuffer, outputImageSurfaceBuffer);
} else {
VPE_LOGE("instance may be miss used");
}
};
std::visit(visitFunc, *someInstance);
g_externLock.unlock();
return ret;
}
int32_t DetailEnhancerDestroy(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "instance is null");
int ret = Extension::ExtensionManager::GetInstance().RemoveInstanceReference(*instance);
if (ret == VPE_ALGO_ERR_OK) {
g_instanceId = -1;
}
return ret;
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,60 @@
/*
* 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 DETAIL_ENHANCER_BASE_H
#define DETAIL_ENHANCER_BASE_H
#include "algorithm_errors.h"
#include "detail_enhancer_common.h"
#include "refbase.h"
#include "surface_buffer.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
enum DetailEnhancerHighLevel {
// The high level adopts downshift logic and uses AISR by default. If AISR processing fails, downshift to EVE.
// Do not modify the high-level logical sequence
DETAIL_ENH_LEVEL_HIGH_EVE = DETAIL_ENH_LEVEL_HIGH,
DETAIL_ENH_LEVEL_HIGH_AISR = DETAIL_ENH_LEVEL_HIGH + 1,
DETAIL_ENH_LEVEL_VIDEO = DETAIL_ENH_LEVEL_HIGH + 2,
};
class DetailEnhancerBase {
public:
enum DetailEnhancerType {
DETAIL_ENH_TYPE_IMAGE = 0,
DETAIL_ENH_TYPE_VIDEO,
};
DetailEnhancerBase() = default;
virtual ~DetailEnhancerBase() = default;
DetailEnhancerBase(const DetailEnhancerBase&) = delete;
DetailEnhancerBase& operator=(const DetailEnhancerBase&) = delete;
DetailEnhancerBase(DetailEnhancerBase&&) = delete;
DetailEnhancerBase& operator=(DetailEnhancerBase&&) = delete;
virtual VPEAlgoErrCode Init() = 0;
virtual VPEAlgoErrCode Deinit() = 0;
virtual VPEAlgoErrCode SetParameter(const DetailEnhancerParameters& parameter, int type, bool flag) = 0;
virtual VPEAlgoErrCode Process(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output) = 0;
};
using DetailEnhancerCreator = std::function<std::shared_ptr<DetailEnhancerBase>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif /* DETAIL_ENHANCER_BASE_H */
@@ -0,0 +1,38 @@
/*
* 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 FRAMEWORK_ALGORITHM_DETAIL_ENHANCER_CAPABILITY_H
#define FRAMEWORK_ALGORITHM_DETAIL_ENHANCER_CAPABILITY_H
#include <functional>
#include <vector>
#include "algorithm_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
struct DetailEnhancerCapability {
std::vector<uint32_t> levels;
uint32_t rank;
int32_t version;
};
using DetailEnhancerCapabilitiesBuilder = std::function<DetailEnhancerCapability()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_DETAIL_ENHANCER_CAPABILITY_H
@@ -0,0 +1,58 @@
/*
* 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 DETAIL_ENHANCER_IMAGE_FWK_H
#define DETAIL_ENHANCER_IMAGE_FWK_H
#include <unordered_set>
#include "detail_enhancer_image.h"
#include "detail_enhancer_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class DetailEnhancerImageFwk : public DetailEnhancerImage {
public:
explicit DetailEnhancerImageFwk(int type);
~DetailEnhancerImageFwk() override;
DetailEnhancerImageFwk(const DetailEnhancerImageFwk&) = delete;
DetailEnhancerImageFwk& operator=(const DetailEnhancerImageFwk&) = delete;
DetailEnhancerImageFwk(DetailEnhancerImageFwk&&) = delete;
DetailEnhancerImageFwk& operator=(DetailEnhancerImageFwk&&) = delete;
VPEAlgoErrCode SetParameter(const DetailEnhancerParameters& parameter) override;
VPEAlgoErrCode GetParameter(DetailEnhancerParameters& parameter) const override;
VPEAlgoErrCode Process(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output, bool flag) override;
private:
std::shared_ptr<DetailEnhancerBase> GetAlgorithm(int feature);
std::shared_ptr<DetailEnhancerBase> CreateAlgorithm(int feature);
bool IsValidProcessedObject(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output);
int EvaluateTargetLevel(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output,
float widthRatio, float heightRatio) const;
VPEAlgoErrCode ProcessVideo(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output, bool flag);
DetailEnhancerParameters parameter_{};
mutable std::mutex lock_{};
std::unordered_map<int, std::shared_ptr<DetailEnhancerBase>> algorithms_{};
int type_;
std::atomic<bool> parameterUpdated{};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // DETAIL_ENHANCER_IMAGE_IMPL_H
@@ -0,0 +1,206 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "detail_enhancer_video_fwk.h"
#include <functional>
#include "vpe_log.h"
#include "vpe_trace.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
using namespace std::chrono_literals;
namespace {
constexpr int MAX_TARGET_WIDTH = 2000;
constexpr int MAX_TARGET_HEIGHT = 2000;
} // namespace
std::shared_ptr<VpeVideoImpl> DetailEnhancerVideoFwk::Create()
{
auto obj = std::make_shared<DetailEnhancerVideoFwk>(VIDEO_TYPE_DETAIL_ENHANCER);
CHECK_AND_RETURN_RET_LOG(obj != nullptr, nullptr, "Failed to create detail enhancer!");
CHECK_AND_RETURN_RET_LOG(obj->Initialize() == VPE_ALGO_ERR_OK, nullptr, "Failed to initialize detail enhancer!");
return obj;
}
VPEAlgoErrCode DetailEnhancerVideoFwk::SetParameter(const Format& parameter)
{
std::function<ParamError(const Format&)> setters[] = {
[this] (const Format& parameter) { return SetLevel(parameter); },
[this] (const Format& parameter) { return SetTargetSize(parameter); },
[this] (const Format& parameter) { return SetAutoDownshift(parameter); },
};
CHECK_AND_RETURN_RET_LOG(IsInitialized(), VPE_ALGO_ERR_INVALID_OPERATION, "NOT initialized!");
std::lock_guard<std::mutex> lock(lock_);
int setCount = 0;
for (auto& setter : setters) {
int err = setter(parameter);
if (err == PARAM_ERR_INVALID) {
return VPE_ALGO_ERR_INVALID_VAL;
}
setCount += err;
}
CHECK_AND_RETURN_RET_LOG(setCount > 0, VPE_ALGO_ERR_INVALID_VAL, "Invalid input: NO valid parameters!");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode DetailEnhancerVideoFwk::GetParameter([[maybe_unused]] Format& parameter)
{
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode DetailEnhancerVideoFwk::OnInitialize()
{
detailEnh_ = DetailEnhancerImage::Create(VIDEO);
CHECK_AND_RETURN_RET_LOG(detailEnh_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "Failed to create DetailEnhancer!");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode DetailEnhancerVideoFwk::OnDeinitialize()
{
detailEnh_ = nullptr;
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode DetailEnhancerVideoFwk::Process(const sptr<SurfaceBuffer>& sourceImage,
sptr<SurfaceBuffer>& destinationImage)
{
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr, VPE_ALGO_ERR_INVALID_VAL,
"Invalid input: source or destination image is null!");
CHECK_AND_RETURN_RET_LOG(IsInitialized(), VPE_ALGO_ERR_INVALID_OPERATION, "NOT initialized!");
auto ret = detailEnh_->Process(sourceImage, destinationImage);
VPE_LOGD("scale %{public}dx%{public}d -> %{public}dx%{public}d ret:%{public}d",
sourceImage->GetWidth(), sourceImage->GetHeight(),
destinationImage->GetWidth(), destinationImage->GetHeight(), ret);
std::lock_guard<std::mutex> lock(lock_);
if (ret == VPE_ALGO_ERR_OK && (lastEffectiveLevel_ != level_ ||
lastEffectiveSize_.width != destinationImage->GetWidth() ||
lastEffectiveSize_.height != destinationImage->GetHeight())) {
VPE_LOGD("level:%{public}d->%{public}d size:%{public}dx%{public}d->%{public}dx%{public}d",
lastEffectiveLevel_, level_, lastEffectiveSize_.width, lastEffectiveSize_.height,
destinationImage->GetWidth(), destinationImage->GetHeight());
Format fmt;
lastEffectiveLevel_ = level_;
fmt.PutIntValue(ParameterKey::DETAIL_ENHANCER_QUALITY_LEVEL, lastEffectiveLevel_);
lastEffectiveSize_.width = destinationImage->GetWidth();
lastEffectiveSize_.height = destinationImage->GetHeight();
fmt.PutBuffer(ParameterKey::DETAIL_ENHANCER_TARGET_SIZE, reinterpret_cast<uint8_t*>(&lastEffectiveSize_),
sizeof(lastEffectiveSize_));
OnOutputFormatChanged(fmt);
}
return ret;
}
bool DetailEnhancerVideoFwk::IsProducerSurfaceValid([[maybe_unused]] const sptr<Surface>& surface)
{
// Check resolution for detail enhancer is valid or not
return true;
}
VPEAlgoErrCode DetailEnhancerVideoFwk::UpdateRequestCfg(const sptr<Surface>& surface, BufferRequestConfig& requestCfg)
{
CHECK_AND_RETURN_RET_LOG(surface != nullptr, VPE_ALGO_ERR_INVALID_VAL, "surface is null!");
// If the target size is set, the target size takes precedence.
std::lock_guard<std::mutex> lock(lock_);
if (size_.width != 0 && size_.height != 0) {
requestCfg.width = size_.width;
requestCfg.height = size_.height;
} else {
// Update buffer request configuration, use default resolution of output surface as the resize destination
// resolution when the request resolution is invalid.
requestCfg.width = surface->GetRequestWidth();
requestCfg.height = surface->GetRequestHeight();
if (requestCfg.width == 0 || requestCfg.height == 0) {
requestCfg.width = surface->GetDefaultWidth();
requestCfg.height = surface->GetDefaultHeight();
}
}
return VPE_ALGO_ERR_OK;
}
void DetailEnhancerVideoFwk::UpdateRequestCfg(const sptr<SurfaceBuffer>& consumerBuffer,
BufferRequestConfig& requestCfg)
{
CHECK_AND_RETURN_LOG(consumerBuffer != nullptr, "surface buffer is null!");
if (size_.width != 0 && size_.height != 0) {
requestCfg.width = size_.width;
requestCfg.height = size_.height;
} else {
requestCfg.width = consumerBuffer->GetWidth();
requestCfg.height = consumerBuffer->GetHeight();
}
requestCfg.format = consumerBuffer->GetFormat();
}
DetailEnhancerVideoFwk::ParamError DetailEnhancerVideoFwk::SetLevel(const Format& parameter)
{
int level;
if (!parameter.GetIntValue(ParameterKey::DETAIL_ENHANCER_QUALITY_LEVEL, level)) {
return PARAM_ERR_NOT_FOUND;
}
CHECK_AND_RETURN_RET_LOG(level >= DETAIL_ENHANCER_LEVEL_NONE && level <= DETAIL_ENHANCER_LEVEL_HIGH,
PARAM_ERR_INVALID, "Invalid input: level=%{public}d(Expected:[%{public}d,%{public}d])!",
level, DETAIL_ENHANCER_LEVEL_NONE, DETAIL_ENHANCER_LEVEL_HIGH);
VPE_LOGI("level:%{public}d->%{public}d", level_, level);
level_ = static_cast<DetailEnhancerQualityLevel>(level);
DetailEnhancerParameters param{};
param.level = static_cast<DetailEnhancerLevel>(level_);
CHECK_AND_RETURN_RET_LOG(detailEnh_->SetParameter(param) == VPE_ALGO_ERR_OK, PARAM_ERR_INVALID,
"Failed to set parameter(level:%{public}d) to detail enhancer!", param.level);
return PARAM_ERR_OK;
}
DetailEnhancerVideoFwk::ParamError DetailEnhancerVideoFwk::SetTargetSize(const Format& parameter)
{
size_t addrSize;
uint8_t* addr = nullptr;
if (!parameter.GetBuffer(ParameterKey::DETAIL_ENHANCER_TARGET_SIZE, &addr, addrSize)) {
return PARAM_ERR_NOT_FOUND;
}
CHECK_AND_RETURN_RET_LOG(addr != nullptr && addrSize == sizeof(VpeBufferSize), PARAM_ERR_INVALID,
"Invalid input: addr is null or addrSize=%{public}zu(Expected:%{public}zu)!",
addrSize, sizeof(VpeBufferSize));
auto size = reinterpret_cast<VpeBufferSize*>(addr);
CHECK_AND_RETURN_RET_LOG(size->width > 0 && size->width <= MAX_TARGET_WIDTH &&
size->height > 0 && size->height <= MAX_TARGET_HEIGHT, PARAM_ERR_INVALID,
"Invalid input: target buffer size width=%{public}d(Expected:(0,%{public}d])"
" height=%{public}d(Expected:(0,%{public}d])!",
size->width, MAX_TARGET_WIDTH, size->height, MAX_TARGET_HEIGHT);
VPE_LOGI("target size:%{public}dx%{public}d->%{public}dx%{public}d",
size_.width, size_.height, size->width, size->height);
size_ = *size;
RefreshBuffers();
return PARAM_ERR_OK;
}
DetailEnhancerVideoFwk::ParamError DetailEnhancerVideoFwk::SetAutoDownshift(const Format& parameter)
{
int autoDownshift;
if (!parameter.GetIntValue(ParameterKey::DETAIL_ENHANCER_AUTO_DOWNSHIFT, autoDownshift)) {
return PARAM_ERR_NOT_FOUND;
}
CHECK_AND_RETURN_RET_LOG(autoDownshift == 0 || autoDownshift == 1, PARAM_ERR_INVALID,
"Invalid input: autoDownshift=%{public}d(Expected: 0 or 1)!", autoDownshift);
VPE_LOGI("auto downshift:%{public}d->%{public}d", isAutoDownshift_, (autoDownshift == 1));
isAutoDownshift_ = (autoDownshift == 1);
return PARAM_ERR_OK;
}
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "detail_enhancer_video_impl.h"
#include "vpe_log.h"
#include "vpe_trace.h"
constexpr int MAX_URL_LENGTH = 100;
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
std::shared_ptr<DetailEnhancerVideo> DetailEnhancerVideo::Create()
{
std::shared_ptr<DetailEnhancerVideoImpl> impl = std::make_shared<DetailEnhancerVideoImpl>();
int32_t ret = impl->Init();
CHECK_AND_RETURN_RET_LOG(ret == static_cast<int32_t>(VPE_ALGO_ERR_OK), nullptr,
"failed to init DetailEnhancerVideoImpl");
return impl;
}
VPEAlgoErrCode DetailEnhancerVideoImpl::RegisterCallback(const std::shared_ptr<VpeVideoCallback>& callback)
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VPE_ALGO_ERR_INIT_FAILED, "Initialization was NOT successful!");
return detailEnhancerVideo_->RegisterCallback(callback);
}
VPEAlgoErrCode DetailEnhancerVideoImpl::SetOutputSurface(const sptr<Surface>& surface)
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VPE_ALGO_ERR_INIT_FAILED, "Initialization was NOT successful!");
return detailEnhancerVideo_->SetOutputSurface(surface);
}
sptr<Surface> DetailEnhancerVideoImpl::GetInputSurface()
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), nullptr, "Initialization was NOT successful!");
return detailEnhancerVideo_->GetInputSurface();
}
VPEAlgoErrCode DetailEnhancerVideoImpl::SetParameter(const DetailEnhancerParameters& parameter, SourceType type)
{
CHECK_AND_RETURN_RET_LOG(parameter.level >= DETAIL_ENH_LEVEL_NONE && parameter.level <= DETAIL_ENH_LEVEL_HIGH &&
parameter.uri.length() < MAX_URL_LENGTH, VPE_ALGO_ERR_INVALID_VAL, "Invalid algo level");
CHECK_AND_RETURN_RET_LOG(type == VIDEO, VPE_ALGO_ERR_INVALID_VAL, "Invalid source type");
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VPE_ALGO_ERR_INIT_FAILED, "Initialization was NOT successful!");
Format fmt;
CHECK_AND_RETURN_RET_LOG(fmt.PutIntValue(ParameterKey::DETAIL_ENHANCER_QUALITY_LEVEL, parameter.level),
VPE_ALGO_ERR_INVALID_VAL, "Failed to put level(%{public}d) to format!", parameter.level);
return detailEnhancerVideo_->SetParameter(fmt);
}
VPEAlgoErrCode DetailEnhancerVideoImpl::Start()
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VPE_ALGO_ERR_INIT_FAILED, "Initialization was NOT successful!");
return detailEnhancerVideo_->Start();
}
VPEAlgoErrCode DetailEnhancerVideoImpl::Stop()
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VPE_ALGO_ERR_INIT_FAILED, "Initialization was NOT successful!");
return detailEnhancerVideo_->Stop();
}
VPEAlgoErrCode DetailEnhancerVideoImpl::RenderOutputBuffer([[maybe_unused]] uint32_t index)
{
return VPE_ALGO_ERR_OK;
}
int32_t DetailEnhancerVideoImpl::Init()
{
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(!isInitialized_.load(), VPE_ALGO_ERR_INVALID_STATE, "Already initialized!");
detailEnhancerVideo_ = DetailEnhancerVideoFwk::Create();
CHECK_AND_RETURN_RET_LOG(detailEnhancerVideo_ != nullptr, VPE_ALGO_ERR_UNKNOWN,
"Failed to create video detail enhancer!");
isInitialized_ = true;
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode DetailEnhancerVideoImpl::NotifyEos()
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VPE_ALGO_ERR_INIT_FAILED, "Initialization was NOT successful!");
return detailEnhancerVideo_->NotifyEos();
}
VPEAlgoErrCode DetailEnhancerVideoImpl::ReleaseOutputBuffer(uint32_t index, bool render)
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VPE_ALGO_ERR_INIT_FAILED, "Initialization was NOT successful!");
return detailEnhancerVideo_->ReleaseOutputBuffer(index, render);
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DETAIL_ENHANCER_VIDEO_FWK_H
#define DETAIL_ENHANCER_VIDEO_FWK_H
#include <memory>
#include <mutex>
#include "algorithm_video_impl.h"
#include "detail_enhancer_image_fwk.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class DetailEnhancerVideoFwk : public VpeVideoImpl {
public:
static std::shared_ptr<VpeVideoImpl> Create();
explicit DetailEnhancerVideoFwk(uint32_t type) : VpeVideoImpl(type) {}
~DetailEnhancerVideoFwk() = default;
DetailEnhancerVideoFwk(const DetailEnhancerVideoFwk&) = delete;
DetailEnhancerVideoFwk& operator=(const DetailEnhancerVideoFwk&) = delete;
DetailEnhancerVideoFwk(DetailEnhancerVideoFwk&&) = delete;
DetailEnhancerVideoFwk& operator=(DetailEnhancerVideoFwk&&) = delete;
VPEAlgoErrCode SetParameter(const Format& parameter) final;
VPEAlgoErrCode GetParameter(Format& parameter) final;
protected:
VPEAlgoErrCode OnInitialize() final;
VPEAlgoErrCode OnDeinitialize() final;
VPEAlgoErrCode Process(const sptr<SurfaceBuffer>& sourceImage, sptr<SurfaceBuffer>& destinationImage) final;
bool IsProducerSurfaceValid(const sptr<Surface>& surface) final;
VPEAlgoErrCode UpdateRequestCfg(const sptr<Surface>& surface, BufferRequestConfig& requestCfg) final;
void UpdateRequestCfg(const sptr<SurfaceBuffer>& consumerBuffer, BufferRequestConfig& requestCfg) final;
private:
enum ParamError {
PARAM_ERR_INVALID = -1,
PARAM_ERR_NOT_FOUND = 0,
PARAM_ERR_OK = 1,
};
ParamError SetLevel(const Format& parameter);
ParamError SetTargetSize(const Format& parameter);
ParamError SetAutoDownshift(const Format& parameter);
std::mutex lock_{};
// Guarded by lock_ begin
DetailEnhancerQualityLevel level_{DETAIL_ENHANCER_LEVEL_LOW};
VpeBufferSize size_{};
DetailEnhancerQualityLevel lastEffectiveLevel_{};
VpeBufferSize lastEffectiveSize_{};
bool isAutoDownshift_{true};
// Guarded by lock_ end
std::shared_ptr<DetailEnhancerImage> detailEnh_{};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // DETAIL_ENHANCER_VIDEO_FWK_H
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DETAIL_ENHANCER_VIDEO_IMPL_H
#define DETAIL_ENHANCER_VIDEO_IMPL_H
#include <atomic>
#include <memory>
#include <mutex>
#include "algorithm_video_common.h"
#include "detail_enhancer_video.h"
#include "detail_enhancer_video_fwk.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class DetailEnhancerVideoImpl : public DetailEnhancerVideo {
public:
DetailEnhancerVideoImpl() = default;
~DetailEnhancerVideoImpl() = default;
int32_t Init();
VPEAlgoErrCode RegisterCallback(const std::shared_ptr<VpeVideoCallback>& callback) override;
VPEAlgoErrCode SetOutputSurface(const sptr<Surface>& surface) override;
sptr<Surface> GetInputSurface() override;
VPEAlgoErrCode SetParameter(const DetailEnhancerParameters& parameter, SourceType type) override;
VPEAlgoErrCode Start() override;
VPEAlgoErrCode Stop() override;
VPEAlgoErrCode RenderOutputBuffer(uint32_t index) override;
VPEAlgoErrCode ReleaseOutputBuffer(uint32_t index, bool render) override;
VPEAlgoErrCode NotifyEos() override;
private:
std::mutex lock_{};
// Guarded by lock_ begin
std::atomic<bool> isInitialized_{false};
std::shared_ptr<VpeVideoImpl> detailEnhancerVideo_{};
// Guarded by lock_ end
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // DETAIL_ENHANCER_VIDEO_IMPL_H
@@ -0,0 +1,700 @@
/*
* 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.
*/
#include "extension_manager.h"
#include <cstdint>
#include <dlfcn.h>
#include <functional>
#include <string>
#include <unordered_map>
#include "static_extension_list.h"
#include "vpe_log.h"
namespace {
using LibFunctionGetRegisters = std::unordered_map<std::string,
OHOS::Media::VideoProcessingEngine::Extension::RegisterExtensionFunc>* (*)();
LibFunctionGetRegisters GetRegisterExtensionFuncs{nullptr};
LibFunctionGetRegisters GetRegisterMetdataGenExtensionFuncs{nullptr};
LibFunctionGetRegisters GetRegisterComposeExtensionFuncs{nullptr};
LibFunctionGetRegisters GetRegisterDecomposeExtensionFuncs{nullptr};
using LibFunctionGetRegisterFunction = OHOS::Media::VideoProcessingEngine::Extension::RegisterExtensionFunc (*)();
LibFunctionGetRegisterFunction GetRegisterVRRExtensionFuncs{nullptr};
void* g_algoHandle{nullptr};
} // namespace
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
ExtensionManager& ExtensionManager::GetInstance()
{
static ExtensionManager instance;
return instance;
}
ExtensionManager::ExtensionManager()
{
(void)Init();
g_algoHandle = dlopen("libvideoprocessingengine_ext.z.so", RTLD_NOW);
}
ExtensionManager::~ExtensionManager()
{
if (g_algoHandle != nullptr) {
dlclose(g_algoHandle);
g_algoHandle = nullptr;
}
}
VPEAlgoErrCode ExtensionManager::Init()
{
if (initialized_) {
return VPE_ALGO_ERR_OK;
}
initialized_ = true;
return VPE_ALGO_ERR_OK;
}
void ExtensionManager::IncreaseInstance()
{
std::lock_guard<std::mutex> lock(instanceCountMtx_);
if (usedInstance_ == 0 && g_algoHandle == nullptr) {
g_algoHandle = dlopen("libvideoprocessingengine_ext.z.so", RTLD_NOW);
}
usedInstance_++;
}
void ExtensionManager::DecreaseInstance()
{
std::lock_guard<std::mutex> lock(instanceCountMtx_);
usedInstance_--;
if ((usedInstance_ == 0) && (g_algoHandle != nullptr)) {
dlclose(g_algoHandle);
g_algoHandle = nullptr;
}
}
bool ExtensionManager::IsColorSpaceConversionSupported(const FrameInfo &inputInfo, const FrameInfo &outputInfo) const
{
if (!initialized_) {
return false;
}
return FindColorSpaceConverterExtension(inputInfo, outputInfo) == nullptr;
}
std::shared_ptr<ColorSpaceConverterBase> ExtensionManager::CreateColorSpaceConverter(const FrameInfo &inputInfo,
const FrameInfo &outputInfo, Extension::ExtensionInfo &extensionInfo) const
{
CHECK_AND_RETURN_RET_LOG(initialized_ == true, nullptr, "Not initialized");
auto extension = FindColorSpaceConverterExtension(inputInfo, outputInfo);
CHECK_AND_RETURN_RET_LOG(extension != nullptr, nullptr, "Create extension failed, get an empty extension");
auto impl = extension->creator();
CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr,
"Call extension creator failed, return a empty impl, extension: %{public}s", extension->info.name.c_str());
extensionInfo = extension->info;
return impl;
}
std::shared_ptr<VideoRefreshRatePredictionBase> ExtensionManager::CreateVideoRefreshRatePredictor() const
{
std::shared_ptr<ExtensionBase> extension;
CHECK_AND_RETURN_RET_LOG(g_algoHandle != nullptr, {}, "dlopen ext fail!");
GetRegisterVRRExtensionFuncs = reinterpret_cast<LibFunctionGetRegisterFunction>
(dlsym(g_algoHandle, "GetRegisterVRRExtensionFuncs"));
CHECK_AND_RETURN_RET_LOG(GetRegisterVRRExtensionFuncs != nullptr, {}, "dlsym Get VRR Extension fail!");
auto registerFunctionPtr = GetRegisterVRRExtensionFuncs();
CHECK_AND_RETURN_RET_LOG(registerFunctionPtr != nullptr, {}, "get GetRegisterVRRExtensionFuncs fail!!");
registerFunctionPtr(reinterpret_cast<uintptr_t>(&extension));
std::shared_ptr<VideoRefreshratePredictionExtension> vrrExtension =
std::static_pointer_cast<VideoRefreshratePredictionExtension>(extension);
auto impl = vrrExtension->creator();
return impl;
}
ColorSpaceConverterDisplaySet ExtensionManager::CreateColorSpaceConverterDisplay() const
{
CHECK_AND_RETURN_RET_LOG(initialized_ == true, {}, "Not initialized");
ColorSpaceConverterDisplaySet impl;
for (const auto &extension : FindColorSpaceConverterDisplayExtension()) {
auto temp = extension->creator();
CHECK_AND_RETURN_RET_LOG(temp != nullptr, {}, "Create failed, extension: %{public}s",
extension->info.name.c_str());
impl.emplace(std::move(temp));
}
return impl;
}
std::shared_ptr<MetadataGeneratorBase> ExtensionManager::CreateMetadataGenerator(const FrameInfo &inputInfo,
Extension::ExtensionInfo &extensionInfo, MetadataGeneratorAlgoType algoType) const
{
CHECK_AND_RETURN_RET_LOG(initialized_ == true, nullptr, "Not initialized");
auto extension = FindMetadataGeneratorExtension(inputInfo, algoType);
CHECK_AND_RETURN_RET_LOG(extension != nullptr, nullptr, "Create failed, get an empty extension");
auto impl = extension->creator();
CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr,
"Call extension creator failed, return a empty impl, extension: %{public}s", extension->info.name.c_str());
extensionInfo = extension->info;
return impl;
}
std::shared_ptr<AihdrEnhancerBase> ExtensionManager::CreateAihdrEnhancer(const FrameInfo &inputInfo,
Extension::ExtensionInfo &extensionInfo) const
{
CHECK_AND_RETURN_RET_LOG(initialized_ == true, nullptr, "Not initialized");
auto extension = FindAihdrEnhancerExtension(inputInfo);
CHECK_AND_RETURN_RET_LOG(extension != nullptr, nullptr, "Create failed, get an empty extension");
auto impl = extension->creator();
CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr,
"Call extension creator failed, return a empty impl, extension: %{public}s", extension->info.name.c_str());
extensionInfo = extension->info;
return impl;
}
int32_t ExtensionManager::NewInstanceId(const ExtensionManager::InstanceVariableType& instance)
{
std::lock_guard<std::mutex> lock(instanceManagementMtx_);
int32_t newId = currentId_;
do {
currentId_ = (currentId_ == MAX_INSTANCE_NUM) ? 0 : currentId_;
if (instanceList_[currentId_] == std::nullopt) {
instanceList_[currentId_] = instance;
newId = currentId_;
++currentId_;
return newId;
}
++currentId_;
} while (currentId_ != newId);
return -1;
}
int32_t ExtensionManager::RemoveInstanceReference(int32_t& id)
{
std::lock_guard<std::mutex> lock(instanceManagementMtx_);
CHECK_AND_RETURN_RET_LOG(id >= 0 && id < MAX_INSTANCE_NUM, VPE_ALGO_ERR_INVALID_VAL, "invalid instance id");
instanceList_[id].reset() ;
id = -1;
return VPE_ALGO_ERR_OK;
}
std::optional<ExtensionManager::InstanceVariableType> ExtensionManager::GetInstance(int32_t id)
{
std::lock_guard<std::mutex> lock(instanceManagementMtx_);
CHECK_AND_RETURN_RET_LOG(id >= 0 && id < MAX_INSTANCE_NUM, std::nullopt, "invalid instance id");
return instanceList_[id];
}
std::shared_ptr<DetailEnhancerBase> ExtensionManager::CreateDetailEnhancer(uint32_t level) const
{
CHECK_AND_RETURN_RET_LOG(initialized_ == true, nullptr, "Not initialized");
auto extension = FindDetailEnhancerExtension(level);
CHECK_AND_RETURN_RET_LOG(extension != nullptr, nullptr,
"Create failed, get an empty extension. level: %{public}d", level);
auto impl = extension->creator();
CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr,
"Call extension creator failed, return a empty impl, extension: %{public}s, level: %{public}d",
extension->info.name.c_str(), level);
return impl;
}
ExtensionList ExtensionManager::LoadExtensions() const
{
ExtensionList extensionList {};
VPEAlgoErrCode ret = LoadStaticExtensions(extensionList);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, {}, "Load extension failed");
LoadDynamicExtensions(extensionList);
return extensionList;
}
ExtensionList ExtensionManager::LoadStaticImageExtensions(
const std::unordered_map<std::string, RegisterExtensionFunc> staticListRegisterMap) const
{
ExtensionList extensionList {};
for (auto &reg : staticListRegisterMap) {
CHECK_AND_RETURN_RET_LOG(reg.second != nullptr, {},
"Get an empty register, extension: %{public}s", reg.first.c_str());
VPE_LOGD("Load extension set: %{public}s", reg.first.c_str());
reg.second(reinterpret_cast<uintptr_t>(&extensionList));
}
return extensionList;
}
bool ExtensionManager::FindImageConverterExtension(
const FrameInfo &inputInfo, const FrameInfo &outputInfo) const
{
auto extensionList = LoadExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), false, "No extension found");
auto colorSpaceConverterCapabilityMap = BuildCaps<ColorSpaceConverterCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!colorSpaceConverterCapabilityMap.empty(), false, "No extension available");
auto key =
std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat, outputInfo.colorSpace, outputInfo.pixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(inputInfo.colorSpace.colorSpaceInfo, inputInfo.pixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(outputInfo.colorSpace.colorSpaceInfo, outputInfo.pixelFormat);
const auto iter = colorSpaceConverterCapabilityMap.find(key);
CHECK_AND_RETURN_RET_LOG(iter != colorSpaceConverterCapabilityMap.cend() && !iter->second.empty(), false,
"CSC Extension is not found");
return true;
}
bool ExtensionManager::FindImageComposeExtension(
const FrameInfo &inputInfo, const FrameInfo &outputInfo) const
{
auto extensionList = LoadDynamicComposeExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), false, "No extension found");
auto colorSpaceConverterCapabilityMap = BuildCaps<ColorSpaceConverterCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!colorSpaceConverterCapabilityMap.empty(), false, "No extension available");
auto key =
std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat, outputInfo.colorSpace, outputInfo.pixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(inputInfo.colorSpace.colorSpaceInfo, inputInfo.pixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(outputInfo.colorSpace.colorSpaceInfo, outputInfo.pixelFormat);
const auto iter = colorSpaceConverterCapabilityMap.find(key);
CHECK_AND_RETURN_RET_LOG(iter != colorSpaceConverterCapabilityMap.cend() && !iter->second.empty(), false,
"CSC Extension is not found");
return true;
}
bool ExtensionManager::FindImageDecomposeExtension(
const FrameInfo &inputInfo, const FrameInfo &outputInfo) const
{
auto extensionList = LoadDynamicDecomposeExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), false, "No extension found");
auto colorSpaceConverterCapabilityMap = BuildCaps<ColorSpaceConverterCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!colorSpaceConverterCapabilityMap.empty(), false, "No extension available");
auto key =
std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat, outputInfo.colorSpace, outputInfo.pixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(inputInfo.colorSpace.colorSpaceInfo, inputInfo.pixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(outputInfo.colorSpace.colorSpaceInfo, outputInfo.pixelFormat);
const auto iter = colorSpaceConverterCapabilityMap.find(key);
CHECK_AND_RETURN_RET_LOG(iter != colorSpaceConverterCapabilityMap.cend() && !iter->second.empty(), false,
"CSC Extension is not found");
return true;
}
bool ExtensionManager::FindImageMetadataGenExtension(const FrameInfo &inputInfo) const
{
auto extensionList = LoadDynamicMetadataGenExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), false, "No extension found");
auto metadataGeneratorCapabilityMap = BuildCaps<MetadataGeneratorCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!metadataGeneratorCapabilityMap.empty(), false, "No extension available");
auto key = std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat,
MetadataGeneratorAlgoType::META_GEN_ALGO_TYPE_IMAGE);
VPE_LOG_PRINT_METADATA_GEN_CAPBILITY(inputInfo.colorSpace.colorSpaceInfo, inputInfo.pixelFormat,
MetadataGeneratorAlgoType::META_GEN_ALGO_TYPE_IMAGE);
const auto iter = metadataGeneratorCapabilityMap.find(key);
CHECK_AND_RETURN_RET_LOG(iter != metadataGeneratorCapabilityMap.cend() && !iter->second.empty(), false,
"CSC metadata generator extension is not found");
return true;
}
bool ImageProcessing_IsColorSpaceConversionSupported(const ColorSpaceInfo inputInfo, const ColorSpaceInfo outputInfo)
{
FrameInfo inputFrameInfo;
inputFrameInfo.colorSpace = {GetColorSpaceInfo(inputInfo.colorSpace), inputInfo.metadataType};
inputFrameInfo.pixelFormat = inputInfo.pixelFormat;
FrameInfo outputFrameInfo;
outputFrameInfo.colorSpace = {GetColorSpaceInfo(outputInfo.colorSpace), outputInfo.metadataType};
outputFrameInfo.pixelFormat = outputInfo.pixelFormat;
ExtensionManager::GetInstance().IncreaseInstance();
auto flag = ExtensionManager::GetInstance().FindImageConverterExtension(inputFrameInfo, outputFrameInfo);
ExtensionManager::GetInstance().DecreaseInstance();
return flag;
}
bool ImageProcessing_IsCompositionSupported(const ColorSpaceInfo inputInfo, const ColorSpaceInfo outputInfo)
{
FrameInfo inputFrameInfo;
inputFrameInfo.colorSpace = {GetColorSpaceInfo(inputInfo.colorSpace), inputInfo.metadataType};
inputFrameInfo.pixelFormat = inputInfo.pixelFormat;
FrameInfo outputFrameInfo;
outputFrameInfo.colorSpace = {GetColorSpaceInfo(outputInfo.colorSpace), outputInfo.metadataType};
outputFrameInfo.pixelFormat = outputInfo.pixelFormat;
ExtensionManager::GetInstance().IncreaseInstance();
auto flag = ExtensionManager::GetInstance().FindImageComposeExtension(inputFrameInfo, outputFrameInfo);
ExtensionManager::GetInstance().DecreaseInstance();
return flag;
}
bool ImageProcessing_IsDecompositionSupported(const ColorSpaceInfo inputInfo, const ColorSpaceInfo outputInfo)
{
FrameInfo inputFrameInfo;
inputFrameInfo.colorSpace = {GetColorSpaceInfo(inputInfo.colorSpace), inputInfo.metadataType};
inputFrameInfo.pixelFormat = inputInfo.pixelFormat;
FrameInfo outputFrameInfo;
outputFrameInfo.colorSpace = {GetColorSpaceInfo(outputInfo.colorSpace), outputInfo.metadataType};
outputFrameInfo.pixelFormat = outputInfo.pixelFormat;
ExtensionManager::GetInstance().IncreaseInstance();
auto flag = ExtensionManager::GetInstance().FindImageDecomposeExtension(inputFrameInfo, outputFrameInfo);
ExtensionManager::GetInstance().DecreaseInstance();
return flag;
}
bool ImageProcessing_IsMetadataGenerationSupported(const ColorSpaceInfo inputInfo)
{
FrameInfo inputFrameInfo;
inputFrameInfo.colorSpace = {GetColorSpaceInfo(inputInfo.colorSpace), inputInfo.metadataType};
inputFrameInfo.pixelFormat = inputInfo.pixelFormat;
ExtensionManager::GetInstance().IncreaseInstance();
auto flag = ExtensionManager::GetInstance().FindImageMetadataGenExtension(inputFrameInfo);
ExtensionManager::GetInstance().DecreaseInstance();
return flag;
}
VPEAlgoErrCode ExtensionManager::LoadStaticExtensions(ExtensionList& extensionList) const
{
for (auto &reg : staticExtensionsRegisterMap) {
CHECK_AND_RETURN_RET_LOG(reg.second != nullptr, VPE_ALGO_ERR_UNKNOWN,
"Get an empty register, extension: %{public}s", reg.first.c_str());
VPE_LOGD("Load extension set: %{public}s", reg.first.c_str());
reg.second(reinterpret_cast<uintptr_t>(&extensionList));
}
return VPE_ALGO_ERR_OK;
}
void ExtensionManager::LoadDynamicExtensions(ExtensionList& extensionList) const
{
CHECK_AND_RETURN_LOG(g_algoHandle != nullptr, "dlopen ext fail!");
GetRegisterExtensionFuncs = reinterpret_cast<LibFunctionGetRegisters>
(dlsym(g_algoHandle, "GetRegisterExtensionFuncs"));
CHECK_AND_RETURN_LOG(GetRegisterExtensionFuncs != nullptr, "dlsym GetRegisterExtensionFuncs fail!");
auto dynamicExtensionsRegisterMapPtr = GetRegisterExtensionFuncs();
CHECK_AND_RETURN_LOG(dynamicExtensionsRegisterMapPtr != nullptr, "get dynamicExtensionsRegisterMap fail!!");
auto dynamicExtensionsRegisterMap = *dynamicExtensionsRegisterMapPtr;
for (auto &reg : dynamicExtensionsRegisterMap) {
if (reg.second != nullptr) {
VPE_LOGD("Load extension set: %{public}s", reg.first.c_str());
reg.second(reinterpret_cast<uintptr_t>(&extensionList));
}
}
}
ExtensionList ExtensionManager::LoadDynamicMetadataGenExtensions() const
{
ExtensionList extensionList {};
CHECK_AND_RETURN_RET_LOG(g_algoHandle != nullptr, {}, "dlopen ext fail!");
GetRegisterMetdataGenExtensionFuncs = reinterpret_cast<LibFunctionGetRegisters>
(dlsym(g_algoHandle, "GetRegisterMetdataGenExtensionFuncs"));
CHECK_AND_RETURN_RET_LOG(GetRegisterMetdataGenExtensionFuncs != nullptr, {},
"dlsym GetRegisterMetdataGenExtensionFuncs fail!");
auto dynamicExtensionsRegisterMapPtr = GetRegisterMetdataGenExtensionFuncs();
CHECK_AND_RETURN_RET_LOG(dynamicExtensionsRegisterMapPtr != nullptr, {},
"get dynamicMetadataGenExtensions fail!!");
auto dynamicExtensionsRegisterMap = *dynamicExtensionsRegisterMapPtr;
for (auto &reg : dynamicExtensionsRegisterMap) {
if (reg.second != nullptr) {
VPE_LOGD("Load extension set: %{public}s", reg.first.c_str());
reg.second(reinterpret_cast<uintptr_t>(&extensionList));
}
}
return extensionList;
}
ExtensionList ExtensionManager::LoadDynamicComposeExtensions() const
{
ExtensionList extensionList {};
CHECK_AND_RETURN_RET_LOG(g_algoHandle != nullptr, {}, "dlopen ext fail!");
GetRegisterComposeExtensionFuncs = reinterpret_cast<LibFunctionGetRegisters>
(dlsym(g_algoHandle, "GetRegisterComposeExtensionFuncs"));
CHECK_AND_RETURN_RET_LOG(GetRegisterComposeExtensionFuncs != nullptr, {},
"dlsym GetRegisterComposeExtensionFuncs fail!");
auto dynamicExtensionsRegisterMapPtr = GetRegisterComposeExtensionFuncs();
CHECK_AND_RETURN_RET_LOG(dynamicExtensionsRegisterMapPtr != nullptr, {},
"get dynamicMetadataGenExtensions fail!!");
auto dynamicExtensionsRegisterMap = *dynamicExtensionsRegisterMapPtr;
for (auto &reg : dynamicExtensionsRegisterMap) {
if (reg.second != nullptr) {
VPE_LOGD("Load extension set: %{public}s", reg.first.c_str());
reg.second(reinterpret_cast<uintptr_t>(&extensionList));
}
}
return extensionList;
}
ExtensionList ExtensionManager::LoadDynamicDecomposeExtensions() const
{
ExtensionList extensionList {};
CHECK_AND_RETURN_RET_LOG(g_algoHandle != nullptr, {}, "dlopen ext fail, g_algoHandle null!");
GetRegisterDecomposeExtensionFuncs = reinterpret_cast<LibFunctionGetRegisters>
(dlsym(g_algoHandle, "GetRegisterDecomposeExtensionFuncs"));
CHECK_AND_RETURN_RET_LOG(GetRegisterDecomposeExtensionFuncs != nullptr, {},
"dlsym GetRegisterDecomposeExtensionFuncs fail!");
auto dynamicExtensionsRegisterMapPtr = GetRegisterDecomposeExtensionFuncs();
CHECK_AND_RETURN_RET_LOG(dynamicExtensionsRegisterMapPtr != nullptr, {},
"get dynamicMetadataGenExtensions fail!!");
auto dynamicExtensionsRegisterMap = *dynamicExtensionsRegisterMapPtr;
for (auto &reg : dynamicExtensionsRegisterMap) {
if (reg.second != nullptr) {
VPE_LOGD("Load extension set: %{public}s", reg.first.c_str());
reg.second(reinterpret_cast<uintptr_t>(&extensionList));
}
}
return extensionList;
}
template<typename T>
T ExtensionManager::BuildCaps(const ExtensionList& extensionList) const
{
VPEAlgoErrCode err = VPE_ALGO_ERR_OK;
T capMap {};
for (size_t idx = 0; idx < extensionList.size(); ++idx) {
auto extension = extensionList[idx];
CHECK_AND_RETURN_RET_LOG(extension != nullptr, {}, "Extension is nullptr");
if constexpr (std::is_same_v<T, ColorSpaceConverterCapabilityMap>) {
if (extension->info.type == ExtensionType::COLORSPACE_CONVERTER) {
err = BuildColorSpaceConverterCaps(extension, idx, capMap);
CHECK_AND_LOG(err == VPE_ALGO_ERR_OK, "Build caps failed, extension: %{public}s",
extension->info.name.c_str());
}
} else if constexpr (std::is_same_v<T, ColorSpaceConverterDisplayCapabilityMap>) {
if (extension->info.type == ExtensionType::COLORSPACE_CONVERTER_DISPLAY) {
err = BuildColorSpaceConverterDisplayCaps(extension, idx, capMap);
CHECK_AND_LOG(err == VPE_ALGO_ERR_OK, "Build caps failed, extension: %{public}s",
extension->info.name.c_str());
}
} else if constexpr (std::is_same_v<T, MetadataGeneratorCapabilityMap>) {
if (extension->info.type == ExtensionType::METADATA_GENERATOR) {
err = BuildMetadataGeneratorCaps(extension, idx, capMap);
CHECK_AND_LOG(err == VPE_ALGO_ERR_OK, "Build caps failed, extension: %{public}s",
extension->info.name.c_str());
}
} else if constexpr (std::is_same_v<T, DetailEnhancerCapabilityMap>) {
if (extension->info.type == ExtensionType::DETAIL_ENHANCER) {
err = BuildDetailEnhancerCaps(extension, idx, capMap);
CHECK_AND_LOG(err == VPE_ALGO_ERR_OK, "Build caps failed, extension: %{public}s",
extension->info.name.c_str());
}
} else if constexpr (std::is_same_v<T, AihdrEnhancerCapabilityMap>) {
if (extension->info.type == ExtensionType::AIHDR_ENHANCER) {
err = BuildAihdrEnhancerCaps(extension, idx, capMap);
CHECK_AND_LOG(err == VPE_ALGO_ERR_OK, "Build caps failed, extension: %{public}s",
extension->info.name.c_str());
}
} else {
VPE_LOGE("Unknown extension type");
return {};
}
}
return capMap;
}
std::shared_ptr<ColorSpaceConverterExtension> ExtensionManager::FindColorSpaceConverterExtension(
const FrameInfo &inputInfo, const FrameInfo &outputInfo) const
{
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(inputInfo.colorSpace.colorSpaceInfo, inputInfo.pixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(outputInfo.colorSpace.colorSpaceInfo, outputInfo.pixelFormat);
auto extensionList = LoadExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), nullptr, "No extension found");
auto colorSpaceConverterCapabilityMap = BuildCaps<ColorSpaceConverterCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!colorSpaceConverterCapabilityMap.empty(), nullptr, "No extension available");
auto key =
std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat, outputInfo.colorSpace, outputInfo.pixelFormat);
const auto iter = colorSpaceConverterCapabilityMap.find(key);
if (iter == colorSpaceConverterCapabilityMap.cend() || iter->second.empty()) {
VPE_LOGE("CSC Extension is not found");
CM_ColorSpaceInfo CSDesc = inputInfo.colorSpace.colorSpaceInfo;
VPE_LOGE("input: (primary=%{public}3d,trans=%{public}3d,mat=%{public}3d,range=%{public}3d,"\
"pixel=%{public}3d,metadata=%{public}3d", (CSDesc).primaries, (CSDesc).transfunc, (CSDesc).matrix,
(CSDesc).range, inputInfo.pixelFormat, inputInfo.colorSpace.metadataType);
CSDesc = outputInfo.colorSpace.colorSpaceInfo;
VPE_LOGE("output: (primary=%{public}3d,trans=%{public}3d,mat=%{public}3d,range=%{public}3d,"\
"pixel=%{public}3d,metadata=%{public}3d", (CSDesc).primaries, (CSDesc).transfunc, (CSDesc).matrix,
(CSDesc).range, outputInfo.pixelFormat, outputInfo.colorSpace.metadataType);
return nullptr;
}
size_t idx = std::get<2>(*(iter->second.cbegin()));
return std::static_pointer_cast<ColorSpaceConverterExtension>(extensionList[idx]);
}
ColorSpaceConverterDisplayExtensionSet ExtensionManager::FindColorSpaceConverterDisplayExtension() const
{
auto extensionList = LoadExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), {}, "No extension found");
ColorSpaceConverterDisplayExtensionSet extensions {};
for (const auto &extension : extensionList) {
CHECK_AND_CONTINUE_LOG(extension != nullptr, "Get an empty extension");
if (extension->info.type != ExtensionType::COLORSPACE_CONVERTER_DISPLAY) {
continue;
}
extensions.emplace(std::static_pointer_cast<ColorSpaceConverterDisplayExtension>(extension));
}
return extensions;
}
std::shared_ptr<MetadataGeneratorExtension> ExtensionManager::FindMetadataGeneratorExtension(const FrameInfo &inputInfo,
MetadataGeneratorAlgoType algoType) const
{
auto extensionList = LoadExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), nullptr, "No extension found");
auto metadataGeneratorCapabilityMap = BuildCaps<MetadataGeneratorCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!metadataGeneratorCapabilityMap.empty(), nullptr, "No extension available");
auto key = std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat, algoType);
VPE_LOG_PRINT_METADATA_GEN_CAPBILITY(inputInfo.colorSpace.colorSpaceInfo, inputInfo.pixelFormat, algoType);
const auto iter = metadataGeneratorCapabilityMap.find(key);
CHECK_AND_RETURN_RET_LOG(iter != metadataGeneratorCapabilityMap.cend() && !iter->second.empty(), nullptr,
"CSC metadata generator extension is not found");
size_t idx = std::get<2>(*(iter->second.cbegin()));
return std::static_pointer_cast<MetadataGeneratorExtension>(extensionList[idx]);
}
VPEAlgoErrCode ExtensionManager::BuildColorSpaceConverterCaps(const std::shared_ptr<ExtensionBase> &ext, size_t idx,
ColorSpaceConverterCapabilityMap& colorSpaceConverterCapabilityMap) const
{
VPEAlgoErrCode err = VPE_ALGO_ERR_OK;
auto realExtension = std::static_pointer_cast<ColorSpaceConverterExtension>(ext);
auto capabilities = realExtension->capabilitiesBuilder();
for (const auto &cap : capabilities) {
err = ExtractColorSpaceConverterCap(cap, idx, colorSpaceConverterCapabilityMap);
}
return err;
}
std::shared_ptr<DetailEnhancerExtension> ExtensionManager::FindDetailEnhancerExtension(uint32_t level) const
{
auto extensionList = LoadExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), nullptr, "No extension found");
auto detailEnhancerCapabilityMap = BuildCaps<DetailEnhancerCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!detailEnhancerCapabilityMap.empty(), nullptr, "No extension available");
const auto iter = detailEnhancerCapabilityMap.find(level);
CHECK_AND_RETURN_RET_LOG(iter != detailEnhancerCapabilityMap.cend(), nullptr,
"Detail enhancer Extension is not found");
size_t idx = iter->second;
return std::static_pointer_cast<DetailEnhancerExtension>(extensionList[idx]);
}
std::shared_ptr<AihdrEnhancerExtension> ExtensionManager::FindAihdrEnhancerExtension(const FrameInfo &inputInfo) const
{
auto extensionList = LoadExtensions();
CHECK_AND_RETURN_RET_LOG(!extensionList.empty(), nullptr, "No extension found");
auto aihdrEnhancerCapabilityMap = BuildCaps<AihdrEnhancerCapabilityMap>(extensionList);
CHECK_AND_RETURN_RET_LOG(!aihdrEnhancerCapabilityMap.empty(), nullptr, "No extension available");
auto key = std::make_tuple(inputInfo.colorSpace, inputInfo.pixelFormat);
const auto iter = aihdrEnhancerCapabilityMap.find(key);
CHECK_AND_RETURN_RET_LOG(iter != aihdrEnhancerCapabilityMap.cend() && !iter->second.empty(), nullptr,
"Aihdr enhancer extension is not found");
size_t idx = std::get<2>(*(iter->second.cbegin()));
return std::static_pointer_cast<AihdrEnhancerExtension>(extensionList[idx]);
}
VPEAlgoErrCode ExtensionManager::ExtractColorSpaceConverterCap(const ColorSpaceConverterCapability& cap, size_t idx,
ColorSpaceConverterCapabilityMap& colorSpaceConverterCapabilityMap) const
{
auto inputColorSpaceDesc = cap.inputColorSpaceDesc;
auto outputColorSpaceDesc = cap.outputColorSpaceDesc;
uint32_t rank = cap.rank;
int32_t version = cap.version;
for (const auto &[inputPixelFormat, outputPixelFormats] : cap.pixelFormatMap) {
for (const auto &outputPixelFormat : outputPixelFormats) {
auto key = std::make_tuple(inputColorSpaceDesc, inputPixelFormat, outputColorSpaceDesc, outputPixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(inputColorSpaceDesc.colorSpaceInfo, inputPixelFormat);
VPE_LOG_PRINT_COLOR_SPACE_CAPBILITY(outputColorSpaceDesc.colorSpaceInfo, outputPixelFormat);
auto value = std::make_tuple(rank, version, idx);
colorSpaceConverterCapabilityMap[key].push_back(value);
}
}
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ExtensionManager::BuildColorSpaceConverterDisplayCaps(const std::shared_ptr<ExtensionBase> &ext,
size_t idx, ColorSpaceConverterDisplayCapabilityMap& colorSpaceConverterDisplayCapabilityMap) const
{
(void)ext;
(void)idx;
(void)colorSpaceConverterDisplayCapabilityMap;
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ExtensionManager::ExtractMetadataGeneratorCap(const MetadataGeneratorCapability &cap, size_t idx,
MetadataGeneratorAlgoType algoType, MetadataGeneratorCapabilityMap& metadataGeneratorCapabilityMap) const
{
auto colorSpaceDesc = cap.colorspaceDesc;
uint32_t rank = cap.rank;
int32_t version = cap.version;
for (const auto &pixelFormat : cap.pixelFormats) {
auto key = std::make_tuple(colorSpaceDesc, pixelFormat, algoType);
VPE_LOG_PRINT_METADATA_GEN_CAPBILITY(colorSpaceDesc.colorSpaceInfo, pixelFormat, algoType);
auto value = std::make_tuple(rank, version, idx);
metadataGeneratorCapabilityMap[key].push_back(value);
}
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ExtensionManager::BuildMetadataGeneratorCaps(const std::shared_ptr<ExtensionBase> &ext, size_t idx,
MetadataGeneratorCapabilityMap& metadataGeneratorCapabilityMap) const
{
VPEAlgoErrCode err = VPE_ALGO_ERR_OK;
auto realExtension = std::static_pointer_cast<MetadataGeneratorExtension>(ext);
auto capabilities = realExtension->capabilitiesBuilder();
MetadataGeneratorAlgoType algoType = MetadataGeneratorAlgoType::META_GEN_ALGO_TYPE_IMAGE;
if (ext->info.name == "VideoMetadataGen") {
algoType = MetadataGeneratorAlgoType::META_GEN_ALGO_TYPE_VIDEO;
}
for (const auto &cap : capabilities) {
err = ExtractMetadataGeneratorCap(cap, idx, algoType, metadataGeneratorCapabilityMap);
}
return err;
}
VPEAlgoErrCode ExtensionManager::BuildDetailEnhancerCaps(const std::shared_ptr<ExtensionBase>& ext, size_t idx,
DetailEnhancerCapabilityMap& detailEnhancerCapabilityMap) const
{
auto realExtension = std::static_pointer_cast<DetailEnhancerExtension>(ext);
auto capabilities = realExtension->capabilitiesBuilder();
for (const auto &level : capabilities.levels) {
detailEnhancerCapabilityMap.emplace(level, idx);
}
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ExtensionManager::ExtractAihdrEnhancerCap(const AihdrEnhancerCapability &cap, size_t idx,
AihdrEnhancerCapabilityMap& aihdrEnhancerCapabilityMap) const
{
auto colorSpaceDesc = cap.colorspaceDesc;
uint32_t rank = cap.rank;
int32_t version = cap.version;
for (const auto &pixelFormat : cap.pixelFormats) {
auto key = std::make_tuple(colorSpaceDesc, pixelFormat);
auto value = std::make_tuple(rank, version, idx);
aihdrEnhancerCapabilityMap[key].push_back(value);
}
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode ExtensionManager::BuildAihdrEnhancerCaps(const std::shared_ptr<ExtensionBase> &ext, size_t idx,
AihdrEnhancerCapabilityMap& aihdrEnhancerCapabilityMap) const
{
VPEAlgoErrCode err = VPE_ALGO_ERR_OK;
auto realExtension = std::static_pointer_cast<AihdrEnhancerExtension>(ext);
auto capabilities = realExtension->capabilitiesBuilder();
for (const auto &cap : capabilities) {
err = ExtractAihdrEnhancerCap(cap, idx, aihdrEnhancerCapabilityMap);
}
return err;
}
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,38 @@
/*
* 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 FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_AIHDR_ENHANCER_EXTENSION_H
#define FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_AIHDR_ENHANCER_EXTENSION_H
#include <vector>
#include "aihdr_enhancer_base.h"
#include "aihdr_enhancer_capability.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
struct AihdrEnhancerExtension : public ExtensionBase {
AihdrEnhancerCreator creator;
AihdrEnhancerCapabilitiesBuilder capabilitiesBuilder;
};
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_AIHDR_ENHANCER_EXTENSION_H
@@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_COLORSPACE_CONVERTER_DISPLAY_EXTENSION_H
#define FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_COLORSPACE_CONVERTER_DISPLAY_EXTENSION_H
#include <vector>
#include "colorspace_converter_display_base.h"
#include "colorspace_converter_display_capability.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
struct ColorSpaceConverterDisplayExtension : public ExtensionBase {
ColorSpaceConverterDisplayCreator creator;
ColorSpaceConverterDisplayCapabilitiesBuilder capabilitiesBuilder;
};
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_COLORSPACE_CONVERTER_DISPLAY_EXTENSION_H
@@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_COLORSPACE_CONVERTER_EXTENSION_H
#define FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_COLORSPACE_CONVERTER_EXTENSION_H
#include <vector>
#include "colorspace_converter_base.h"
#include "colorspace_converter_capability.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
struct ColorSpaceConverterExtension : public ExtensionBase {
ColorSpaceConverterCreator creator;
ColorSpaceConverterCapabilitiesBuilder capabilitiesBuilder;
};
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_COLORSPACE_CONVERTER_EXTENSION_H
@@ -0,0 +1,40 @@
/*
* 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 FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_DETAIL_ENHANCER_EXTENSION_H
#define FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_DETAIL_ENHANCER_EXTENSION_H
#include <vector>
#include "detail_enhancer_base.h"
#include "detail_enhancer_capability.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
struct DetailEnhancerExtension : public ExtensionBase {
DetailEnhancerCreator creator;
DetailEnhancerCapabilitiesBuilder capabilitiesBuilder;
};
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_DETAIL_ENHANCER_EXTENSION_H
@@ -0,0 +1,49 @@
/*
* 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.
*/
#ifndef FRMEWORK_ALGORITHM_EXTENSION_MANAGER_EXTENSION_BASE_H
#define FRMEWORK_ALGORITHM_EXTENSION_MANAGER_EXTENSION_BASE_H
#include <string>
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
enum class ExtensionType {
COLORSPACE_CONVERTER,
COLORSPACE_CONVERTER_DISPLAY,
METADATA_GENERATOR,
DETAIL_ENHANCER,
VIDEO_REFRESHRATE_PREDICTION,
AIHDR_ENHANCER
};
struct ExtensionInfo {
ExtensionType type {ExtensionType::COLORSPACE_CONVERTER};
std::string name;
std::string version;
};
struct ExtensionBase {
virtual ~ExtensionBase() = default;
ExtensionInfo info;
};
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRMEWORK_ALGORITHM_EXTENSION_MANAGER_EXTENSION_BASE_H
@@ -0,0 +1,179 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_EXTENSION_MANAGER_H
#define FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_EXTENSION_MANAGER_H
#include <atomic>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <set>
#include <tuple>
#include <unordered_set>
#include <variant>
#include <vector>
#include "aihdr_enhancer.h"
#include "aihdr_enhancer_extension.h"
#include "static_extension_list.h"
#include "extension_base.h"
#include "frame_info.h"
#include "colorspace_converter.h"
#include "metadata_generator.h"
#include "detail_enhancer_image.h"
#include "video_refreshrate_prediction.h"
#include "colorspace_converter_capability.h"
#include "colorspace_converter_display_capability.h"
#include "metadata_generator_capability.h"
#include "colorspace_converter_extension.h"
#include "colorspace_converter_display_extension.h"
#include "metadata_generator_extension.h"
#include "detail_enhancer_extension.h"
#include "video_refreshrate_prediction_extension.h"
#include "utils.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
namespace {
/*
{
(inputColorSpaceDesc, inputPixelFormat, outputColorSpaceDesc, outputPixelFormat): [
(rank, version, extensionListIndex),
(rank, version, extensionListIndex),
......
]
}*/
using ColorSpaceConverterCapabilityMap =
std::map<
std::tuple<ColorSpaceDescription, GraphicPixelFormat, ColorSpaceDescription, GraphicPixelFormat>,
std::vector<std::tuple<uint32_t, int32_t, size_t>>>;
using ColorSpaceConverterDisplayCapabilityMap = ColorSpaceConverterCapabilityMap;
/*
{
(colorSpaceDesc, pixelFormat, metadataGeneratorAlgoType): [
(rank, version, extensionListIndex),
(rank, version, extensionListIndex),
......
]
}
*/
using MetadataGeneratorCapabilityMap =
std::map<
std::tuple<ColorSpaceDescription, GraphicPixelFormat, MetadataGeneratorAlgoType>,
std::vector<std::tuple<uint32_t, int32_t, size_t>>>;
using DetailEnhancerCapabilityMap = std::map<uint32_t, size_t>;
using AihdrEnhancerCapabilityMap =
std::map<
std::tuple<ColorSpaceDescription, GraphicPixelFormat>,
std::vector<std::tuple<uint32_t, int32_t, size_t>>>;
using ColorSpaceConverterDisplaySet = std::set<std::shared_ptr<ColorSpaceConverterDisplayBase>>;
using ColorSpaceConverterDisplayExtensionSet = std::set<std::shared_ptr<ColorSpaceConverterDisplayExtension>>;
}
class ExtensionManager {
public:
static ExtensionManager& GetInstance();
bool IsColorSpaceConversionSupported(const FrameInfo &inputInfo, const FrameInfo &outputInfo) const;
std::shared_ptr<ColorSpaceConverterBase> CreateColorSpaceConverter(const FrameInfo &inputInfo,
const FrameInfo &outputInfo, Extension::ExtensionInfo &extensionInfo) const;
ColorSpaceConverterDisplaySet CreateColorSpaceConverterDisplay() const;
std::shared_ptr<MetadataGeneratorBase> CreateMetadataGenerator(const FrameInfo &inputInfo,
Extension::ExtensionInfo &extensionInfo, MetadataGeneratorAlgoType algoType) const;
std::shared_ptr<AihdrEnhancerBase> CreateAihdrEnhancer(const FrameInfo &inputInfo,
Extension::ExtensionInfo &extensionInfo) const;
std::shared_ptr<DetailEnhancerBase> CreateDetailEnhancer(uint32_t level) const;
std::shared_ptr<VideoRefreshRatePredictionBase> CreateVideoRefreshRatePredictor() const;
using InstanceVariableType = std::variant<std::shared_ptr<ColorSpaceConverter>,
std::shared_ptr<MetadataGenerator>,
std::shared_ptr<DetailEnhancerImage>,
std::shared_ptr<AihdrEnhancer>>;
void IncreaseInstance();
void DecreaseInstance();
int32_t NewInstanceId(const InstanceVariableType& instance);
int32_t RemoveInstanceReference(int32_t& id);
std::optional<InstanceVariableType> GetInstance(int32_t id);
bool FindImageConverterExtension(const FrameInfo &inputInfo, const FrameInfo &outputInfo) const;
bool FindImageComposeExtension(const FrameInfo &inputInfo, const FrameInfo &outputInfo) const;
bool FindImageDecomposeExtension(const FrameInfo &inputInfo, const FrameInfo &outputInfo) const;
bool FindImageMetadataGenExtension(const FrameInfo &inputInfo) const;
private:
VPEAlgoErrCode Init();
ExtensionManager();
~ExtensionManager();
ExtensionManager(const ExtensionManager&) = delete;
ExtensionManager& operator=(const ExtensionManager&) = delete;
std::shared_ptr<ColorSpaceConverterExtension> FindColorSpaceConverterExtension(const FrameInfo &inputInfo,
const FrameInfo &outputInfo) const;
ColorSpaceConverterDisplayExtensionSet FindColorSpaceConverterDisplayExtension() const;
std::shared_ptr<MetadataGeneratorExtension> FindMetadataGeneratorExtension(const FrameInfo &inputInfo,
MetadataGeneratorAlgoType algoType) const;
std::shared_ptr<AihdrEnhancerExtension> FindAihdrEnhancerExtension(const FrameInfo &inputInfo) const;
std::shared_ptr<DetailEnhancerExtension> FindDetailEnhancerExtension(uint32_t level) const;
ExtensionList LoadExtensions() const;
VPEAlgoErrCode LoadStaticExtensions(ExtensionList& extensionList) const;
ExtensionList LoadStaticImageExtensions(
const std::unordered_map<std::string, RegisterExtensionFunc> staticListRegisterMap) const;
ExtensionList LoadDynamicMetadataGenExtensions() const;
ExtensionList LoadDynamicComposeExtensions() const;
ExtensionList LoadDynamicDecomposeExtensions() const;
void LoadDynamicExtensions(ExtensionList& extensionList) const;
template<typename T> T BuildCaps(const ExtensionList& extensionList) const;
VPEAlgoErrCode BuildColorSpaceConverterCaps(const std::shared_ptr<ExtensionBase>& ext, size_t idx,
ColorSpaceConverterCapabilityMap& colorSpaceConverterCapabilityMap) const;
VPEAlgoErrCode BuildColorSpaceConverterDisplayCaps(const std::shared_ptr<ExtensionBase>& ext, size_t idx,
ColorSpaceConverterDisplayCapabilityMap& colorSpaceConverterDisplayCapabilityMap) const;
VPEAlgoErrCode BuildMetadataGeneratorCaps(const std::shared_ptr<ExtensionBase>& ext, size_t idx,
MetadataGeneratorCapabilityMap& metadataGeneratorCapabilityMap) const;
VPEAlgoErrCode BuildAihdrEnhancerCaps(const std::shared_ptr<ExtensionBase>& ext, size_t idx,
AihdrEnhancerCapabilityMap& aihdrEnhancerCapabilityMap) const;
VPEAlgoErrCode BuildDetailEnhancerCaps(const std::shared_ptr<ExtensionBase>& ext, size_t idx,
DetailEnhancerCapabilityMap& detailEnhancerCapabilityMap) const;
VPEAlgoErrCode ExtractColorSpaceConverterCap(const ColorSpaceConverterCapability& cap, size_t idx,
ColorSpaceConverterCapabilityMap& colorSpaceConverterCapabilityMap) const;
VPEAlgoErrCode ExtractMetadataGeneratorCap(const MetadataGeneratorCapability &cap, size_t idx,
MetadataGeneratorAlgoType algoType, MetadataGeneratorCapabilityMap& metadataGeneratorCapabilityMap) const;
VPEAlgoErrCode ExtractAihdrEnhancerCap(const AihdrEnhancerCapability &cap, size_t idx,
AihdrEnhancerCapabilityMap& aihdrEnhancerCapabilityMap) const;
std::atomic<bool> initialized_ {false};
static constexpr int32_t MAX_INSTANCE_NUM { 1024 };
std::mutex instanceManagementMtx_;
std::mutex instanceCountMtx_;
int32_t currentId_ { 0 };
int32_t usedInstance_ { 0 };
std::array<std::optional<InstanceVariableType>, MAX_INSTANCE_NUM> instanceList_ { std::nullopt };
};
extern "C" bool ImageProcessing_IsColorSpaceConversionSupported(const ColorSpaceInfo inputInfo,
const ColorSpaceInfo outputInfo);
extern "C" bool ImageProcessing_IsCompositionSupported(const ColorSpaceInfo inputInfo,
const ColorSpaceInfo outputInfo);
extern "C" bool ImageProcessing_IsDecompositionSupported(const ColorSpaceInfo inputInfo,
const ColorSpaceInfo outputInfo);
extern "C" bool ImageProcessing_IsMetadataGenerationSupported(const ColorSpaceInfo inputInfo);
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_EXTENSION_MANAGER_H
@@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_METADATA_GENERATOR_EXTENSION_H
#define FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_METADATA_GENERATOR_EXTENSION_H
#include <vector>
#include "metadata_generator_base.h"
#include "metadata_generator_capability.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
struct MetadataGeneratorExtension : public ExtensionBase {
MetadataGeneratorCreator creator;
MetadataGeneratorCapabilitiesBuilder capabilitiesBuilder;
};
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_METADATA_GENERATOR_EXTENSION_H
@@ -0,0 +1,23 @@
/*
* 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.
*/
#ifndef VPE_FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_STATIC_EXTENSION_LIST_H
#define VPE_FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_STATIC_EXTENSION_LIST_H
namespace OHOS::Media::VideoProcessingEngine::Extension {
using RegisterExtensionFunc = void (*)(uintptr_t extensionListAddr);
const std::unordered_map<std::string, RegisterExtensionFunc> staticExtensionsRegisterMap = {
};
} // namespace OHOS::Media::VideoProcessingEngine::Extension
#endif // VPE_FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_STATIC_EXTENSION_LIST_H
@@ -0,0 +1,49 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_UTILS_H
#define FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_UTILS_H
#include <cstdint>
#include <functional>
#include <memory>
#include <vector>
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
namespace Utils {
using RegisterExtensionFunc = std::function<std::vector<std::shared_ptr<ExtensionBase>>()>;
} // namespace Utils
using ExtensionList = std::vector<std::shared_ptr<ExtensionBase>>;
void DoRegisterExtensions(uintptr_t addr, Utils::RegisterExtensionFunc func);
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#define EXTENSION_EXPORT extern "C" __attribute__((visibility("default")))
#define REGISTER_EXTENSIONS(libName, registerFunc) \
EXTENSION_EXPORT void Register##libName##Extensions(uintptr_t extensionListAddr) \
{ \
OHOS::Media::VideoProcessingEngine::Extension::DoRegisterExtensions(extensionListAddr, (registerFunc)); \
}
#endif // FRAMEWORK_ALGORITHM_EXTENSION_MANAGER_UTILS_H
@@ -0,0 +1,34 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_EXTENSION_VIDEO_REFRESHRATE_PREDICTION_EXTENSION_H
#define FRAMEWORK_ALGORITHM_EXTENSION_VIDEO_REFRESHRATE_PREDICTION_EXTENSION_H
#include "video_refreshrate_prediction_base.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
struct VideoRefreshratePredictionExtension : public ExtensionBase {
VideoRefreshRatePredictionCreator creator;
};
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_EXTENSION_VIDEO_REFRESHRATE_PREDICTION_EXTENSION_H
@@ -0,0 +1,40 @@
/*
* 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.
*/
#include "utils.h"
#include <algorithm>
#include <iterator>
#include "vpe_log.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
namespace Extension {
void DoRegisterExtensions(uintptr_t addr, Utils::RegisterExtensionFunc func)
{
CHECK_AND_RETURN_LOG(func, "Register function is invalid");
auto extensionList = reinterpret_cast<ExtensionList *>(addr);
CHECK_AND_RETURN_LOG(extensionList != nullptr, "Extensionlist is nullptr");
auto extensions = func();
std::copy(extensions.begin(), extensions.end(), std::back_inserter(*extensionList));
VPE_LOGD("%{public}zu extensions loaded", extensions.size());
return;
}
} // namespace Extension
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,43 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_BASE_H
#define FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_BASE_H
#include <functional>
#include <memory>
#include "nocopyable.h"
#include "frame_info.h"
#include "vpe_context.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class MetadataGeneratorBase : public NoCopyable {
public:
virtual ~MetadataGeneratorBase() = default;
virtual VPEAlgoErrCode Init(VPEContext context) = 0;
virtual VPEAlgoErrCode Deinit() = 0;
virtual VPEAlgoErrCode SetParameter(const MetadataGeneratorParameter &parameter) = 0;
virtual VPEAlgoErrCode GetParameter(MetadataGeneratorParameter &parameter) = 0;
virtual VPEAlgoErrCode Process(const sptr<SurfaceBuffer> &input) = 0;
};
using MetadataGeneratorCreator = std::function<std::shared_ptr<MetadataGeneratorBase>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_BASE_H
@@ -0,0 +1,38 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_CAPABILITY_H
#define FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_CAPABILITY_H
#include <functional>
#include <vector>
#include "frame_info.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
struct MetadataGeneratorCapability {
ColorSpaceDescription colorspaceDesc;
std::vector<GraphicPixelFormat> pixelFormats;
uint32_t rank;
int32_t version;
};
using MetadataGeneratorCapabilitiesBuilder = std::function<std::vector<MetadataGeneratorCapability>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_CAPABILITY_H
@@ -0,0 +1,52 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_FWK_H
#define FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_FWK_H
#include <atomic>
#include <memory>
#include <optional>
#include "metadata_generator.h"
#include "metadata_generator_base.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class MetadataGeneratorFwk : public MetadataGenerator {
public:
MetadataGeneratorFwk();
MetadataGeneratorFwk(std::shared_ptr<OpenGLContext> openGlContext);
~MetadataGeneratorFwk();
VPEAlgoErrCode SetParameter(const MetadataGeneratorParameter &parameter) override;
VPEAlgoErrCode GetParameter(MetadataGeneratorParameter &parameter) const override;
VPEAlgoErrCode Process(const sptr<SurfaceBuffer> &input) override;
private:
VPEAlgoErrCode Init(const sptr<SurfaceBuffer> &input);
void OpenGLInit();
std::shared_ptr<MetadataGeneratorBase> impl_ { nullptr };
MetadataGeneratorParameter parameter_;
std::atomic<bool> initialized_ { false };
Extension::ExtensionInfo extensionInfo_;
VPEContext context;
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_FWK_H
@@ -0,0 +1,185 @@
/*
* 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.
*/
#include "metadata_generator_fwk.h"
#include "video_processing_client.h"
#include "extension_manager.h"
#include "native_buffer.h"
#include "surface_buffer.h"
#include "vpe_trace.h"
#include "vpe_log.h"
#include "EGL/egl.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
MetadataGeneratorFwk::MetadataGeneratorFwk()
{
OpenGLInit();
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Connect();
VPE_LOGI("VPE Framework connect and load SA!");
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Disconnect();
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
void MetadataGeneratorFwk::OpenGLInit()
{
context.glDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (context.glDisplay == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS) {
VPE_LOGE("MetadataGeneratorFwk Get display failed!");
}
EGLint major;
EGLint minor;
if (eglInitialize(context.glDisplay, &major, &minor) == EGL_FALSE || eglGetError() != EGL_SUCCESS) {
VPE_LOGE("MetadataGeneratorFwk eglInitialize failed!");
}
}
MetadataGeneratorFwk::MetadataGeneratorFwk(std::shared_ptr<OpenGLContext> openglContext)
{
if (openglContext != nullptr) {
context.glDisplay = openglContext->display;
}
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Connect();
VPE_LOGI("VPE Framework connect and load SA!");
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Disconnect();
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
MetadataGeneratorFwk::~MetadataGeneratorFwk()
{
if (impl_) {
impl_->Deinit();
impl_ = nullptr;
}
if (context.glDisplay != EGL_NO_DISPLAY) {
eglTerminate(context.glDisplay);
}
Extension::ExtensionManager::GetInstance().DecreaseInstance();
}
VPEAlgoErrCode MetadataGeneratorFwk::SetParameter(const MetadataGeneratorParameter &parameter)
{
parameter_ = parameter;
VPE_LOGI("MetadataGeneratorFwk SetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode MetadataGeneratorFwk::GetParameter(MetadataGeneratorParameter &parameter) const
{
parameter = parameter_;
VPE_LOGI("MetadataGeneratorFwk GetParameter Succeed");
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode MetadataGeneratorFwk::Process(const sptr<SurfaceBuffer> &input)
{
CHECK_AND_RETURN_RET_LOG(input != nullptr, VPE_ALGO_ERR_INVALID_VAL, "Input is nullptr");
CHECK_AND_RETURN_RET_LOG((input->GetUsage() & (BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_HW_RENDER)) != 0,
VPE_ALGO_ERR_INVALID_VAL, "Input surfacebuffer usage need NATIVEBUFFER_USAGE_HW_RENDER");
VPEAlgoErrCode ret = Init(input);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Init failed");
VPE_SYNC_TRACE;
ret = impl_->Process(input);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Process failed, ret: %{public}d", ret);
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode MetadataGeneratorFwk::Init(const sptr<SurfaceBuffer> &input)
{
if (initialized_) {
impl_->SetParameter(parameter_);
return VPE_ALGO_ERR_OK;
}
auto &manager = Extension::ExtensionManager::GetInstance();
VPE_SYNC_TRACE;
FrameInfo info(input);
impl_ = manager.CreateMetadataGenerator(info, extensionInfo_, parameter_.algoType);
CHECK_AND_RETURN_RET_LOG(impl_ != nullptr, VPE_ALGO_ERR_NOT_IMPLEMENTED, "Create failed");
int32_t ret = impl_->Init(context);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_NOT_IMPLEMENTED, "Init failed");
impl_->SetParameter(parameter_);
initialized_ = true;
VPE_LOGI("MetadataGeneratorFwk Init Succeed");
return VPE_ALGO_ERR_OK;
}
std::shared_ptr<MetadataGenerator> MetadataGenerator::Create()
{
auto p = std::make_shared<MetadataGeneratorFwk>();
CHECK_AND_RETURN_RET_LOG(p != nullptr, nullptr, "Create MetadataGenerator failed");
return std::static_pointer_cast<MetadataGenerator>(p);
}
std::shared_ptr<MetadataGenerator> MetadataGenerator::Create(std::shared_ptr<OpenGLContext> openglContext)
{
auto p = std::make_shared<MetadataGeneratorFwk>(openglContext);
CHECK_AND_RETURN_RET_LOG(p != nullptr, nullptr, "Create MetadataGenerator failed");
return std::static_pointer_cast<MetadataGenerator>(p);
}
int32_t MetadataGeneratorCreate(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
auto p = MetadataGenerator::Create();
CHECK_AND_RETURN_RET_LOG(p != nullptr, VPE_ALGO_ERR_INVALID_VAL, "cannot create instance");
Extension::ExtensionManager::InstanceVariableType instanceVar { p };
int32_t newId = Extension::ExtensionManager::GetInstance().NewInstanceId(instanceVar);
CHECK_AND_RETURN_RET_LOG(newId != -1, VPE_ALGO_ERR_NO_MEMORY, "cannot create more instance");
*instance = newId;
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorProcessImage(int32_t instance, OHNativeWindowBuffer* inputImage)
{
CHECK_AND_RETURN_RET_LOG((inputImage != nullptr), VPE_ALGO_ERR_INVALID_VAL,
"invalid parameters");
auto someInstance = Extension::ExtensionManager::GetInstance().GetInstance(instance);
CHECK_AND_RETURN_RET_LOG(someInstance != std::nullopt, VPE_ALGO_ERR_INVALID_VAL, "invalid instance");
VPEAlgoErrCode ret = VPE_ALGO_ERR_INVALID_VAL;
auto visitFunc = [inputImage, &ret](auto&& var) {
using VarType = std::decay_t<decltype(var)>;
if constexpr (std::is_same_v<VarType, std::shared_ptr<MetadataGenerator>>) {
OH_NativeBuffer* inputImageNativeBuffer = nullptr;
CHECK_AND_RETURN_LOG(
(OH_NativeBuffer_FromNativeWindowBuffer(inputImage, &inputImageNativeBuffer) == GSERROR_OK),
"invalid input image");
sptr<SurfaceBuffer> inputImageSurfaceBuffer(
SurfaceBuffer::NativeBufferToSurfaceBuffer(inputImageNativeBuffer));
(void)var->SetParameter({ MetadataGeneratorAlgoType::META_GEN_ALGO_TYPE_IMAGE});
ret = var->Process(inputImageSurfaceBuffer);
} else {
VPE_LOGE("instance may be miss used");
}
};
std::visit(visitFunc, *someInstance);
return ret;
}
int32_t MetadataGeneratorDestroy(int32_t* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "instance is null");
return Extension::ExtensionManager::GetInstance().RemoveInstanceReference(*instance);
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,129 @@
/*
* 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 METADATA_GENERATOR_VIDEO_IMPL_H
#define METADATA_GENERATOR_VIDEO_IMPL_H
#include <functional>
#include <queue>
#include <mutex>
#include <limits>
#include <map>
#include "metadata_generator_video.h"
#include "surface.h"
#include "sync_fence.h"
#include "metadata_generator_video_common.h"
#include "metadata_generator.h"
#include "algorithm_video_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class MetadataGeneratorVideoImpl : public MetadataGeneratorVideo {
public:
MetadataGeneratorVideoImpl();
~MetadataGeneratorVideoImpl();
int32_t Init();
int32_t Init(std::shared_ptr<OpenGLContext> openglContext);
// 北向调用接口
int32_t SetCallback(const std::shared_ptr<MetadataGeneratorVideoCallback> &callback) override;
int32_t SetOutputSurface(sptr<Surface> surface) override;
sptr<Surface> CreateInputSurface() override;
int32_t Configure() override;
int32_t Prepare() override;
int32_t Start() override;
int32_t Stop() override;
int32_t Reset() override;
int32_t Release() override;
int32_t NotifyEos() override;
int32_t ReleaseOutputBuffer(uint32_t index, bool render) override;
int32_t Flush() override;
GSError OnConsumerBufferAvailable();
GSError OnProducerBufferReleased();
private:
struct SurfaceBufferWrapper {
public:
SurfaceBufferWrapper() = default;
~SurfaceBufferWrapper() = default;
sptr<SurfaceBuffer> memory{nullptr};
MdgBufferFlag bufferFlag{MDG_BUFFER_FLAG_NONE};
sptr<SyncFence> fence{nullptr};
int64_t timestamp;
};
void InitBuffers();
bool WaitProcessing();
bool AcquireInputOutputBuffers(
std::shared_ptr<SurfaceBufferWrapper> &inputBuffer, std::shared_ptr<SurfaceBufferWrapper> &outputBuffer);
void DoTask();
void OnTriggered();
void Process(std::shared_ptr<SurfaceBufferWrapper> inputBuffer, std::shared_ptr<SurfaceBufferWrapper> outputBuffer);
int32_t AttachToNewSurface(sptr<Surface> newSurface);
int32_t SetOutputSurfaceConfig(sptr<Surface> surface);
int32_t SetOutputSurfaceRunning(sptr<Surface> newSurface);
int32_t GetReleaseOutBuffer();
std::atomic<VPEAlgoState> state_{VPEAlgoState::UNINITIALIZED};
std::shared_ptr<MetadataGeneratorVideoCallback> cb_{nullptr};
std::shared_ptr<MetadataGenerator> csc_{nullptr};
std::mutex mutex_;
bool getUsage_{false};
std::atomic<bool> initBuffer_{false};
// task相关
std::mutex mtxTaskDone_;
std::condition_variable cvTaskDone_;
std::shared_ptr<std::thread> taskThread_{nullptr};
std::condition_variable cvTaskStart_;
std::mutex mtxTaskStart_;
std::atomic<bool> isRunning_{false};
std::atomic<bool> isProcessing_{false};
std::atomic<bool> isEos_{false};
// surface相关
std::queue<std::shared_ptr<SurfaceBufferWrapper>> outputBufferAvilQue_;
std::queue<std::shared_ptr<SurfaceBufferWrapper>> inputBufferAvilQue_;
std::queue<std::shared_ptr<SurfaceBufferWrapper>> renderBufferAvilQue_;
using RenderBufferAvilMapType = std::map<uint64_t, std::shared_ptr<SurfaceBufferWrapper>>;
RenderBufferAvilMapType renderBufferAvilMap_;
RenderBufferAvilMapType renderBufferMapBak_;
RenderBufferAvilMapType outputBufferAvilQueBak_;
std::mutex onBqMutex_; // inputsruface buffer
std::mutex renderQueMutex_; // outputsruface buffer
std::mutex surfaceChangeMutex_;
std::mutex surfaceChangeMutex2_;
sptr<Surface> inputSurface_{nullptr};
sptr<Surface> outputSurface_{nullptr};
static constexpr size_t MAX_BUFFER_CNT{5};
uint32_t outBufferCnt_{MAX_BUFFER_CNT};
uint32_t inBufferCnt_{MAX_BUFFER_CNT};
static constexpr size_t MAX_SURFACE_SEQUENCE{std::numeric_limits<uint32_t>::max()};
uint32_t lastSurfaceSequence_{MAX_SURFACE_SEQUENCE};
BufferRequestConfig requestCfg_{};
BufferFlushConfig flushCfg_{};
};
class MetadataGeneratorBufferConsumerListener : public OHOS::IBufferConsumerListener {
public:
explicit MetadataGeneratorBufferConsumerListener(MetadataGeneratorVideoImpl *process) : process_(process) {}
void OnBufferAvailable() override;
private:
MetadataGeneratorVideoImpl *process_;
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // METADATA_GENERATOR_VIDEO_IMPL_H
@@ -0,0 +1,636 @@
/*
* 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 "metadata_generator_video_impl.h"
#include <cstring>
#include <limits>
#include <memory>
#include <algorithm>
#include "vpe_log.h"
#include "algorithm_errors.h"
#include "algorithm_common.h"
#include "vpe_trace.h"
#include "algorithm_utils.h"
#include "securec.h"
#include "extension_manager.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
std::shared_ptr<MetadataGeneratorVideo> MetadataGeneratorVideo::Create()
{
std::shared_ptr<MetadataGeneratorVideoImpl> impl = std::make_shared<MetadataGeneratorVideoImpl>();
int32_t ret = impl->Init();
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, nullptr, "failed to init MetadataGeneratorVideoImpl");
return impl;
}
std::shared_ptr<MetadataGeneratorVideo> MetadataGeneratorVideo::Create(std::shared_ptr<OpenGLContext> openglContext)
{
std::shared_ptr<MetadataGeneratorVideoImpl> impl = std::make_shared<MetadataGeneratorVideoImpl>();
int32_t ret = impl->Init(openglContext);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, nullptr, "failed to init MetadataGeneratorVideoImpl");
return impl;
}
MetadataGeneratorVideoImpl::MetadataGeneratorVideoImpl()
{
requestCfg_.timeout = 0;
requestCfg_.strideAlignment = 32; // 32 内存对齐
requestCfg_.usage = 0;
requestCfg_.format = 0;
requestCfg_.width = 0;
requestCfg_.height = 0;
flushCfg_.timestamp = 0;
flushCfg_.damage.x = 0;
flushCfg_.damage.y = 0;
flushCfg_.damage.w = 0;
flushCfg_.damage.h = 0;
}
MetadataGeneratorVideoImpl::~MetadataGeneratorVideoImpl()
{
Release();
}
int32_t MetadataGeneratorVideoImpl::Init()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::UNINITIALIZED, VPE_ALGO_ERR_INVALID_STATE,
"Init failed: not in UNINITIALIZED state");
csc_ = MetadataGenerator::Create();
CHECK_AND_RETURN_RET_LOG(csc_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "MetadataGenerator Create failed");
isRunning_.store(true);
taskThread_ = std::make_shared<std::thread>(&MetadataGeneratorVideoImpl::OnTriggered, this);
CHECK_AND_RETURN_RET_LOG(taskThread_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "Fatal: No memory");
state_ = VPEAlgoState::INITIALIZED;
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::Init(std::shared_ptr<OpenGLContext> openglContext)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::UNINITIALIZED, VPE_ALGO_ERR_INVALID_STATE,
"Init failed: not in UNINITIALIZED state");
csc_ = MetadataGenerator::Create(openglContext);
CHECK_AND_RETURN_RET_LOG(csc_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "MetadataGenerator Create failed");
isRunning_.store(true);
taskThread_ = std::make_shared<std::thread>(&MetadataGeneratorVideoImpl::OnTriggered, this);
CHECK_AND_RETURN_RET_LOG(taskThread_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "Fatal: No memory");
state_ = VPEAlgoState::INITIALIZED;
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::SetCallback(const std::shared_ptr<MetadataGeneratorVideoCallback> &callback)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(callback != nullptr, VPE_ALGO_ERR_INVALID_VAL, "Set callback failed: callback is NULL");
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING,
VPE_ALGO_ERR_INVALID_STATE, "SetCallback failed: not in INITIALIZED or CONFIGURING state");
cb_ = callback;
state_ = VPEAlgoState::CONFIGURING;
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::AttachToNewSurface(sptr<Surface> newSurface)
{
std::lock_guard<std::mutex> lockrender(renderQueMutex_);
for (auto it = outputBufferAvilQueBak_.begin(); it != outputBufferAvilQueBak_.end(); ++it) {
auto buffer = it->second;
GSError err = newSurface->AttachBufferToQueue(buffer->memory);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "outputbuffer AttachToNewSurface fail");
}
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::GetReleaseOutBuffer()
{
std::lock_guard<std::mutex> mapLock(renderQueMutex_);
for (RenderBufferAvilMapType::iterator it = renderBufferMapBak_.begin(); it != renderBufferMapBak_.end(); ++it) {
outputBufferAvilQue_.push(it->second);
}
renderBufferMapBak_.clear();
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::SetOutputSurfaceConfig(sptr<Surface> surface)
{
GSError err = surface->RegisterReleaseListener([this](sptr<SurfaceBuffer> &buffer) {
(void)buffer;
return OnProducerBufferReleased();
});
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "RegisterReleaseListener fail");
surface->SetQueueSize(outBufferCnt_);
outputSurface_ = surface;
state_ = VPEAlgoState::CONFIGURING;
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::SetOutputSurfaceRunning(sptr<Surface> newSurface)
{
std::lock_guard<std::mutex> lockSurface(surfaceChangeMutex_);
std::lock_guard<std::mutex> lockSurface2(surfaceChangeMutex2_);
uint64_t oldId = outputSurface_->GetUniqueId();
uint64_t newId = newSurface->GetUniqueId();
if (oldId == newId) {
VPE_LOGD("SetOutputSurfaceRunning same surface");
return VPE_ALGO_ERR_OK;
}
outputSurface_->UnRegisterReleaseListener();
outputSurface_->CleanCache(true);
GSError err = newSurface->RegisterReleaseListener([this](sptr<SurfaceBuffer> &buffer) {
(void)buffer;
return OnProducerBufferReleased();
});
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "RegisterReleaseListener fail");
newSurface->SetQueueSize(outBufferCnt_);
newSurface->Connect();
newSurface->CleanCache();
GetReleaseOutBuffer();
int32_t ret = AttachToNewSurface(newSurface);
if (ret != VPE_ALGO_ERR_OK) {
return ret;
}
GraphicTransformType inTransform;
ScalingMode inScaleMode;
inTransform = inputSurface_->GetTransform();
outputSurface_ = newSurface;
err = outputSurface_->SetTransform(inTransform);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "SetTransform fail");
if (lastSurfaceSequence_ != MAX_SURFACE_SEQUENCE) {
err = inputSurface_->GetScalingMode(lastSurfaceSequence_, inScaleMode);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "GetScalingMode fail");
err = outputSurface_->SetScalingMode(inScaleMode);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "SetScalingMode fail");
}
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::SetOutputSurface(sptr<Surface> surface)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(surface != nullptr, VPE_ALGO_ERR_INVALID_VAL, "surface is nullptr");
CHECK_AND_RETURN_RET_LOG(surface->IsConsumer() == false, VPE_ALGO_ERR_INVALID_VAL, "surface is not producer");
if (state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING) {
int32_t ret = SetOutputSurfaceConfig(surface);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_INVALID_STATE, "SetOutputSurface config fail");
} else if (state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS || state_ == VPEAlgoState::FLUSHED) {
int32_t ret = SetOutputSurfaceRunning(surface);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, VPE_ALGO_ERR_INVALID_STATE, "SetOutputSurface Running fail");
} else {
CHECK_AND_RETURN_RET_LOG(false, VPE_ALGO_ERR_INVALID_STATE, "surface state not support SetOutputSurface");
}
return VPE_ALGO_ERR_OK;
}
sptr<Surface> MetadataGeneratorVideoImpl::CreateInputSurface()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING, nullptr,
"CreateInputSurface failed: not in INITIALIZED or CONFIGURING state");
CHECK_AND_RETURN_RET_LOG(inputSurface_ == nullptr, nullptr, "inputSurface already exists");
inputSurface_ = Surface::CreateSurfaceAsConsumer("ConvertInputSurface");
CHECK_AND_RETURN_RET_LOG(inputSurface_ != nullptr, nullptr, "CreateSurfaceAsConsumer fail");
sptr<IBufferConsumerListener> listener = new MetadataGeneratorBufferConsumerListener(this);
GSError err = inputSurface_->RegisterConsumerListener(listener);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, nullptr, "RegisterConsumerListener fail");
sptr<IBufferProducer> producer = inputSurface_->GetProducer();
sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(producer);
CHECK_AND_RETURN_RET_LOG(producerSurface != nullptr, nullptr, "CreateSurfaceAsProducer fail");
producerSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_HW_RENDER |
BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE);
inputSurface_->SetQueueSize(inBufferCnt_);
state_ = VPEAlgoState::CONFIGURING;
return producerSurface;
}
int32_t MetadataGeneratorVideoImpl::Configure()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::INITIALIZED || state_ == VPEAlgoState::CONFIGURING || state_ ==
VPEAlgoState::STOPPED, VPE_ALGO_ERR_INVALID_STATE, "Configure failed: not in INITIALIZED or CONFIGURING state");
MetadataGeneratorParameter param;
param.algoType = MetadataGeneratorAlgoType::META_GEN_ALGO_TYPE_VIDEO;
int32_t ret = csc_->SetParameter(param);
state_ = (ret == VPE_ALGO_ERR_OK ? VPEAlgoState::CONFIGURING : VPEAlgoState::ERROR);
return ret;
}
int32_t MetadataGeneratorVideoImpl::Prepare()
{
std::lock_guard<std::mutex> lock(mutex_);
if (state_ == VPEAlgoState::STOPPED) {
state_ = VPEAlgoState::CONFIGURED;
return VPE_ALGO_ERR_OK;
}
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::CONFIGURING, VPE_ALGO_ERR_INVALID_STATE,
"Prepare failed: not in CONFIGURING state");
CHECK_AND_RETURN_RET_LOG(cb_ != nullptr && inputSurface_ != nullptr && outputSurface_ != nullptr,
VPE_ALGO_ERR_INVALID_OPERATION, "Prepare faled: inputSurface or outputSurface or callback is null");
state_ = VPEAlgoState::CONFIGURED;
return VPE_ALGO_ERR_OK;
}
void MetadataGeneratorVideoImpl::InitBuffers()
{
flushCfg_.damage.x = 0;
flushCfg_.damage.y = 0;
flushCfg_.damage.w = requestCfg_.width;
flushCfg_.damage.h = requestCfg_.height;
for (uint32_t i = 0; i < outBufferCnt_; ++i) {
std::shared_ptr<SurfaceBufferWrapper> buffer = std::make_shared<SurfaceBufferWrapper>();
GSError err = outputSurface_->RequestBuffer(buffer->memory, buffer->fence, requestCfg_);
if (err != GSERROR_OK || buffer->memory == nullptr) {
VPE_LOGW("RequestBuffer %{public}u failed, GSError=%{public}d", i, err);
continue;
}
outputBufferAvilQue_.push(buffer);
outputBufferAvilQueBak_.insert(std::make_pair(buffer->memory->GetSeqNum(), buffer));
}
}
int32_t MetadataGeneratorVideoImpl::Start()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(
(state_ == VPEAlgoState::CONFIGURED || state_ == VPEAlgoState::STOPPED || state_ == VPEAlgoState::FLUSHED),
VPE_ALGO_ERR_INVALID_STATE,
"Start failed: not in CONFIGURED or STOPPED state");
if (isEos_.load()) {
state_ = VPEAlgoState::EOS;
} else {
state_ = VPEAlgoState::RUNNING;
}
cb_->OnState(static_cast<int32_t>(state_.load()));
cvTaskStart_.notify_all();
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::Stop()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(
state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS || state_ == VPEAlgoState::FLUSHED,
VPE_ALGO_ERR_INVALID_STATE,
"Stop failed: not in RUNNING or EOS state");
state_ = VPEAlgoState::STOPPED;
if (!isProcessing_) {
cb_->OnState(static_cast<int32_t>(state_.load()));
}
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::Reset()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(
state_ != VPEAlgoState::UNINITIALIZED, VPE_ALGO_ERR_INVALID_STATE, "Start failed: not in right state");
std::unique_lock<std::mutex> lockTask(mtxTaskDone_);
state_ = VPEAlgoState::INITIALIZED;
cvTaskDone_.wait(lockTask, [this]() { return isProcessing_.load() == false; });
csc_ = MetadataGenerator::Create();
CHECK_AND_RETURN_RET_LOG(csc_ != nullptr, VPE_ALGO_ERR_UNKNOWN, "ColorSpaceConverter Create failed");
isEos_.store(false);
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::Release()
{
std::lock_guard<std::mutex> lock(mutex_);
{
std::unique_lock<std::mutex> lockTask(mtxTaskDone_);
state_ = VPEAlgoState::UNINITIALIZED;
cvTaskDone_.wait(lockTask, [this]() { return isProcessing_.load() == false; });
inputSurface_ = nullptr;
std::unique_lock<std::mutex> lockSurface(surfaceChangeMutex_);
std::unique_lock<std::mutex> lockSurface2(surfaceChangeMutex2_);
if (outputSurface_ != nullptr) {
outputSurface_->UnRegisterReleaseListener();
outputSurface_->CleanCache(true);
outputSurface_ = nullptr;
}
lockSurface2.unlock();
lockSurface.unlock();
cb_ = nullptr;
csc_ = nullptr;
isRunning_.store(false);
}
if (taskThread_ != nullptr && taskThread_->joinable()) {
cvTaskStart_.notify_all();
taskThread_->join();
}
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::Flush()
{
std::lock_guard<std::mutex> lock(mutex_);
{
std::unique_lock<std::mutex> lockTask(mtxTaskDone_);
cvTaskDone_.wait(lockTask, [this]() { return isProcessing_.load() == false; });
}
{
std::unique_lock<std::mutex> lockInQue(onBqMutex_);
std::queue<std::shared_ptr<SurfaceBufferWrapper>> tempQueue;
inputBufferAvilQue_.swap(tempQueue);
for (; tempQueue.size() != 0;) {
auto buffer = tempQueue.front();
tempQueue.pop();
CHECK_AND_RETURN_RET_LOG(buffer && buffer->memory != nullptr, VPE_ALGO_ERR_UNKNOWN, "Invalid memory");
GSError err = inputSurface_->ReleaseBuffer(buffer->memory, -1);
CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, VPE_ALGO_ERR_UNKNOWN, "Release buffer failed");
}
}
std::lock_guard<std::mutex> mapLock(renderQueMutex_);
for (auto &[id, buffer] : renderBufferAvilMap_) {
VPE_LOGD("Reclaim buffer %{public}" PRIu64, id);
outputBufferAvilQue_.push(buffer);
}
renderBufferAvilMap_.clear();
state_ = VPEAlgoState::FLUSHED;
return VPE_ALGO_ERR_OK;
}
void MetadataGeneratorVideoImpl::Process(std::shared_ptr<SurfaceBufferWrapper> inputBuffer,
std::shared_ptr<SurfaceBufferWrapper> outputBuffer)
{
VPETrace videoTrace("MetadataGeneratorVideoImpl::Process");
int32_t ret = VPE_ALGO_ERR_EXTENSION_PROCESS_FAILED;
outputBuffer->timestamp = inputBuffer->timestamp;
sptr<SurfaceBuffer> surfaceInputBuffer = inputBuffer->memory;
sptr<SurfaceBuffer> surfaceOutputBuffer = outputBuffer->memory;
bool copyRet = AlgorithmUtils::CopySurfaceBufferToSurfaceBuffer(surfaceInputBuffer, surfaceOutputBuffer);
if (!copyRet) {
requestCfg_.width = surfaceInputBuffer->GetWidth();
requestCfg_.height = surfaceInputBuffer->GetHeight();
requestCfg_.format = surfaceInputBuffer->GetFormat();
surfaceOutputBuffer->EraseMetadataKey(ATTRKEY_COLORSPACE_INFO);
surfaceOutputBuffer->EraseMetadataKey(ATTRKEY_HDR_METADATA_TYPE);
if (surfaceOutputBuffer->Alloc(requestCfg_) == GSERROR_OK) {
copyRet = AlgorithmUtils::CopySurfaceBufferToSurfaceBuffer(surfaceInputBuffer, surfaceOutputBuffer);
}
}
if (copyRet) {
VPETrace cscTrace("MetadataGeneratorVideoImpl::csc_->Process");
ret = csc_->Process(surfaceOutputBuffer);
}
if (ret != 0 && cb_) {
cb_->OnError(ret);
}
inputSurface_->ReleaseBuffer(surfaceInputBuffer, -1);
if (!ret) {
std::unique_lock<std::mutex> lockOnBq(renderQueMutex_);
renderBufferAvilMap_.emplace(outputBuffer->memory->GetSeqNum(), outputBuffer);
} else {
std::lock_guard<std::mutex> renderLock(renderQueMutex_);
outputBufferAvilQue_.push(outputBuffer);
}
if (!ret && cb_) {
cb_->OnOutputBufferAvailable(surfaceOutputBuffer->GetSeqNum(), outputBuffer->bufferFlag);
}
}
bool MetadataGeneratorVideoImpl::WaitProcessing()
{
if (!isRunning_.load()) {
return false;
}
{
std::unique_lock<std::mutex> lock(mtxTaskStart_);
cvTaskStart_.wait(lock, [this]() {
std::lock_guard<std::mutex> inQueueLock(onBqMutex_);
std::lock_guard<std::mutex> outQueueLock(renderQueMutex_);
if (initBuffer_.load()) {
InitBuffers();
initBuffer_.store(false);
}
return ((inputBufferAvilQue_.size() > 0 && outputBufferAvilQue_.size() > 0) || !isRunning_.load());
});
}
return true;
}
bool MetadataGeneratorVideoImpl::AcquireInputOutputBuffers(std::shared_ptr<SurfaceBufferWrapper>& inputBuffer,
std::shared_ptr<SurfaceBufferWrapper>& outputBuffer)
{
std::lock_guard<std::mutex> lockOnBq(onBqMutex_);
std::lock_guard<std::mutex> mapLock(renderQueMutex_);
if (inputBufferAvilQue_.size() == 0 || outputBufferAvilQue_.size() == 0) {
if (state_ == VPEAlgoState::STOPPED) {
cb_->OnState(static_cast<int32_t>(state_.load()));
}
return false;
}
inputBuffer = inputBufferAvilQue_.front();
outputBuffer = outputBufferAvilQue_.front();
inputBufferAvilQue_.pop();
outputBufferAvilQue_.pop();
return inputBuffer && outputBuffer;
}
void MetadataGeneratorVideoImpl::DoTask()
{
std::shared_ptr<SurfaceBufferWrapper> inputBuffer = nullptr;
std::shared_ptr<SurfaceBufferWrapper> outputBuffer = nullptr;
while (true) {
std::lock_guard<std::mutex> lockTask(mtxTaskDone_);
if (!isRunning_.load()) {
return;
}
isProcessing_.store(true);
if (!AcquireInputOutputBuffers(inputBuffer, outputBuffer)) {
break;
}
if (inputBuffer->bufferFlag == MDG_BUFFER_FLAG_EOS) {
{
std::unique_lock<std::mutex> lockOnBq(renderQueMutex_);
renderBufferAvilMap_.emplace(outputBuffer->memory->GetSeqNum(), outputBuffer);
}
if (cb_) {
cb_->OnOutputBufferAvailable(outputBuffer->memory->GetSeqNum(), MDG_BUFFER_FLAG_EOS);
}
break;
}
Process(inputBuffer, outputBuffer);
}
isProcessing_.store(false);
cvTaskDone_.notify_all();
}
void MetadataGeneratorVideoImpl::OnTriggered()
{
while (true) {
if (!WaitProcessing()) {
break;
}
DoTask();
}
}
int32_t MetadataGeneratorVideoImpl::ReleaseOutputBuffer(uint32_t index, bool render)
{
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS, VPE_ALGO_ERR_INVALID_STATE,
"ReleaseOutputBuffer failed: not in RUNNING or EOS state");
std::unique_lock<std::mutex> lockRenderQue(renderQueMutex_);
auto search = renderBufferAvilMap_.find(index);
if (search == renderBufferAvilMap_.end()) {
VPE_LOGE("ReleaseOutputBuffer invalid index %{public}d ", index);
return VPE_ALGO_ERR_INVALID_PARAM;
}
auto buffer = search->second;
renderBufferAvilMap_.erase(search);
lockRenderQue.unlock();
if (render) {
flushCfg_.timestamp = buffer->timestamp;
{
std::lock_guard<std::mutex> lockSurface(surfaceChangeMutex_);
CHECK_AND_RETURN_RET_LOG(outputSurface_ != nullptr, GSERROR_OK, "outputSurface_ is nullptr");
auto ret = outputSurface_->FlushBuffer(buffer->memory, -1, flushCfg_);
if (ret != 0) {
VPE_LOGE("ReleaseOutputBuffer flushbuffer err %{public}d ", (int)ret);
return VPE_ALGO_ERR_UNKNOWN;
}
}
std::lock_guard<std::mutex> renderLock(renderQueMutex_);
renderBufferMapBak_.emplace(buffer->memory->GetSeqNum(), buffer);
} else {
std::lock_guard<std::mutex> renderLock(renderQueMutex_);
outputBufferAvilQue_.push(buffer);
}
return VPE_ALGO_ERR_OK;
}
int32_t MetadataGeneratorVideoImpl::NotifyEos()
{
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard<std::mutex> lockOnBq(onBqMutex_);
CHECK_AND_RETURN_RET_LOG(state_ == VPEAlgoState::RUNNING, VPE_ALGO_ERR_INVALID_STATE,
"NotifyEos failed: not in RUNNING state");
state_ = VPEAlgoState::EOS;
isEos_.store(true);
std::shared_ptr<SurfaceBufferWrapper> buf = std::make_shared<SurfaceBufferWrapper>();
buf->bufferFlag = MDG_BUFFER_FLAG_EOS;
inputBufferAvilQue_.push(buf);
cvTaskStart_.notify_all();
return VPE_ALGO_ERR_OK;
}
GSError MetadataGeneratorVideoImpl::OnProducerBufferReleased()
{
{
std::unique_lock<std::mutex> lockSurface(surfaceChangeMutex2_);
std::lock_guard<std::mutex> outQueLock(renderQueMutex_);
std::shared_ptr<SurfaceBufferWrapper> buf = std::make_shared<SurfaceBufferWrapper>();
CHECK_AND_RETURN_RET_LOG(outputSurface_ != nullptr, GSERROR_OK, "outputSurface_ is nullptr");
if (renderBufferMapBak_.empty()) {
return GSERROR_OK;
}
GSError err = outputSurface_->RequestBuffer(buf->memory, buf->fence, requestCfg_);
if (err != GSERROR_OK || buf->memory == nullptr) {
VPE_LOGE("RequestBuffer failed, GSError=%{public}d", err);
return err;
}
lockSurface.unlock();
outputBufferAvilQue_.push(buf);
auto bufSeqNum = buf->memory->GetSeqNum();
lastSurfaceSequence_ = bufSeqNum;
renderBufferMapBak_.erase(bufSeqNum);
auto it = outputBufferAvilQueBak_.find(bufSeqNum);
if (it == outputBufferAvilQueBak_.end()) {
outputBufferAvilQueBak_.insert(std::make_pair(bufSeqNum, buf));
auto firstSeqNum = renderBufferMapBak_.begin();
if (firstSeqNum != renderBufferMapBak_.end()) {
outputBufferAvilQueBak_.erase(firstSeqNum->first);
renderBufferMapBak_.erase(firstSeqNum->first);
}
}
}
if (state_ == VPEAlgoState::RUNNING || state_ == VPEAlgoState::EOS) {
cvTaskStart_.notify_all();
}
return GSERROR_OK;
}
GSError MetadataGeneratorVideoImpl::OnConsumerBufferAvailable()
{
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard<std::mutex> lockInQue(onBqMutex_);
CHECK_AND_RETURN_RET_LOG(inputSurface_ != nullptr, GSERROR_OK, "inputSurface is nullptr");
CHECK_AND_RETURN_RET_LOG(state_ != VPEAlgoState::STOPPED, GSERROR_OK, "state change to stop");
std::shared_ptr<SurfaceBufferWrapper> buffer = std::make_shared<SurfaceBufferWrapper>();
OHOS::Rect damage;
GSError err = inputSurface_->AcquireBuffer(buffer->memory, buffer->fence, buffer->timestamp, damage);
if (err != GSERROR_OK || buffer->memory == nullptr) {
VPE_LOGW("AcquireBuffer failed, GSError=%{public}d", err);
return err;
}
inputBufferAvilQue_.push(buffer);
if (!getUsage_) {
requestCfg_.usage = (buffer->memory->GetUsage() | requestCfg_.usage);
getUsage_ = true;
requestCfg_.width = buffer->memory->GetWidth();
requestCfg_.height = buffer->memory->GetHeight();
requestCfg_.format = buffer->memory->GetFormat();
initBuffer_.store(true);
}
if (state_ == VPEAlgoState::RUNNING) {
cvTaskStart_.notify_all();
}
return GSERROR_OK;
}
void MetadataGeneratorBufferConsumerListener::OnBufferAvailable()
{
if (process_ != nullptr) {
process_->OnConsumerBufferAvailable();
}
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,40 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_VIDEO_REFRESHRATE_PREDICTION_BASE_H
#define FRAMEWORK_ALGORITHM_VIDEO_REFRESHRATE_PREDICTION_BASE_H
#include <functional>
#include <memory>
#include "nocopyable.h"
#include "frame_info.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class VideoRefreshRatePredictionBase : public NoCopyable {
public:
virtual ~VideoRefreshRatePredictionBase() = default;
virtual VPEAlgoErrCode CheckVRRSupport(std::string processName) = 0;
virtual VPEAlgoErrCode Process(const sptr<SurfaceBuffer> &input, int videoFps, int codecType) = 0;
};
using VideoRefreshRatePredictionCreator = std::function<std::shared_ptr<VideoRefreshRatePredictionBase>()>;
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_VIDEO_REFRESHRATE_PREDICTION_BASE_H
@@ -0,0 +1,45 @@
/*
* 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.
*/
#ifndef FRAMEWORK_ALGORITHM_VIDEO_REFRESHRATE_PREDICTION_FWK_H
#define FRAMEWORK_ALGORITHM_VIDEO_REFRESHRATE_PREDICTION_FWK_H
#include <atomic>
#include <memory>
#include <optional>
#include "video_refreshrate_prediction.h"
#include "video_refreshrate_prediction_base.h"
#include "extension_base.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class VideoRefreshRatePredictionFwk : public VideoRefreshRatePrediction {
public:
VideoRefreshRatePredictionFwk();
~VideoRefreshRatePredictionFwk();
VPEAlgoErrCode CheckVRRSupport(std::string processName) override;
VPEAlgoErrCode Process(const sptr<SurfaceBuffer> &input, int videoFps, int codecType) override;
private:
VPEAlgoErrCode Init();
std::shared_ptr<VideoRefreshRatePredictionBase> impl_ { nullptr };
std::atomic<bool> initialized_ { false };
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // FRAMEWORK_ALGORITHM_METADATA_GENERATOR_METADATA_GENERATOR_FWK_H
@@ -0,0 +1,114 @@
/*
* 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.
*/
#include "video_refreshrate_prediction_fwk.h"
#include "extension_manager.h"
#include "surface_buffer.h"
#include "vpe_trace.h"
#include "vpe_log.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
VideoRefreshRatePredictionFwk::VideoRefreshRatePredictionFwk()
{
Extension::ExtensionManager::GetInstance().IncreaseInstance();
}
VideoRefreshRatePredictionFwk::~VideoRefreshRatePredictionFwk()
{
impl_ = nullptr;
Extension::ExtensionManager::GetInstance().DecreaseInstance();
}
VPEAlgoErrCode VideoRefreshRatePredictionFwk::Process(const sptr<SurfaceBuffer> &input, int videoFps, int codecType)
{
VPEAlgoErrCode ret = Init();
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "VRR Init failed");
ret = impl_->Process(input, videoFps, codecType);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "Process failed, ret: %{public}d", ret);
return VPE_ALGO_ERR_OK;
}
VPEAlgoErrCode VideoRefreshRatePredictionFwk::CheckVRRSupport(std::string processName)
{
VPEAlgoErrCode ret = Init();
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ret, "VRR Init failed");
ret = impl_->CheckVRRSupport(processName);
return ret;
}
VPEAlgoErrCode VideoRefreshRatePredictionFwk::Init()
{
if (initialized_) {
return VPE_ALGO_ERR_OK;
}
auto& manager = Extension::ExtensionManager::GetInstance();
VPE_SYNC_TRACE;
impl_ = manager.CreateVideoRefreshRatePredictor();
CHECK_AND_RETURN_RET_LOG(impl_ != nullptr, VPE_ALGO_ERR_NOT_IMPLEMENTED, "Create impl failed");
initialized_ = true;
VPE_LOGI("create VideoRefreshRatePredictionFwk Successed");
return VPE_ALGO_ERR_OK;
}
std::shared_ptr<VideoRefreshRatePrediction> VideoRefreshRatePrediction::Create()
{
auto p = std::make_shared<VideoRefreshRatePredictionFwk>();
CHECK_AND_RETURN_RET_LOG(p != nullptr, nullptr, "Create VideoRefreshRatePrediction failed");
return std::static_pointer_cast<VideoRefreshRatePrediction>(p);
}
struct VideoRefreshRatePredictionHandleImpl {
std::shared_ptr<VideoRefreshRatePredictionFwk> obj;
};
VideoRefreshRatePredictionHandle *VideoRefreshRatePredictionCreate()
{
auto impl = std::make_shared<VideoRefreshRatePredictionFwk>();
CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr, "Create VideoRefreshRatePrediction failed");
auto handle = new VideoRefreshRatePredictionHandleImpl;
handle->obj = impl;
return static_cast<VideoRefreshRatePredictionHandle *>(handle);
}
void VideoRefreshRatePredictionDestroy(VideoRefreshRatePredictionHandle *handle)
{
VPE_LOGD("VideoRefreshRatePredictionFwk Destroy");
if (handle != nullptr) {
auto p = static_cast<VideoRefreshRatePredictionHandleImpl *>(handle);
delete p;
}
}
int32_t VideoRefreshRatePredictionCheckSupport(VideoRefreshRatePredictionHandle *handle, const char *processName)
{
auto p = static_cast<VideoRefreshRatePredictionHandleImpl *>(handle);
int32_t ret = p->obj->CheckVRRSupport(processName);
return ret;
}
void VideoRefreshRatePredictionProcess(VideoRefreshRatePredictionHandle *handle,
OH_NativeBuffer* inputImageNativeBuffer, int videoFps, int codecType)
{
auto p = static_cast<VideoRefreshRatePredictionHandleImpl *>(handle);
sptr<SurfaceBuffer> inputImageSurfaceBuffer(SurfaceBuffer::NativeBufferToSurfaceBuffer(inputImageNativeBuffer));
p->obj->Process(inputImageSurfaceBuffer, videoFps, codecType);
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
+16
View File
@@ -0,0 +1,16 @@
# 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("//foundation/multimedia/video_processing_engine/config.gni")
VIDEO_PROCESSING_ENGINE_CAPI_DIR = "//foundation/multimedia/media_foundation/video_processing_engine"
@@ -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.
*/
#include "colorspace_converter_image_native.h"
#include <unordered_map>
#include "image_processing_capi_impl.h"
#include "detail_enhancer_common.h"
#include "detail_enhancer_image_fwk.h"
#include "image_processing_utils.h"
#include "surface_buffer.h"
#include "surface_buffer_impl.h"
#include "surface_type.h"
#include "vpe_log.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
ImageProcessing_ErrorCode ColorspaceConverterImageNative::InitializeInner()
{
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(!isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already init!");
colorspaceConverter_ = ColorSpaceConverter::Create(nullptr, opengclContext_);
CHECK_AND_RETURN_RET_LOG(colorspaceConverter_ != nullptr, IMAGE_PROCESSING_ERROR_CREATE_FAILED,
"Create detail colorspaceConverter failed!");
isInitialized_ = true;
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::DeinitializeInner()
{
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already deinit!");
colorspaceConverter_ = nullptr;
isInitialized_ = false;
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::SetParameter(const OHOS::Media::Format& parameter)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::GetParameter(OHOS::Media::Format& parameter)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::Process(
const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
CM_ColorSpaceInfo GetColorSpaceInfo(const uint32_t colorSpaceType)
{
CM_ColorSpaceInfo info;
info.primaries = static_cast<CM_ColorPrimaries>((colorSpaceType & COLORPRIMARIES_MASK) >> COLORPRIMARIES_OFFSET);
info.transfunc = static_cast<CM_TransFunc>((colorSpaceType & TRANSFUNC_MASK) >> TRANSFUNC_OFFSET);
info.matrix = static_cast<CM_Matrix>((colorSpaceType & MATRIX_MASK) >> MATRIX_OFFSET);
info.range = static_cast<CM_Range>((colorSpaceType & RANGE_MASK) >> RANGE_OFFSET);
return info;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::ConvertColorSpace(
const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
ColorSpaceConverterParameter parameter;
parameter.renderIntent = RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC;
auto ret = ImageProcessingUtils::InnerErrorToCAPI(colorspaceConverter_->SetParameter(parameter));
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "cSetParameter failed!");
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED,
"ConvertColorSpace image is not initialized!");
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "sourceImage or destinationImage is null!");
sptr<SurfaceBuffer> sourceImageSurfaceBuffer = nullptr;
sptr<SurfaceBuffer> destinationImageSurfaceBuffer = nullptr;
ret = ConvertPixelmapToSurfaceBuffer(sourceImage, sourceImageSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ConvertPixelmapToSurfaceBuffer(destinationImage, destinationImageSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ImageProcessingUtils::InnerErrorToCAPI(
colorspaceConverter_->Process(sourceImageSurfaceBuffer, destinationImageSurfaceBuffer));
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "process failed!");
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::Compose(
const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
const std::shared_ptr<OHOS::Media::PixelMap>& sourceGainmap,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
ColorSpaceConverterParameter parameter;
parameter.renderIntent = RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC;
auto ret = ImageProcessingUtils::InnerErrorToCAPI(colorspaceConverter_->SetParameter(parameter));
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "cSetParameter failed!");
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED,
"Compose image is not initialized!");
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr && sourceGainmap != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "sourceImage or destinationImage is null!");
sptr<SurfaceBuffer> sourceImageSurfaceBuffer = nullptr;
sptr<SurfaceBuffer> sourceGainmapSurfaceBuffer = nullptr;
sptr<SurfaceBuffer> destinationImageSurfaceBuffer = nullptr;
ret = ConvertPixelmapToSurfaceBuffer(sourceImage, sourceImageSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ConvertPixelmapToSurfaceBuffer(sourceGainmap, sourceGainmapSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ConvertPixelmapToSurfaceBuffer(destinationImage, destinationImageSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ImageProcessingUtils::InnerErrorToCAPI(
colorspaceConverter_->ComposeImage(sourceImageSurfaceBuffer, sourceGainmapSurfaceBuffer,
destinationImageSurfaceBuffer, false));
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "process failed!");
return ret;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::Decompose(
const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationGainmap)
{
ColorSpaceConverterParameter parameter;
parameter.renderIntent = RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC;
auto ret = ImageProcessingUtils::InnerErrorToCAPI(colorspaceConverter_->SetParameter(parameter));
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "cSetParameter failed!");
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED,
"Decompose image is not initialized!");
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr && destinationGainmap != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "sourceImage or destinationImage is null!");
sptr<SurfaceBuffer> sourceImageSurfaceBuffer = nullptr;
sptr<SurfaceBuffer> destinationImageSurfaceBuffer = nullptr;
sptr<SurfaceBuffer> destinationGainmapSurfaceBuffer = nullptr;
ret = ConvertPixelmapToSurfaceBuffer(sourceImage, sourceImageSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ConvertPixelmapToSurfaceBuffer(destinationImage, destinationImageSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ConvertPixelmapToSurfaceBuffer(destinationGainmap, destinationGainmapSurfaceBuffer);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to surface buffer failed!");
ret = ImageProcessingUtils::InnerErrorToCAPI(
colorspaceConverter_->DecomposeImage(sourceImageSurfaceBuffer, destinationImageSurfaceBuffer,
destinationGainmapSurfaceBuffer));
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "process failed!");
return ret;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::GenerateMetadata(
const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::EnhanceDetail(
const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
// LCOV_EXCL_START
static CM_ColorSpaceType ConvertColorSpaceType(ColorManager::ColorSpaceName colorSpace, bool base)
{
switch (colorSpace) {
case ColorManager::ColorSpaceName::SRGB :
return CM_SRGB_FULL;
case ColorManager::ColorSpaceName::SRGB_LIMIT :
return CM_SRGB_LIMIT;
case ColorManager::ColorSpaceName::DISPLAY_P3 :
return CM_P3_FULL;
case ColorManager::ColorSpaceName::DISPLAY_P3_LIMIT :
return CM_P3_LIMIT;
case ColorManager::ColorSpaceName::BT2020 :
case ColorManager::ColorSpaceName::BT2020_HLG :
return CM_BT2020_HLG_FULL;
case ColorManager::ColorSpaceName::BT2020_HLG_LIMIT :
return CM_BT2020_HLG_LIMIT;
case ColorManager::ColorSpaceName::BT2020_PQ :
return CM_BT2020_PQ_FULL;
case ColorManager::ColorSpaceName::BT2020_PQ_LIMIT :
return CM_BT2020_PQ_LIMIT;
default:
return base ? CM_SRGB_FULL : CM_BT2020_HLG_FULL;
}
return base ? CM_SRGB_FULL : CM_BT2020_HLG_FULL;
}
ImageProcessing_ErrorCode ColorspaceConverterImageNative::ConvertPixelmapToSurfaceBuffer(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap, sptr<SurfaceBuffer>& bufferImpl)
{
auto it = IMAGE_FORMAT_MAP.find(pixelmap->GetPixelFormat());
CHECK_AND_RETURN_RET_LOG(it != IMAGE_FORMAT_MAP.end(), IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"unsupported format: %{public}d", pixelmap->GetPixelFormat());
CHECK_AND_RETURN_RET_LOG(pixelmap->GetAllocatorType() == AllocatorType::DMA_ALLOC,
IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING, "GetAllocatorType: %{public}d", pixelmap->GetAllocatorType());
bufferImpl = reinterpret_cast<SurfaceBuffer*>(pixelmap->GetFd());
CHECK_AND_RETURN_RET_LOG(bufferImpl != nullptr, IMAGE_PROCESSING_ERROR_PROCESS_FAILED,
"bufferImpl is nullptr");
auto colorspace = ConvertColorSpaceType(pixelmap->InnerGetGrColorSpace().GetColorSpaceName(), true);
auto colorspaceinfo = GetColorSpaceInfo(colorspace);
VPE_LOGD("colorspace : %{public}d", colorspace);
std::vector<uint8_t> colorSpaceInfoVec;
colorSpaceInfoVec.resize(sizeof(CM_ColorSpaceInfo));
auto ret = memcpy_s(colorSpaceInfoVec.data(), colorSpaceInfoVec.size(), &colorspaceinfo,
sizeof(CM_ColorSpaceInfo));
CHECK_AND_RETURN_RET_LOG(ret == EOK, IMAGE_PROCESSING_ERROR_PROCESS_FAILED,
"memcpy_s, err: %{public}d", ret);
auto err = bufferImpl->SetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoVec);
CHECK_AND_RETURN_RET_LOG(GSERROR_OK == err, IMAGE_PROCESSING_ERROR_PROCESS_FAILED,
"Get hdr metadata type failed, err: %{public}d", err);
return IMAGE_PROCESSING_SUCCESS;
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COLORSPACE_CONVERTER_IMAGE_NATIVE_H
#define COLORSPACE_CONVERTER_IMAGE_NATIVE_H
#include <atomic>
#include <functional>
#include <mutex>
#include "image_processing_native_template.h"
#include "image_processing_types.h"
#include "pixelmap_native_impl.h"
#include "detail_enhancer_image.h"
#include "colorspace_converter.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class ColorspaceConverterImageNative : public ImageProcessingNativeTemplate<ColorspaceConverterImageNative> {
public:
DEFINE_WITH_DISALLOW_COPY_AND_MOVE(ColorspaceConverterImageNative);
ImageProcessing_ErrorCode InitializeInner() override;
ImageProcessing_ErrorCode DeinitializeInner() override;
ImageProcessing_ErrorCode SetParameter(const OHOS::Media::Format& parameter) override;
ImageProcessing_ErrorCode GetParameter(OHOS::Media::Format& parameter) override;
ImageProcessing_ErrorCode Process(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage) override;
ImageProcessing_ErrorCode ConvertColorSpace(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage) override;
ImageProcessing_ErrorCode Compose(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
const std::shared_ptr<OHOS::Media::PixelMap>& sourceGainmap,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage) override;
ImageProcessing_ErrorCode Decompose(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationGainmap) override;
ImageProcessing_ErrorCode GenerateMetadata(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage) override;
ImageProcessing_ErrorCode EnhanceDetail(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage) override;
private:
ImageProcessing_ErrorCode CheckParameter();
ImageProcessing_ErrorCode ConvertPixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap,
sptr<SurfaceBuffer>& bufferImpl);
ImageProcessing_ErrorCode ConvertSurfaceBufferToPixelmap(sptr<SurfaceBuffer> buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap);
int LevelTransfer(int level, const std::unordered_map<int, int> levelMap) const;
mutable std::mutex lock_{};
// Guarded by lock_ begin
std::atomic<bool> isInitialized_{false};
std::shared_ptr<ColorSpaceConverter> colorspaceConverter_{};
// Guarded by lock_ end
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // COLORSPACE_CONVERTER_IMAGE_NATIVE_H
@@ -0,0 +1,331 @@
/*
* 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.
*/
#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
#undef LOG_TAG
#define LOG_TAG "DetailEnhanceNapi"
#include "detail_enhance_napi.h"
#include <chrono>
#include "image_log.h"
#include "image_trace.h"
#include "image_utils.h"
#include "log_tags.h"
#include "media_errors.h"
#include "memory_manager.h"
#include "native_avformat.h"
#include "pixelmap_native_impl.h"
#include "pixelmap_native.h"
#include "vpe_utils.h"
#if defined(__OHOS__)
#include "hitrace_meter.h"
#define ATRACE_CALL() HITRACE_METER_NAME(HITRACE_TAG_GRAPHIC_AGP, __func__)
#define ATRACE_BEGIN(name) StartTrace(HITRACE_TAG_GRAPHIC_AGP, name)
#define ATRACE_END() FinishTrace(HITRACE_TAG_GRAPHIC_AGP)
#define ATRACE_INT(name, value) CountTrace(HITRACE_TAG_GRAPHIC_AGP, name, value)
#endif
namespace {
constexpr uint32_t NUM_0 = 0;
constexpr uint32_t NUM_1 = 1;
constexpr uint32_t NUM_2 = 2;
constexpr uint32_t NUM_3 = 3;
}
namespace OHOS {
namespace Media {
using namespace VideoProcessingEngine;
ImageType DetailEnhanceNapi::ParserImageType(napi_env env, napi_value argv)
{
napi_value constructor = nullptr;
napi_value global = nullptr;
napi_status ret = napi_invalid_arg;
napi_get_global(env, &global);
ret = napi_get_named_property(env, global, "PixelMap", &constructor);
if (ret != napi_ok) {
IMAGE_LOGI("Get DetailEnhanceNapi property failed!");
}
bool isInstance = false;
ret = napi_instanceof(env, argv, constructor, &isInstance);
if (ret == napi_ok && isInstance) {
return ImageType::TYPE_PIXEL_MAP;
}
return ImageType::TYPE_UNKNOWN;
}
bool DetailEnhanceNapi::PrepareNapiEnv(napi_env env, napi_callback_info info, struct NapiValues* nVal)
{
napi_get_undefined(env, &(nVal->result));
nVal->status = napi_get_cb_info(env, info, &(nVal->argc), nVal->argv, &(nVal->thisVar), nullptr);
if (nVal->status != napi_ok) {
IMAGE_LOGE("fail to napi_get_cb_info");
return false;
}
nVal->context = std::make_unique<DetailEnhanceContext>();
return true;
}
std::shared_ptr<DetailEnhancerImage> DetailEnhancerImageCreate()
{
auto detailEnh = DetailEnhancerImage::Create();
if (detailEnh == nullptr) {
return nullptr;
}
return detailEnh;
}
napi_value DetailEnhanceNapi::Init(napi_env env, napi_callback_info info)
{
ATRACE_BEGIN("DetailEnhanceNapi::OH_ImageProcessing_Create");
std::lock_guard<std::mutex> lock(lock_);
napi_value result;
if (mDetailEnh != nullptr) {
napi_get_boolean(env, true, &result);
return result;
}
mDetailEnh = DetailEnhancerImageCreate();
if (mDetailEnh == nullptr) {
IMAGE_LOGE("mDetailEnh == nullptr");
return nullptr;
}
DetailEnhancerParameters param {
.uri = "",
.level = static_cast<DetailEnhancerLevel>(DETAIL_ENH_LEVEL_HIGH),
.forceEve = 1,
};
if (mDetailEnh->SetParameter(param)!= VPE_ALGO_ERR_OK) {
printf("Init failed!");
napi_get_boolean(env, false, &result);
return result;
}
ATRACE_END();
napi_get_boolean(env, true, &result);
return result;
}
napi_value DetailEnhanceNapi::Destroy(napi_env env, napi_callback_info info)
{
std::lock_guard<std::mutex> lock(lock_);
ATRACE_BEGIN("DetailEnhanceNapi::Destroy");
napi_value result;
if (mDetailEnh != nullptr) {
mDetailEnh = nullptr;
}
ATRACE_END();
napi_get_boolean(env, true, &result);
return result;
}
void DetailEnhanceNapi::SetDstPixelMapInfo(PixelMap &source, void* dstPixels, uint32_t dstPixelsSize,
std::unique_ptr<AbsMemory>& memory, PixelMap &dstPixelMap)
{
AllocatorType sourceType = source.GetAllocatorType();
if (sourceType != AllocatorType::DMA_ALLOC) {
IMAGE_LOGW("only support DMA");
return;
}
if (memory == nullptr) {
IMAGE_LOGW("Invalid memory");
return;
}
dstPixelMap.SetPixelsAddr(dstPixels, memory->extend.data, memory->data.size, sourceType, nullptr);
if (source.GetAllocatorType() == AllocatorType::DMA_ALLOC && source.IsHdr()) {
sptr<SurfaceBuffer> sourceSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (source.GetFd()));
sptr<SurfaceBuffer> dstSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (dstPixelMap.GetFd()));
VpeUtils::CopySurfaceBufferInfo(sourceSurfaceBuffer, dstSurfaceBuffer);
}
#ifdef IMAGE_COLORSPACE_FLAG
OHOS::ColorManager::ColorSpace colorspace = source.InnerGetGrColorSpace();
dstPixelMap.InnerSetColorSpace(colorspace);
#endif
}
bool DetailEnhanceNapi::AllocMemory(PixelMap &source, PixelMap &dstPixelMap)
{
if (source.GetPixels() == nullptr || source.GetAllocatorType() != AllocatorType::DMA_ALLOC) {
IMAGE_LOGE("source pixelMap data invalid");
return false;
}
int32_t bufferSize = source.GetByteCount();
if (bufferSize <= 0) {
IMAGE_LOGE("CopyPixelMap parameter bufferSize:[%{public}d] error.", bufferSize);
return false;
}
ImageInfo dstImageInfo;
dstPixelMap.GetImageInfo(dstImageInfo);
MemoryData memoryData = {nullptr, static_cast<size_t>(bufferSize), "Copy ImageData",
dstImageInfo.size, dstImageInfo.pixelFormat};
std::unique_ptr<AbsMemory> memory = MemoryManager::CreateMemory(source.GetAllocatorType(), memoryData);
if (memory == nullptr) {
IMAGE_LOGE("invalid memory");
return false;
}
void *dstPixels = memory->data.data;
if (dstPixels == nullptr) {
IMAGE_LOGE("source crop allocate memory fail allocatetype: %{public}d ", source.GetAllocatorType());
return false;
}
SetDstPixelMapInfo(source, dstPixels, static_cast<size_t>(bufferSize), memory, dstPixelMap);
return true;
}
std::unique_ptr<PixelMap> DetailEnhanceNapi::CreateDstPixelMap(PixelMap &source, const InitializationOptions &opts)
{
std::unique_ptr<PixelMap> dstPixelMap = std::make_unique<PixelMap>();
if (dstPixelMap == nullptr) {
IMAGE_LOGE("create pixelmap pointer fail");
return nullptr;
}
ImageInfo srcImageInfo;
source.GetImageInfo(srcImageInfo);
ImageInfo dstImageInfo = {
.size = opts.size,
.pixelFormat = srcImageInfo.pixelFormat,
.alphaType = srcImageInfo.alphaType,
};
if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) {
return nullptr;
}
if (!AllocMemory(source, *dstPixelMap.get())) {
return nullptr;
}
return dstPixelMap;
}
sptr<SurfaceBuffer> DetailEnhanceNapi::GetSurfaceBufferFromDMAPixelMap(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
if (pixelmap == nullptr || pixelmap->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
return nullptr;
}
return reinterpret_cast<SurfaceBuffer*>(pixelmap->GetFd());
}
napi_value DetailEnhanceNapi::DetailEnhanceImpl(napi_env env, std::unique_ptr<DetailEnhanceContext>& context)
{
if (context == nullptr) {
IMAGE_LOGE("context == nullptr");
return nullptr;
}
if (mDetailEnh == nullptr) {
IMAGE_LOGE("mDetailEnh == nullptr");
return nullptr;
}
ATRACE_BEGIN("DetailEnhanceNapi::CreatePixelMap");
InitializationOptions opts {
.size = {
.width = static_cast<int>(context->xArg),
.height = static_cast<int>(context->yArg),
},
};
std::unique_ptr<PixelMap> outputPtr = CreateDstPixelMap(*context->inputPixelMap, opts);
if (outputPtr == nullptr) {
IMAGE_LOGE("create failed");
return nullptr;
}
std::shared_ptr<PixelMap> dstPixelMap{std::move(outputPtr)};
if (dstPixelMap == nullptr) {
IMAGE_LOGE("move failed");
return nullptr;
}
auto input = GetSurfaceBufferFromDMAPixelMap(context->inputPixelMap);
auto output = GetSurfaceBufferFromDMAPixelMap(dstPixelMap);
if (mDetailEnh->Process(input, output) != VPE_ALGO_ERR_OK) {
IMAGE_LOGE("process failed");
return nullptr;
}
return PixelMapNapi::CreatePixelMap(env, dstPixelMap);
}
napi_value DetailEnhanceNapi::Process(napi_env env, napi_callback_info info)
{
ImageTrace imageTrace("DetailEnhanceNapi::DetailEnhance");
ATRACE_BEGIN("DetailEnhanceNapi::ProcessCheckEnv");
std::lock_guard<std::mutex> lock(lock_);
if (mDetailEnh == nullptr) {
napi_value result;
napi_get_boolean(env, false, &result);
return result;
}
ATRACE_END();
ATRACE_BEGIN("DetailEnhanceNapi::prepareNapi");
NapiValues nVal;
nVal.argc = NUM_3;
napi_value argValue[NUM_3] = {0};
nVal.argv = argValue;
if (!PrepareNapiEnv(env, info, &nVal)) {
return nVal.result;
}
if (nVal.argc != NUM_3) {
IMAGE_LOGE("Invalid args count %{public}zu", nVal.argc);
return nullptr;
} else {
if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_0], &(nVal.context->xArg))) {
IMAGE_LOGE("Arg 0 type mismatch");
return nullptr;
}
if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_1], &(nVal.context->yArg))) {
IMAGE_LOGE("Arg 1 type mismatch");
return nullptr;
}
if (ParserImageType(env, argValue[NUM_2]) == ImageType::TYPE_PIXEL_MAP) {
nVal.context->inputPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_2]);
}
if (nVal.context->inputPixelMap == nullptr) {
return nullptr;
}
}
if (nVal.context->callbackRef == nullptr) {
napi_create_promise(env, &(nVal.context->deferred), &(nVal.result));
}
ATRACE_END();
std::chrono::steady_clock::time_point clProcess = std::chrono::steady_clock::now();
napi_value outPixelmap = DetailEnhanceImpl(env, nVal.context);
std::chrono::duration<float, std::milli> clProcessD = std::chrono::steady_clock::now() - clProcess;
IMAGE_LOGI("detail enhance total cost: %{public}f ms", clProcessD.count());
return outPixelmap;
}
static napi_value Init(napi_env env, napi_value exports)
{
static napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("init", DetailEnhanceNapi::Init),
DECLARE_NAPI_FUNCTION("process", DetailEnhanceNapi::Process),
DECLARE_NAPI_FUNCTION("destroy", DetailEnhanceNapi::Destroy),
};
NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
return exports;
}
static napi_module detailEnhanceModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "multimedia.detailEnhancer",
.nm_priv = ((void *)0),
.reserved = {0},
};
extern "C" __attribute__((constructor)) void DetailEnhanceRegisterModule(void)
{
napi_module_register(&detailEnhanceModule);
}
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,848 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#undef LOG_DOMAIN
#define LOG_DOMAIN 0xD002B3F
#undef LOG_TAG
#define LOG_TAG "VpeNapi"
#include "detail_enhance_napi_formal.h"
#include <algorithm>
#include "image_processing_types.h"
#include "image_napi_utils.h"
#include "media_errors.h"
#include "memory_manager.h"
#include "native_avformat.h"
#include "pixelmap_native_impl.h"
#include "pixelmap_native.h"
#include "detail_enhancer_common.h"
#include "vpe_log.h"
#include "vpe_trace.h"
#include "vpe_utils.h"
namespace {
constexpr uint32_t NUM_0 = 0;
constexpr uint32_t NUM_1 = 1;
constexpr uint32_t NUM_2 = 2;
constexpr uint32_t NUM_3 = 3;
constexpr uint32_t NUM_4 = 4;
constexpr uint32_t NUM_5 = 5;
constexpr uint32_t NUM_6 = 6;
constexpr int32_t NEW_INSTANCE_ARGC = 1;
const std::string CLASS_NAME = "ImageProcessor";
static std::mutex g_imageProcessorMutex{std::mutex()};
static std::mutex g_detailLock{std::mutex()};
static std::mutex g_contrastLock{std::mutex()};
}
namespace OHOS {
namespace Media {
using namespace VideoProcessingEngine;
thread_local napi_ref VpeNapi::constructor_ = nullptr;
thread_local napi_ref VpeNapi::qualityLevelTypeRef_ = nullptr;
thread_local std::shared_ptr<VpeNapi::DetailEnhanceContext> VpeNapi::detailContext_ = nullptr;
thread_local std::shared_ptr<VpeNapi::ContrastEnhanceContext> VpeNapi::contrastContext_ = nullptr;
static std::shared_ptr<DetailEnhancerImage> g_detailEnh{};
static std::shared_ptr<ContrastEnhancerImage> g_contrastEnh{};
struct QualityLevelEnum {
std::string name;
int32_t numVal;
std::string strVal;
};
static std::vector<struct QualityLevelEnum> g_qualityLevels = {
{"NONE", OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_NONE, ""},
{"LOW", OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_LOW, ""},
{"MEDIUM", OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_MEDIUM, ""},
{"HIGH", OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_HIGH, ""},
};
void VpeNapi::ThrowExceptionError(napi_env env, const int32_t errCode, const std::string errMsg)
{
std::string errCodeStr = std::to_string(errCode);
napi_throw_error(env, errCodeStr.c_str(), errMsg.c_str());
}
bool VpeNapi::PrepareNapiEnv(napi_env env, napi_callback_info info, NapiValues* nVal)
{
CHECK_AND_RETURN_RET_LOG(nVal != nullptr, false, "nVal == nullptr");
if (napi_get_undefined(env, &(nVal->result)) != napi_ok) {
VPE_LOGE("Get undefined result failed");
return false;
}
nVal->status = napi_get_cb_info(env, info, &(nVal->argc), nVal->argv, &(nVal->thisVar), nullptr);
if (nVal->status != napi_ok) {
VPE_LOGE("fail to napi_get_cb_info");
return false;
}
return true;
}
ImageType VpeNapi::ParserImageType(napi_env env, napi_value argv)
{
napi_value constructor = nullptr;
napi_value global = nullptr;
napi_status ret = napi_invalid_arg;
napi_get_global(env, &global);
ret = napi_get_named_property(env, global, "PixelMap", &constructor);
if (ret != napi_ok) {
VPE_LOGI("Get VpeNapi property failed!");
}
bool isInstance = false;
ret = napi_instanceof(env, argv, constructor, &isInstance);
if (ret == napi_ok && isInstance) {
return ImageType::TYPE_PIXEL_MAP;
}
return ImageType::TYPE_UNKNOWN;
}
bool VpeNapi::ConfigResolutionBasedOnRatio(napi_env env, napi_value& nVal,
std::shared_ptr<VpeNapi::DetailEnhanceContext> context)
{
CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context == nullptr");
double zoomRatio;
if (napi_ok != napi_get_value_double(env, nVal, &zoomRatio)) {
VPE_LOGE("Arg 1 type mismatch");
return false;
}
CHECK_AND_RETURN_RET_LOG(context->inputPixelMap != nullptr, false, "context->inputPixelMap == nullptr");
context->xArg = zoomRatio * context->inputPixelMap->GetWidth();
context->yArg = zoomRatio * context->inputPixelMap->GetHeight();
VPE_LOGE("config resolution with ratio :%{public}d, %{public}d",
static_cast<int>(context->xArg), static_cast<int>(context->yArg));
return true;
}
bool VpeNapi::ConfigResolution(napi_env env, napi_value& width, napi_value& height,
std::shared_ptr<VpeNapi::DetailEnhanceContext> context)
{
CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context == nullptr");
CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_double(env, width, &(context->xArg)),
false, "Arg 1 type mismatch");
CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_double(env, height, &(context->yArg)),
false, "Arg 2 type mismatch");
return true;
}
bool VpeNapi::ParseDetailEnhanceParameter(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceParseParameter");
std::lock_guard<std::mutex> lock(g_detailLock);
CHECK_AND_RETURN_RET_LOG(detailContext_ != nullptr, false, "detailContext_ == nullptr");
NapiValues nVal;
nVal.argc = NUM_4; // Use the maximum value to initialize argc before executing PrepareNapiEnv
napi_value argValue[NUM_4] = {0};
nVal.argv = argValue;
CHECK_AND_RETURN_RET_LOG(PrepareNapiEnv(env, info, &nVal), false, "PrepareNapiEnv failed");
if (nVal.argc != NUM_2 && nVal.argc != NUM_3 && nVal.argc != NUM_4) {
VPE_LOGE("Invalid args count %{public}zu", nVal.argc);
return false;
}
if (ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP) {
detailContext_->inputPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
} else {
VPE_LOGE("args0 is not pixelMap!");
return false;
}
CHECK_AND_RETURN_RET_LOG(detailContext_->inputPixelMap != nullptr, false, "inputPixelMap is nullptr!");
if (nVal.argc == NUM_2) { // 2 parameter: pixelmap scaleRatio
CHECK_AND_RETURN_RET_LOG(ConfigResolutionBasedOnRatio(env, nVal.argv[NUM_1], detailContext_),
false, "ConfigResolutionBasedOnRatio failed");
detailContext_->qualityLevel = DETAIL_ENH_LEVEL_LOW; // default as low level
}
if (nVal.argc == NUM_3) { // 3 parameter: pixelmap scaleRatio level / pixelmap x y
double valueToCheck = 0;
CHECK_AND_RETURN_RET_LOG(napi_get_value_double(env, nVal.argv[NUM_2], &valueToCheck) == napi_ok,
false, "failed to parse");
if (valueToCheck >= 0 && valueToCheck <= 3) { // if valueToCheck in [0,3], valueToCheck should be level.
CHECK_AND_RETURN_RET_LOG(ConfigResolutionBasedOnRatio(env, nVal.argv[NUM_1], detailContext_), false,
"ConfigResolutionBasedOnRatio failed");
detailContext_->qualityLevel = static_cast<int>(valueToCheck);
} else {
CHECK_AND_RETURN_RET_LOG(ConfigResolution(env, nVal.argv[NUM_1], nVal.argv[NUM_2], detailContext_),
false, "ConfigResolution failed");
detailContext_->qualityLevel = DETAIL_ENH_LEVEL_LOW; // default as low level
}
}
if (nVal.argc == NUM_4) { // 4 parameter: pixelmap x y level
CHECK_AND_RETURN_RET_LOG(ConfigResolution(env, nVal.argv[NUM_1], nVal.argv[NUM_2], detailContext_),
false, "ConfigResolution failed");
CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_int32(env, nVal.argv[NUM_3],
&(detailContext_->qualityLevel)), false, "Arg 3 type mismatch");
}
return true;
}
napi_value VpeNapi::InitializeEnvironment(napi_env env, napi_callback_info info)
{
napi_value result;
napi_get_boolean(env, true, &result);
return result;
}
napi_value VpeNapi::DeinitializeEnvironment(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceDeinitializeEnvironment");
std::lock_guard<std::mutex> lock(g_detailLock);
napi_value result;
napi_get_boolean(env, true, &result);
return result;
}
void VpeNapi::SetDstPixelMapInfo(PixelMap& source, void* dstPixels, uint32_t dstPixelsSize,
std::unique_ptr<AbsMemory>& memory, PixelMap& dstPixelMap)
{
AllocatorType sourceType = source.GetAllocatorType();
if (sourceType != AllocatorType::DMA_ALLOC) {
VPE_LOGW("only support DMA");
return;
}
if (memory == nullptr) {
VPE_LOGW("Invalid memory");
return;
}
dstPixelMap.SetPixelsAddr(dstPixels, memory->extend.data, memory->data.size, sourceType, nullptr);
if (source.GetAllocatorType() == AllocatorType::DMA_ALLOC && source.IsHdr()) {
sptr<SurfaceBuffer> sourceSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (source.GetFd()));
sptr<SurfaceBuffer> dstSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (dstPixelMap.GetFd()));
VpeUtils::CopySurfaceBufferInfo(sourceSurfaceBuffer, dstSurfaceBuffer);
}
OHOS::ColorManager::ColorSpace colorspace = source.InnerGetGrColorSpace();
dstPixelMap.InnerSetColorSpace(colorspace);
}
bool VpeNapi::AllocMemory(PixelMap& source, PixelMap& dstPixelMap, const InitializationOptions& opt)
{
if (source.GetPixels() == nullptr) {
VPE_LOGE("pixels of source are not available");
return false;
}
int32_t bufferSize = source.GetByteCount();
if (bufferSize <= 0) {
VPE_LOGE("CopyPixelMap parameter bufferSize:[%{public}d] error.", bufferSize);
return false;
}
ImageInfo dstImageInfo;
dstPixelMap.GetImageInfo(dstImageInfo);
MemoryData memoryData = {nullptr, static_cast<size_t>(bufferSize), "Copy ImageData",
dstImageInfo.size, dstImageInfo.pixelFormat};
std::unique_ptr<AbsMemory> memory = MemoryManager::CreateMemory(source.GetAllocatorType(), memoryData);
if (memory == nullptr) {
VPE_LOGE("invalid memory");
return false;
}
void* dstPixels = memory->data.data;
if (dstPixels == nullptr) {
VPE_LOGE("source crop allocate memory fail allocatetype: %{public}d ", source.GetAllocatorType());
return false;
}
SetDstPixelMapInfo(source, dstPixels, static_cast<size_t>(bufferSize), memory, dstPixelMap);
return true;
}
std::unique_ptr<PixelMap> VpeNapi::CreateDstPixelMap(PixelMap& source, const InitializationOptions& opts)
{
if (source.GetAllocatorType() != AllocatorType::DMA_ALLOC) {
VPE_LOGE("alloc type of source is not dma, create with default method");
return source.Create(source, opts);
}
std::unique_ptr<PixelMap> dstPixelMap = std::make_unique<PixelMap>();
if (dstPixelMap == nullptr) {
VPE_LOGE("create pixelmap pointer fail");
return nullptr;
}
ImageInfo srcImageInfo;
source.GetImageInfo(srcImageInfo);
ImageInfo dstImageInfo = {
.size = opts.size,
.pixelFormat = srcImageInfo.pixelFormat,
.alphaType = srcImageInfo.alphaType,
};
if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) {
return nullptr;
}
if (!AllocMemory(source, *dstPixelMap.get(), opts)) {
return nullptr;
}
return dstPixelMap;
}
bool VpeNapi::ConvertPixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap,
sptr<SurfaceBuffer>& bufferImpl)
{
BufferRequestConfig bfConfig = {};
bfConfig.width = pixelmap->GetWidth();
bfConfig.height = pixelmap->GetHeight();
bfConfig.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE;
bfConfig.strideAlignment = bfConfig.width;
bfConfig.format = GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888;
bfConfig.timeout = 0;
bfConfig.colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB;
bfConfig.transform = GraphicTransformType::GRAPHIC_ROTATE_NONE;
CHECK_AND_RETURN_RET_LOG((bufferImpl->Alloc(bfConfig) == GSERROR_OK), false, "invalid OH_PixelmapNative image");
return true;
}
sptr<SurfaceBuffer> VpeNapi::GetSurfaceBufferFromDMAPixelMap(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
CHECK_AND_RETURN_RET_LOG(pixelmap != nullptr, nullptr, "pixelmap == nullptr");
if (pixelmap->GetAllocatorType() == AllocatorType::DMA_ALLOC) {
return reinterpret_cast<SurfaceBuffer*>(pixelmap->GetFd());
}
auto buffer = SurfaceBuffer::Create();
CHECK_AND_RETURN_RET_LOG(buffer != nullptr, nullptr, "get surface buffer failed!");
CHECK_AND_RETURN_RET_LOG(ConvertPixelmapToSurfaceBuffer(pixelmap, buffer), nullptr,
"get surface buffer failed!");
return buffer;
}
napi_value VpeNapi::Create(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_value constructor = nullptr;
napi_status status = napi_ok;
status = napi_get_reference_value(env, constructor_, &constructor);
if (status == napi_ok) {
size_t argc = NEW_INSTANCE_ARGC;
napi_value argv[NEW_INSTANCE_ARGC] = { 0 };
status = napi_new_instance(env, constructor, argc, argv, &result);
}
if (status != napi_ok) {
VPE_LOGE("create instance failed");
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "create instance failed");
return nullptr;
}
VPE_LOGE("create done");
return result;
}
std::shared_ptr<PixelMap> VpeNapi::PrepareDstPixelMap(napi_env env, DetailEnhanceContext* context)
{
CHECK_AND_RETURN_RET_LOG(context->inputPixelMap->GetWidth() != 0 && context->inputPixelMap->GetHeight() != 0,
nullptr, "invalid resolution");
float ratio = std::min(static_cast<float>(context->xArg) / static_cast<float>(context->inputPixelMap->GetWidth()),
static_cast<float>(context->yArg) / static_cast<float>(context->inputPixelMap->GetHeight()));
InitializationOptions opts {
.size = {
.width = ratio < 1.0 ? static_cast<int>(context->xArg) :
static_cast<int>(context->inputPixelMap->GetWidth()),
.height = ratio < 1.0 ? static_cast<int>(context->yArg) :
static_cast<int>(context->inputPixelMap->GetHeight()),
},
};
std::unique_ptr<PixelMap> outputPtr = CreateDstPixelMap(*context->inputPixelMap, opts);
if (outputPtr == nullptr) {
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_INVALID_VALUE, "create failed");
return nullptr;
}
std::shared_ptr<PixelMap> dstPixelMap{std::move(outputPtr)};
return dstPixelMap;
}
bool VpeNapi::InitDetailAlgo(napi_env env, int level)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceInitAlgo");
CHECK_AND_RETURN_RET_LOG(g_detailEnh == nullptr, true, "DetailEnhancerImage handle has created");
g_detailEnh = DetailEnhancerImage::Create();
CHECK_AND_RETURN_RET_LOG(g_detailEnh != nullptr, false, "create DetailEnhancerImage failed");
DetailEnhancerParameters param {
.uri = "",
.level = static_cast<DetailEnhancerLevel>(level),
};
if (g_detailEnh->SetParameter(param)!= VPE_ALGO_ERR_OK) {
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "set parameter failed");
return false;
}
return true;
}
std::shared_ptr<PixelMap> VpeNapi::DetailEnhanceImpl(napi_env env, DetailEnhanceContext* context)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceImpl");
if (context == nullptr) {
VPE_LOGE("context == nullptr");
return nullptr;
}
if (!InitDetailAlgo(env, context->qualityLevel)) {
VPE_LOGE("init algo failed");
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "init algo failed");
return nullptr;
}
if (context->inputPixelMap == nullptr) {
VPE_LOGE("*context->inputPixelMap == nullptr");
return nullptr;
}
auto dstPixelMap = PrepareDstPixelMap(env, context);
if (dstPixelMap == nullptr) {
VPE_LOGE("move failed");
return nullptr;
}
auto output = GetSurfaceBufferFromDMAPixelMap(dstPixelMap);
auto input = GetSurfaceBufferFromDMAPixelMap(context->inputPixelMap);
CHECK_AND_RETURN_RET_LOG((g_detailEnh != nullptr && g_detailEnh->Process(input, output) == VPE_ALGO_ERR_OK),
nullptr, "process failed");
VPE_LOGI("process done");
return dstPixelMap;
}
napi_value VpeNapi::EnhanceDetail(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceProcess");
if (detailContext_ == nullptr) {
detailContext_ = std::make_shared<DetailEnhanceContext>();
}
CHECK_AND_RETURN_RET_LOG(detailContext_ != nullptr, nullptr, "context == nullptr");
napi_deferred deferred;
napi_value promise;
NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
CHECK_AND_RETURN_RET_LOG(ParseDetailEnhanceParameter(env, info), nullptr, "parse parameter failed");
detailContext_->deferred = deferred;
napi_value resourceName;
napi_create_string_latin1(env, "Asynchronous processing", NAPI_AUTO_LENGTH, &resourceName);
napi_status status = napi_create_async_work(env, nullptr, resourceName,
[](napi_env env, void* data) {
DetailEnhanceContext* innerAsyncContext = reinterpret_cast<DetailEnhanceContext*>(data);
if (innerAsyncContext == nullptr) {
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_PROCESS_FAILED, "innerAsyncContext is nullptr");
return;
}
innerAsyncContext->outputPixelMap = DetailEnhanceImpl(env, innerAsyncContext);
},
[](napi_env env, napi_status status, void* data) {
DetailEnhanceContext* innerAsyncContext = reinterpret_cast<DetailEnhanceContext*>(data);
if (innerAsyncContext == nullptr) {
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_PROCESS_FAILED, "innerAsyncContext is nullptr");
return;
}
napi_value outputPixelMapNapi = (innerAsyncContext->outputPixelMap == nullptr) ?
nullptr : PixelMapNapi::CreatePixelMap(env, innerAsyncContext->outputPixelMap);
if (outputPixelMapNapi == nullptr) {
VPE_LOGI("outputPixelMap is nullptr");
return;
}
if (innerAsyncContext->deferred) {
napi_resolve_deferred(env, innerAsyncContext->deferred, outputPixelMapNapi);
} else {
napi_value callback = nullptr;
napi_get_reference_value(env, innerAsyncContext->callbackRef, &callback);
napi_call_function(env, nullptr, callback, 1, &(outputPixelMapNapi), nullptr);
napi_delete_reference(env, innerAsyncContext->callbackRef);
innerAsyncContext->callbackRef = nullptr;
}
napi_delete_async_work(env, innerAsyncContext->asyncWork);
delete innerAsyncContext;
}, reinterpret_cast<void*>(detailContext_.get()), &detailContext_->asyncWork);
CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "create aysnc failed");
napi_queue_async_work(env, detailContext_->asyncWork);
return promise;
}
napi_value VpeNapi::EnhanceDetailSync(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceProcess");
if (detailContext_ == nullptr) {
detailContext_ = std::make_shared<DetailEnhanceContext>();
}
CHECK_AND_RETURN_RET_LOG(detailContext_ != nullptr, nullptr, "context == nullptr");
CHECK_AND_RETURN_RET_LOG(ParseDetailEnhanceParameter(env, info), nullptr, "parse parameter failed");
std::shared_ptr<PixelMap> outputPixelMap = DetailEnhanceImpl(env, detailContext_.get());
if (outputPixelMap == nullptr) {
VPE_LOGE("DetailEnhanceImpl processed failed");
return nullptr;
}
napi_value outputPixelMapNapi = PixelMapNapi::CreatePixelMap(env, outputPixelMap);
return outputPixelMapNapi;
}
bool VpeNapi::UpdateMetadataBasedOnLcd(ContrastEnhanceContext* context)
{
sptr<SurfaceBuffer> surfaceBuffer = GetSurfaceBufferFromDMAPixelMap(context->inputPixelMap);
return g_contrastEnh->UpdateMetadataBasedOnLcd(context->displayArea, context->lcdWidth, context->lcdHeight,
surfaceBuffer);
}
bool VpeNapi::UpdateMetadataBasedOnDetail(ContrastEnhanceContext* context)
{
OHOS::Rect completePixelmapArea = {
.x = 0,
.y = 0,
.w = context->oriWidth,
.h = context->oriHeight,
};
sptr<SurfaceBuffer> surfaceBuffer = GetSurfaceBufferFromDMAPixelMap(context->inputPixelMap);
return g_contrastEnh->UpdateMetadataBasedOnDetail(context->displayArea, context->curPixelmapArea,
completePixelmapArea, surfaceBuffer, context->fullRatio);
}
napi_value VpeNapi::SetDetailImage(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceProcess");
if (contrastContext_ == nullptr) {
contrastContext_ = std::make_shared<ContrastEnhanceContext>();
VPE_LOGI("create new contrast context");
}
CHECK_AND_RETURN_RET_LOG(contrastContext_ != nullptr, nullptr, "context == nullptr");
NapiValues nVal;
CHECK_AND_RETURN_RET_LOG(ParseDetailImageParameter(env, info, nVal), nullptr, "parse parameter failed");
// 不管是不是区域解码,都先使用直方图的结果进行展示,之后再转变成bitmap的结果
UpdateMetadataBasedOnLcd(contrastContext_.get());
CallCallback(env, contrastContext_.get());
// 如果在计算完成前坐标位置已经发生了变化,则不需要继续进行计算
CHECK_AND_RETURN_RET_LOG(!contrastContext_->genFinalEffect, nullptr, "It's still moving. Stop processing");
if (contrastContext_->callbackRef == nullptr) {
napi_create_promise(env, &(contrastContext_->deferred), &(nVal.result));
}
napi_value resourceName;
napi_create_string_latin1(env, "Asynchronous processing", NAPI_AUTO_LENGTH, &resourceName);
napi_status status = napi_create_async_work(
env, nullptr, resourceName,
[](napi_env env, void* data) {
ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
if (innerAsyncContext == nullptr) {
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_PROCESS_FAILED, "innerAsyncContext == nullptr");
return;
}
UpdateMetadataBasedOnDetail(innerAsyncContext);
},
[](napi_env env, napi_status status, void* data) {
ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
CallCallback(env, innerAsyncContext);
if (status != napi_ok) {
VPE_LOGE("process failed");
}
VPE_LOGI("process detail image done");
},
(void*)(contrastContext_.get()), &contrastContext_->asyncWork);
CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "create aysnc failed");
status = napi_queue_async_work(env, contrastContext_->asyncWork);
CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "queue aysnc work failed");
return nullptr;
}
bool VpeNapi::GenerateRegionHist(napi_env env, ContrastEnhanceContext* context)
{
CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context == nullptr");
CHECK_AND_RETURN_RET_LOG(context->lcdPixelMap != nullptr, false, "lcdPixelMap == nullptr");
auto input = GetSurfaceBufferFromDMAPixelMap(context->lcdPixelMap);
CHECK_AND_RETURN_RET_LOG(input != nullptr, false, "input == nullptr");
CHECK_AND_RETURN_RET_LOG(g_contrastEnh != nullptr, false, "g_contrastEnh == nullptr");
if (g_contrastEnh->GetRegionHist(input) != 0) { // 9ms
VPE_LOGE("processed failed. Clear LUT history");
return false;
}
return true;
}
bool VpeNapi::InitContrastAlgo(napi_env env)
{
VPETrace vpeTrace("VpeNapi::DetailEnhanceInitAlgo");
CHECK_AND_RETURN_RET_LOG(g_contrastEnh == nullptr, true, "ContrastEnhancerImage handle has created");
g_contrastEnh = ContrastEnhancerImage::Create();
CHECK_AND_RETURN_RET_LOG(g_contrastEnh != nullptr, false, "create ContrastEnhancerImage failed");
ContrastEnhancerParameters param {
.uri = "",
};
if (g_contrastEnh->SetParameter(param)!= VPE_ALGO_ERR_OK) {
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "set parameter failed");
return false;
}
return true;
}
bool VpeNapi::ParseRect(napi_env env, napi_value nVal, OHOS::Rect& rect)
{
CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "x", rect.x), false, "Failed to parse start pos X");
CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "y", rect.y), false, "Failed to parse start pos Y");
napi_value tmpValue = nullptr;
CHECK_AND_RETURN_RET_LOG(GET_NODE_BY_NAME(nVal, "size", tmpValue), false, "Failed to parse resolution of rect");
CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(tmpValue, "height", rect.h), false, "Failed to parse height of rect");
CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(tmpValue, "width", rect.w), false, "Failed to parse width of rect");
return true;
}
bool VpeNapi::ParseSize(napi_env env, napi_value nVal)
{
napi_value tmpValue = nullptr;
CHECK_AND_RETURN_RET_LOG(GET_NODE_BY_NAME(nVal, "size", tmpValue), false, "Failed to parse resolution of rect");
CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "height", contrastContext_->oriHeight),
false, "Failed to parse height of rect");
CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "width", contrastContext_->oriWidth),
false, "Failed to parse width of rect");
return true;
}
bool VpeNapi::ParseDetailImageParameter(napi_env env, napi_callback_info info, NapiValues& nVal)
{
VPETrace vpeTrace("VpeNapi::DetailEnhance");
std::lock_guard<std::mutex> lock(g_contrastLock);
nVal.argc = NUM_6;
napi_value argValue[NUM_6] = {0};
nVal.argv = argValue;
if (!PrepareNapiEnv(env, info, &nVal)) {
return false;
}
if (nVal.argc != NUM_6) {
VPE_LOGE("Invalid args count %{public}zu", nVal.argc);
return false;
} else {
CHECK_AND_RETURN_RET_LOG(ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP,
false, "Arg 0 type mismatch");
contrastContext_->inputPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
CHECK_AND_RETURN_RET_LOG(contrastContext_->inputPixelMap != nullptr, false,
"contrastContext_->srcPixelMap == nullptr, resuse history");
CHECK_AND_RETURN_RET_LOG(napi_get_value_int32(env, nVal.argv[NUM_1],
&(contrastContext_->pixelmapId)) == napi_ok, false, "Arg 1 type mismatch");
CHECK_AND_RETURN_RET_LOG(ParseRect(env, argValue[NUM_2], contrastContext_->curPixelmapArea), false,
"parse pixelmap area failed");
CHECK_AND_RETURN_RET_LOG(ParseRect(env, argValue[NUM_3], contrastContext_->displayArea), false,
"parse display area failed");
CHECK_AND_RETURN_RET_LOG(ParseSize(env, argValue[NUM_4]), false, "parse resolution of original image failed");
CHECK_AND_RETURN_RET_LOG(napi_get_value_bool(env, nVal.argv[NUM_5],
&(contrastContext_->genFinalEffect)) == napi_ok, false, "Arg 5 type mismatch");
}
contrastContext_->fullRatio = std::min(
static_cast<float>(contrastContext_->inputPixelMap->GetWidth()) /
static_cast<float>(contrastContext_->curPixelmapArea.w),
static_cast<float>(contrastContext_->inputPixelMap->GetHeight()) /
static_cast<float>(contrastContext_->curPixelmapArea.h));
return true;
}
bool VpeNapi::ParseLCDParameter(napi_env env, napi_callback_info info, NapiValues& nVal)
{
VPETrace vpeTrace("VpeNapi::DetailEnhance");
std::lock_guard<std::mutex> lock(g_contrastLock);
nVal.argc = NUM_3;
napi_value argValue[NUM_3] = {0};
nVal.argv = argValue;
if (!PrepareNapiEnv(env, info, &nVal)) {
return false;
}
if (nVal.argc != NUM_3) {
VPE_LOGE("Invalid args count %{public}zu", nVal.argc);
return false;
} else {
CHECK_AND_RETURN_RET_LOG(ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP,
false, "Arg 0 type is not pixelmap");
contrastContext_->lcdPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
CHECK_AND_RETURN_RET_LOG(napi_get_value_int32(env, nVal.argv[NUM_1],
&(contrastContext_->contentId)) == napi_ok, false, "Failed to parse lcd param. Arg 1 type mismatch");
CHECK_AND_RETURN_RET_LOG(napi_get_value_double(env, nVal.argv[NUM_2],
&(contrastContext_->defaultRatio)) == napi_ok, false, "Failed to parse lcd param. Arg 2 type mismatch");
contrastContext_->lcdWidth = contrastContext_->lcdPixelMap->GetWidth();
contrastContext_->lcdHeight = contrastContext_->lcdPixelMap->GetHeight();
}
VPE_LOGI("update content info: lcdWidth:%{public}d, lcdHeight:%{public}d",
contrastContext_->lcdWidth, contrastContext_->lcdHeight);
return true;
}
napi_value VpeNapi::SetLcdImage(napi_env env, napi_callback_info info)
{
VPE_LOGI("set lcd image");
VPETrace vpeTrace("VpeNapi::DetailEnhanceProcess");
napi_value result = nullptr;
if (contrastContext_ == nullptr) {
contrastContext_ = std::make_shared<ContrastEnhanceContext>();
VPE_LOGI("create new contrast context");
}
if (contrastContext_ == nullptr) {
VPE_LOGE("context == nullptr");
return result;
}
NapiValues nVal;
if (!ParseLCDParameter(env, info, nVal)) {
VPE_LOGE("parse parameter failed");
return result;
}
napi_value resourceName;
napi_create_string_latin1(env, "Asynchronous processing", NAPI_AUTO_LENGTH, &resourceName);
napi_status status = napi_create_async_work(
env, nullptr, resourceName,
[](napi_env env, void* data) {
ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
if (innerAsyncContext == nullptr) {
ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_PROCESS_FAILED, "innerAsyncContext == nullptr");
return;
}
GenerateRegionHist(env, innerAsyncContext);
},
[](napi_env env, napi_status status, void* data) {
ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
CallCallback(env, innerAsyncContext);
if (status != napi_ok) {
VPE_LOGE("Failed to generate lut baseline for pcicture %{public}d", contrastContext_->contentId);
}
VPE_LOGI("Generate lut baseline for picture %{public}d successfully. Initial scaling ratio: %{public}f",
contrastContext_->contentId, contrastContext_->defaultRatio);
},
(void*)(contrastContext_.get()), &contrastContext_->asyncWork);
CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "create aysnc failed");
CHECK_AND_RETURN_RET_LOG(napi_queue_async_work(env, contrastContext_->asyncWork) == napi_ok,
nullptr, "queue aysnc work failed");
return result;
}
napi_value VpeNapi::RegisterCallback(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1];
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (contrastContext_->callbackRef != nullptr) {
napi_delete_reference(env, contrastContext_->callbackRef);
}
napi_create_reference(env, argv[0], 1, &(contrastContext_->callbackRef));
return nullptr;
}
napi_value VpeNapi::CallCallback(napi_env env, ContrastEnhanceContext* context)
{
bool noCall = true;
if (noCall) {
return nullptr;
}
if (context->callbackRef != nullptr) {
napi_value global;
napi_get_global(env, &global);
napi_value callbackFunc;
napi_get_reference_value(env, context->callbackRef, &callbackFunc);
napi_value result;
napi_call_function(env, global, callbackFunc, 0, nullptr, &result);
}
return nullptr;
}
napi_value VpeNapi::Constructor(napi_env env, napi_callback_info info)
{
napi_value undefineVar = nullptr;
napi_get_undefined(env, &undefineVar);
napi_status status;
napi_value thisVar = nullptr;
napi_get_undefined(env, &thisVar);
size_t argc = NEW_INSTANCE_ARGC;
napi_value argv[NEW_INSTANCE_ARGC] = { 0 };
status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
if (status != napi_ok || thisVar == nullptr) {
return undefineVar;
}
VpeNapi* pDetailEnhanceNapi = new VpeNapi();
status = napi_wrap_with_size(env, thisVar, reinterpret_cast<void*>(pDetailEnhanceNapi),
VpeNapi::Destructor, nullptr, nullptr, static_cast<size_t>(sizeof(VpeNapi)));
CHECK_AND_RETURN_RET_LOG(status == napi_ok, undefineVar, "Failure wrapping js to native napi");
return thisVar;
}
void VpeNapi::Destructor(napi_env env, void* nativeObject, void* finalize)
{
if (nativeObject != nullptr) {
std::lock_guard<std::mutex> lock(g_imageProcessorMutex);
delete reinterpret_cast<VpeNapi*>(nativeObject);
nativeObject = nullptr;
}
}
napi_value VpeNapi::DoInitAfter(napi_env env, napi_value exports, napi_value constructor,
size_t property_count, const napi_property_descriptor* properties)
{
napi_value global = nullptr;
CHECK_AND_RETURN_RET_LOG(napi_get_global(env, &global) == napi_ok, nullptr, "Init:get global fail");
CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor) == napi_ok,
nullptr, "Init:set global named property fail");
CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor) == napi_ok,
nullptr, "set named property fail");
CHECK_AND_RETURN_RET_LOG(napi_define_properties(env, exports, property_count, properties) == napi_ok,
nullptr, "define properties fail");
return exports;
}
napi_value VpeNapi::CreateEnumTypeObject(napi_env env, napi_valuetype type, napi_ref* ref,
std::vector<struct QualityLevelEnum>& imageEnumMap)
{
napi_value result = nullptr;
napi_status status;
int32_t refCount = 1;
std::string propName;
status = napi_create_object(env, &result);
if (status == napi_ok) {
for (auto imgEnum : imageEnumMap) {
napi_value enumNapiValue = nullptr;
if (type == napi_string) {
status = napi_create_string_utf8(env, imgEnum.strVal.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
} else if (type == napi_number) {
status = napi_create_int32(env, imgEnum.numVal, &enumNapiValue);
} else {
VPE_LOGE("Unsupported type %{public}d!", type);
}
if (status == napi_ok && enumNapiValue != nullptr) {
status = napi_set_named_property(env, result, imgEnum.name.c_str(), enumNapiValue);
}
if (status != napi_ok) {
VPE_LOGE("Failed to add named prop!");
break;
}
}
if (status == napi_ok) {
status = napi_create_reference(env, result, refCount, ref);
if (status == napi_ok) {
return result;
}
}
}
VPE_LOGE("CreateEnumTypeObject is Failed!");
napi_get_undefined(env, &result);
return result;
}
std::vector<napi_property_descriptor> VpeNapi::RegisterNapi()
{
std::vector<napi_property_descriptor> props = {
DECLARE_NAPI_FUNCTION("enhanceDetail", VpeNapi::EnhanceDetail),
DECLARE_NAPI_FUNCTION("enhanceDetailSync", VpeNapi::EnhanceDetailSync),
DECLARE_NAPI_FUNCTION("setLcdImage", VpeNapi::SetLcdImage),
DECLARE_NAPI_FUNCTION("setDetailImage", VpeNapi::SetDetailImage),
DECLARE_NAPI_FUNCTION("registerCallback", VpeNapi::RegisterCallback)
};
return props;
}
napi_value VpeNapi::Init(napi_env env, napi_value exports)
{
std::vector<napi_property_descriptor> props = VpeNapi::RegisterNapi();
napi_value constructor = nullptr;
CHECK_AND_RETURN_RET_LOG(napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
VpeNapi::Constructor, nullptr, props.size(), props.data(), &constructor) == napi_ok,
nullptr, "define class fail");
CHECK_AND_RETURN_RET_LOG(napi_create_reference(env, constructor, 1, &constructor_) == napi_ok,
nullptr, "create reference fail");
static napi_property_descriptor desc[] = {
DECLARE_NAPI_PROPERTY("QualityLevel",
CreateEnumTypeObject(env, napi_number, &qualityLevelTypeRef_, g_qualityLevels)),
DECLARE_NAPI_FUNCTION("create", VpeNapi::Create),
DECLARE_NAPI_FUNCTION("initializeEnvironment", VpeNapi::InitializeEnvironment),
DECLARE_NAPI_FUNCTION("deinitializeEnvironment", VpeNapi::DeinitializeEnvironment),
};
auto result = DoInitAfter(env, exports, constructor, sizeof(desc) / sizeof(desc[0]), desc);
return result;
}
}
}
@@ -0,0 +1,149 @@
/*
* 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 "detail_enhancer_image_native.h"
#include <unordered_map>
#include "detail_enhancer_common.h"
#include "detail_enhancer_image_fwk.h"
#include "image_processing_utils.h"
#include "surface_buffer.h"
#include "vpe_log.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
namespace {
const std::unordered_map<int, int> CAPI_TO_INNER_LEVEL_MAP = {
{ IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_NONE, DETAIL_ENH_LEVEL_NONE },
{ IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_LOW, DETAIL_ENH_LEVEL_LOW },
{ IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_MEDIUM, DETAIL_ENH_LEVEL_MEDIUM },
{ IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_HIGH, DETAIL_ENH_LEVEL_HIGH },
};
const std::unordered_map<int, int> INNER_TO_CAPI_LEVEL_MAP = {
{ DETAIL_ENH_LEVEL_NONE, IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_NONE },
{ DETAIL_ENH_LEVEL_LOW, IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_LOW },
{ DETAIL_ENH_LEVEL_MEDIUM, IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_MEDIUM },
{ DETAIL_ENH_LEVEL_HIGH, IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_HIGH },
};
}
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
ImageProcessing_ErrorCode DetailEnhancerImageNative::InitializeInner()
{
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(!isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already init!");
detailEnhancer_ = DetailEnhancerImage::Create();
CHECK_AND_RETURN_RET_LOG(detailEnhancer_ != nullptr, IMAGE_PROCESSING_ERROR_CREATE_FAILED,
"Create detail enhancement failed!");
isInitialized_ = true;
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode DetailEnhancerImageNative::DeinitializeInner()
{
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already deinit!");
detailEnhancer_ = nullptr;
isInitialized_ = false;
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode DetailEnhancerImageNative::SetParameter(const OHOS::Media::Format& parameter)
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED,
"Detail enhancer image is not initialized!");
int level;
CHECK_AND_RETURN_RET_LOG(parameter.GetIntValue(IMAGE_DETAIL_ENHANCER_PARAMETER_KEY_QUALITY_LEVEL, level),
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "No quality level!");
int innerLevel = LevelTransfer(level, CAPI_TO_INNER_LEVEL_MAP);
CHECK_AND_RETURN_RET_LOG(innerLevel != -1, IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "Quality level is invalid!");
DetailEnhancerParameters param{};
param.level = static_cast<DetailEnhancerLevel>(innerLevel);
return ImageProcessingUtils::InnerErrorToCAPI(detailEnhancer_->SetParameter(param));
}
ImageProcessing_ErrorCode DetailEnhancerImageNative::GetParameter(OHOS::Media::Format& parameter)
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED,
"Detail enhancer image is not initialized!");
DetailEnhancerParameters param {
.uri = "",
.level{},
};
auto ret = detailEnhancer_->GetParameter(param);
CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, ImageProcessingUtils::InnerErrorToCAPI(ret), "param is not set");
int level = LevelTransfer(param.level, INNER_TO_CAPI_LEVEL_MAP);
CHECK_AND_RETURN_RET_LOG(level != -1, IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "Quality level is invalid!");
parameter.PutIntValue(IMAGE_DETAIL_ENHANCER_PARAMETER_KEY_QUALITY_LEVEL, level);
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode DetailEnhancerImageNative::Process(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED,
"Detail enhancer image is not initialized!");
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "sourceImage or destinationImage is null!");
auto sourceImageSurfaceBuffer = ImageProcessingUtils::GetSurfaceBufferFromPixelMap(sourceImage);
CHECK_AND_RETURN_RET_LOG(sourceImageSurfaceBuffer != nullptr, IMAGE_PROCESSING_ERROR_PROCESS_FAILED,
"sourceImageSurfaceBuffer create failed!");
auto destinationImageSurfaceBuffer = ImageProcessingUtils::GetSurfaceBufferFromPixelMap(destinationImage);
CHECK_AND_RETURN_RET_LOG(destinationImageSurfaceBuffer != nullptr, IMAGE_PROCESSING_ERROR_PROCESS_FAILED,
"destinationImageSurfaceBuffer create failed!");
auto ret = CheckParameter();
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "check parameter failed!");
ret = ImageProcessingUtils::InnerErrorToCAPI(
detailEnhancer_->Process(sourceImageSurfaceBuffer, destinationImageSurfaceBuffer, true));
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "process failed!");
ret = ImageProcessingUtils::SetSurfaceBufferToPixelMap(destinationImageSurfaceBuffer, destinationImage);
CHECK_AND_RETURN_RET_LOG(ret == IMAGE_PROCESSING_SUCCESS, ret, "convert to pixelmap failed!");
return ret;
}
ImageProcessing_ErrorCode DetailEnhancerImageNative::CheckParameter()
{
DetailEnhancerParameters param {
.uri = "",
.level{},
};
if (detailEnhancer_->GetParameter(param) == VPE_ALGO_ERR_OK) {
return IMAGE_PROCESSING_SUCCESS;
}
param.level = static_cast<DetailEnhancerLevel>(IMAGE_DETAIL_ENHANCER_QUALITY_LEVEL_HIGH);
CHECK_AND_RETURN_RET_LOG(detailEnhancer_->SetParameter(param) == VPE_ALGO_ERR_OK,
IMAGE_PROCESSING_ERROR_PROCESS_FAILED, "set default enhance level failed!!");
return IMAGE_PROCESSING_SUCCESS;
}
int DetailEnhancerImageNative::LevelTransfer(int level, const std::unordered_map<int, int> levelMap) const
{
auto it = levelMap.find(level);
if (it == levelMap.end()) [[unlikely]] {
VPE_LOGE("Invalid input level:%{public}d", level);
return -1;
}
return it->second;
}
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,58 @@
/*
* 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 DETAIL_ENHANCER_IMAGE_NATIVE_H
#define DETAIL_ENHANCER_IMAGE_NATIVE_H
#include <atomic>
#include <functional>
#include <mutex>
#include "image_processing_native_template.h"
#include "image_processing_types.h"
#include "pixelmap_native_impl.h"
#include "detail_enhancer_image.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class DetailEnhancerImageNative : public ImageProcessingNativeTemplate<DetailEnhancerImageNative> {
public:
DEFINE_WITH_DISALLOW_COPY_AND_MOVE(DetailEnhancerImageNative);
ImageProcessing_ErrorCode InitializeInner() override;
ImageProcessing_ErrorCode DeinitializeInner() override;
ImageProcessing_ErrorCode SetParameter(const OHOS::Media::Format& parameter) override;
ImageProcessing_ErrorCode GetParameter(OHOS::Media::Format& parameter) override;
ImageProcessing_ErrorCode Process(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage) override;
private:
ImageProcessing_ErrorCode CheckParameter();
int LevelTransfer(int level, const std::unordered_map<int, int> levelMap) const;
mutable std::mutex lock_{};
// Guarded by lock_ begin
std::atomic<bool> isInitialized_{false};
std::shared_ptr<DetailEnhancerImage> detailEnhancer_{};
// Guarded by lock_ end
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // DETAIL_ENHANCER_IMAGE_NATIVE_H
@@ -0,0 +1,110 @@
/*
* 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 "image_environment_native.h"
#include "image_processing_utils.h"
#include "video_processing_client.h"
#include "vpe_log.h"
using namespace OHOS::Media::VideoProcessingEngine;
ImageEnvironmentNative& ImageEnvironmentNative::Get()
{
static ImageEnvironmentNative instance{};
return instance;
}
ImageProcessing_ErrorCode ImageEnvironmentNative::Initialize()
{
std::lock_guard<std::mutex> lock(lock_);
if (isExplicitInit_) [[unlikely]] {
VPE_LOGE("Repeated initialization of the image environment!");
return IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
}
isExplicitInit_ = true;
return InitializeLocked();
}
ImageProcessing_ErrorCode ImageEnvironmentNative::Deinitialize()
{
std::lock_guard<std::mutex> lock(lock_);
if (!isExplicitInit_) [[unlikely]] {
VPE_LOGE("Repeated deinitialization of the image environment!");
return IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
}
isExplicitInit_ = false;
return DeinitializeLocked();
}
ImageProcessing_ErrorCode ImageEnvironmentNative::InitializeByDefault()
{
std::lock_guard<std::mutex> lock(lock_);
return InitializeLocked();
}
ImageProcessing_ErrorCode ImageEnvironmentNative::DeinitializeByDefault()
{
std::lock_guard<std::mutex> lock(lock_);
return DeinitializeLocked();
}
ImageProcessing_ErrorCode ImageEnvironmentNative::InitializeLocked()
{
if (referenceCount_ > 0) [[likely]] {
VPE_LOGD("already init(cnt:%{public}d)", referenceCount_);
referenceCount_++;
return IMAGE_PROCESSING_SUCCESS;
}
VPE_LOGD("start to initialize...");
ImageProcessing_ErrorCode result = InitializeEnvLocked();
VPE_LOGD("initialize ret:%{public}s", ImageProcessingUtils::ToString(result).c_str());
if (result == IMAGE_PROCESSING_SUCCESS) [[likely]] {
referenceCount_++;
}
return result;
}
ImageProcessing_ErrorCode ImageEnvironmentNative::DeinitializeLocked()
{
if (referenceCount_ > 1) [[likely]] {
VPE_LOGD("environment is still in use(cnt:%{public}d)", referenceCount_);
referenceCount_--;
return IMAGE_PROCESSING_SUCCESS;
}
VPE_LOGD("start to deinitialize...");
ImageProcessing_ErrorCode result = DeinitializeEnvLocked();
VPE_LOGD("deinitialize ret:%{public}s", ImageProcessingUtils::ToString(result).c_str());
if (result == IMAGE_PROCESSING_SUCCESS) [[likely]] {
if (referenceCount_ <= 0) {
VPE_LOGE("referenceCount_ is less than 1, no need to deinitialize");
return IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
}
referenceCount_--;
}
return result;
}
ImageProcessing_ErrorCode ImageEnvironmentNative::InitializeEnvLocked()
{
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Connect();
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageEnvironmentNative::DeinitializeEnvLocked()
{
OHOS::Media::VideoProcessingEngine::VideoProcessingManager::GetInstance().Disconnect();
return IMAGE_PROCESSING_SUCCESS;
}
@@ -0,0 +1,382 @@
/*
* 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 "image_processing_capi_impl.h"
#include "vpe_log.h"
#include "image_environment_native.h"
#include "image_processing_impl.h"
using namespace OHOS::Media::VideoProcessingEngine;
const int32_t IMAGE_PROCESSING_TYPE_COLOR_SPACE_CONVERSION = 0x1;
const int32_t IMAGE_PROCESSING_TYPE_COMPOSITION = 0x2;
const int32_t IMAGE_PROCESSING_TYPE_DECOMPOSITION = 0x4;
const int32_t IMAGE_PROCESSING_TYPE_METADATA_GENERATION = 0x8;
const int32_t IMAGE_PROCESSING_TYPE_DETAIL_ENHANCER = 0x10;
const char* IMAGE_DETAIL_ENHANCER_PARAMETER_KEY_QUALITY_LEVEL = "QualityLevel";
namespace {
ImageProcessing_ErrorCode CallImageProcessing(OH_ImageProcessing* imageProcessor,
std::function<ImageProcessing_ErrorCode(std::shared_ptr<IImageProcessingNative>&)>&& operation)
{
CHECK_AND_RETURN_RET_LOG(imageProcessor != nullptr, IMAGE_PROCESSING_ERROR_INVALID_INSTANCE,
"imageProcessor is null!");
auto imageProcessing = imageProcessor->GetImageProcessing();
CHECK_AND_RETURN_RET_LOG(imageProcessing != nullptr, IMAGE_PROCESSING_ERROR_INVALID_INSTANCE,
"imageProcessor is invalid!");
return operation(imageProcessing);
}
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::OpenCLInit()
{
void *OpenclFoundationHandle = nullptr;
std::string path = "/sys_prod/lib64/VideoProcessingEngine/libaihdr_engine.so";
auto ret = access(path.c_str(), F_OK);
if (ret != 0) {
VPE_LOGW("access = %d path = %s", ret, path.c_str());
} else {
constexpr int DEVICE_NAME_LENGTH = 32; // 32 max name length
char deviceName[DEVICE_NAME_LENGTH];
auto status = SetupOpencl(&OpenclFoundationHandle, "HUA", deviceName);
CHECK_AND_RETURN_RET_LOG(status == static_cast<int>(IMAGE_PROCESSING_SUCCESS),
IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"GetOpenCLContext SetupOpencl fail!");
}
openclContext_ = reinterpret_cast<ClContext *>(OpenclFoundationHandle);
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::OpenGLInit()
{
auto status = SetupOpengl(openglContext_);
CHECK_AND_RETURN_RET_LOG(status == static_cast<int>(IMAGE_PROCESSING_SUCCESS),
IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"OpenGLInit SetupOpengl fail!");
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::InitializeEnvironment()
{
CHECK_AND_RETURN_RET_LOG(OpenCLInit() == IMAGE_PROCESSING_SUCCESS, IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"OpenCLInit failed!");
CHECK_AND_RETURN_RET_LOG(OpenGLInit() == IMAGE_PROCESSING_SUCCESS, IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"OpenGLInit failed!");
return ImageEnvironmentNative::Get().Initialize();
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::DeinitializeEnvironment()
{
return ImageEnvironmentNative::Get().Deinitialize();
}
void ImageProcessingCapiImpl::LoadLibrary()
{
std::lock_guard<std::mutex> lock(lock_);
if (usedInstance_ == 0 && mLibHandle == nullptr) {
std::string path = "libvideoprocessingengine.z.so";
mLibHandle = dlopen(path.c_str(), RTLD_NOW);
}
usedInstance_++;
}
void ImageProcessingCapiImpl::UnloadLibrary()
{
std::lock_guard<std::mutex> lock(lock_);
usedInstance_--;
if ((usedInstance_ == 0) && (mLibHandle != nullptr)) {
dlclose(mLibHandle);
mLibHandle = nullptr;
}
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::LoadAlgo()
{
CHECK_AND_RETURN_RET_LOG(mLibHandle != nullptr, IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"Library is nullptr!");
std::pair<std::string, LibFunction&> funcs[] = {
{ "ImageProcessing_IsColorSpaceConversionSupported", isColorSpaceConversionSupported_},
{ "ImageProcessing_IsCompositionSupported", isCompositionSupported_ },
{ "ImageProcessing_IsDecompositionSupported", isDecompositionSupported_ },
};
for (auto& func : funcs) {
func.second = reinterpret_cast<LibFunction>(dlsym(mLibHandle, func.first.c_str()));
CHECK_AND_RETURN_RET_LOG(func.second != nullptr, IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"Failed to locate %s in - %s", func.first.c_str(), dlerror());
}
isMetadataGenSupported_ = reinterpret_cast<LibMetaFunction>(dlsym(mLibHandle,
"ImageProcessing_IsMetadataGenerationSupported"));
CHECK_AND_RETURN_RET_LOG(isMetadataGenSupported_ != nullptr, IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING,
"Failed to locate %s in - %s", "ImageProcessing_IsMetadataGenerationSupported",
dlerror());
return IMAGE_PROCESSING_SUCCESS;
}
bool ImageProcessingCapiImpl::CheckColorSpaceConversionSupport(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo)
{
CHECK_AND_RETURN_RET_LOG(sourceImageInfo != nullptr, false, "sourceImageInfo is nullptr!");
CHECK_AND_RETURN_RET_LOG(destinationImageInfo != nullptr, false, "destinationImageInfo is nullptr!");
auto status = LoadAlgo();
CHECK_AND_RETURN_RET_LOG(status == IMAGE_PROCESSING_SUCCESS, false, "LoadAlgo faild");
OHOS::Media::VideoProcessingEngine::ColorSpaceInfo inputInfo;
OHOS::Media::VideoProcessingEngine::ColorSpaceInfo outputInfo;
auto iterPixelFormat = IMAGE_FORMAT_MAP.find(static_cast<OHOS::Media::PixelFormat>(sourceImageInfo->pixelFormat));
CHECK_AND_RETURN_RET_LOG(iterPixelFormat != IMAGE_FORMAT_MAP.end(), false, "src IMAGE_FORMAT_MAP find failed!");
inputInfo.pixelFormat = iterPixelFormat->second;
iterPixelFormat = IMAGE_FORMAT_MAP.find(static_cast<OHOS::Media::PixelFormat>(destinationImageInfo->pixelFormat));
CHECK_AND_RETURN_RET_LOG(iterPixelFormat != IMAGE_FORMAT_MAP.end(), false, "dst IMAGE_FORMAT_MAP find failed!");
outputInfo.pixelFormat = iterPixelFormat->second;
auto iterMetadataType = HDR_METADATA_TYPE_MAP.find(static_cast<ImagePixelmapHdrMetadataType>(
sourceImageInfo->metadataType));
CHECK_AND_RETURN_RET_LOG(iterMetadataType != HDR_METADATA_TYPE_MAP.end(), false,
"src HDR_METADATA_TYPE_MAP find failed!");
inputInfo.metadataType = iterMetadataType->second;
iterMetadataType = HDR_METADATA_TYPE_MAP.find(static_cast<ImagePixelmapHdrMetadataType>(
destinationImageInfo->metadataType));
CHECK_AND_RETURN_RET_LOG(iterMetadataType != HDR_METADATA_TYPE_MAP.end(), false,
"dst HDR_METADATA_TYPE_MAP find failed!");
outputInfo.metadataType = iterMetadataType->second;
auto iterColorSpace = COLORSPACE_MAP.find(static_cast<ImagePixelmapColorspace>(sourceImageInfo->colorSpace));
CHECK_AND_RETURN_RET_LOG(iterColorSpace != COLORSPACE_MAP.end(), false, "dst colorSpace find failed!");
inputInfo.colorSpace = iterColorSpace->second;
iterColorSpace = COLORSPACE_MAP.find(static_cast<ImagePixelmapColorspace>(destinationImageInfo->colorSpace));
CHECK_AND_RETURN_RET_LOG(iterColorSpace != COLORSPACE_MAP.end(), false, "dst colorSpace find failed!");
outputInfo.colorSpace = iterColorSpace->second;
return isColorSpaceConversionSupported_(inputInfo, outputInfo);
}
bool ImageProcessingCapiImpl::CheckCompositionSupport(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* sourceGainmapInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo)
{
CHECK_AND_RETURN_RET_LOG(sourceImageInfo != nullptr, false, "sourceImageInfo is nullptr!");
CHECK_AND_RETURN_RET_LOG(destinationImageInfo != nullptr, false, "destinationImageInfo is nullptr!");
CHECK_AND_RETURN_RET_LOG(sourceGainmapInfo != nullptr, false, "sourceGainmapInfo is nullptr!");
auto status = LoadAlgo();
CHECK_AND_RETURN_RET_LOG(status == IMAGE_PROCESSING_SUCCESS, false, "LoadAlgo faild");
OHOS::Media::VideoProcessingEngine::ColorSpaceInfo inputInfo;
OHOS::Media::VideoProcessingEngine::ColorSpaceInfo outputInfo;
auto iterPixelFormat = IMAGE_FORMAT_MAP.find(static_cast<OHOS::Media::PixelFormat>(sourceImageInfo->pixelFormat));
CHECK_AND_RETURN_RET_LOG(iterPixelFormat != IMAGE_FORMAT_MAP.end(), false, "src IMAGE_FORMAT_MAP find failed!");
inputInfo.pixelFormat = iterPixelFormat->second;
iterPixelFormat = IMAGE_FORMAT_MAP.find(static_cast<OHOS::Media::PixelFormat>(destinationImageInfo->pixelFormat));
CHECK_AND_RETURN_RET_LOG(iterPixelFormat != IMAGE_FORMAT_MAP.end(), false, "dst IMAGE_FORMAT_MAP find failed!");
outputInfo.pixelFormat = iterPixelFormat->second;
auto iterMetadataType = HDR_METADATA_TYPE_MAP.find(static_cast<ImagePixelmapHdrMetadataType>(
sourceImageInfo->metadataType));
CHECK_AND_RETURN_RET_LOG(iterMetadataType != HDR_METADATA_TYPE_MAP.end(), false,
"src HDR_METADATA_TYPE_MAP find failed!");
inputInfo.metadataType = iterMetadataType->second;
iterMetadataType = HDR_METADATA_TYPE_MAP.find(static_cast<ImagePixelmapHdrMetadataType>(
destinationImageInfo->metadataType));
CHECK_AND_RETURN_RET_LOG(iterMetadataType != HDR_METADATA_TYPE_MAP.end(), false,
"dst HDR_METADATA_TYPE_MAP find failed!");
outputInfo.metadataType = iterMetadataType->second;
auto iterColorSpace = COLORSPACE_MAP.find(static_cast<ImagePixelmapColorspace>(sourceImageInfo->colorSpace));
CHECK_AND_RETURN_RET_LOG(iterColorSpace != COLORSPACE_MAP.end(), false, "dst colorSpace find failed!");
inputInfo.colorSpace = iterColorSpace->second;
iterColorSpace = COLORSPACE_MAP.find(static_cast<ImagePixelmapColorspace>(destinationImageInfo->colorSpace));
CHECK_AND_RETURN_RET_LOG(iterColorSpace != COLORSPACE_MAP.end(), false, "dst colorSpace find failed!");
outputInfo.colorSpace = iterColorSpace->second;
return isCompositionSupported_(inputInfo, outputInfo);
}
bool ImageProcessingCapiImpl::CheckDecompositionSupport(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationGainmapInfo)
{
CHECK_AND_RETURN_RET_LOG(sourceImageInfo != nullptr, false, "sourceImageInfo is nullptr!");
CHECK_AND_RETURN_RET_LOG(destinationImageInfo != nullptr, false, "destinationImageInfo is nullptr!");
CHECK_AND_RETURN_RET_LOG(destinationGainmapInfo != nullptr, false, "destinationGainmapInfo is nullptr!");
auto status = LoadAlgo();
CHECK_AND_RETURN_RET_LOG(status == IMAGE_PROCESSING_SUCCESS, false, "LoadAlgo faild");
OHOS::Media::VideoProcessingEngine::ColorSpaceInfo inputInfo;
OHOS::Media::VideoProcessingEngine::ColorSpaceInfo outputInfo;
auto iterPixelFormat = IMAGE_FORMAT_MAP.find(static_cast<OHOS::Media::PixelFormat>(sourceImageInfo->pixelFormat));
CHECK_AND_RETURN_RET_LOG(iterPixelFormat != IMAGE_FORMAT_MAP.end(), false, "src IMAGE_FORMAT_MAP find failed!");
inputInfo.pixelFormat = iterPixelFormat->second;
iterPixelFormat = IMAGE_FORMAT_MAP.find(static_cast<OHOS::Media::PixelFormat>(destinationImageInfo->pixelFormat));
CHECK_AND_RETURN_RET_LOG(iterPixelFormat != IMAGE_FORMAT_MAP.end(), false, "dst IMAGE_FORMAT_MAP find failed!");
outputInfo.pixelFormat = iterPixelFormat->second;
auto iterMetadataType = HDR_METADATA_TYPE_MAP.find(static_cast<ImagePixelmapHdrMetadataType>(
sourceImageInfo->metadataType));
CHECK_AND_RETURN_RET_LOG(iterMetadataType != HDR_METADATA_TYPE_MAP.end(), false,
"src HDR_METADATA_TYPE_MAP find failed!");
inputInfo.metadataType = iterMetadataType->second;
iterMetadataType = HDR_METADATA_TYPE_MAP.find(static_cast<ImagePixelmapHdrMetadataType>(
destinationImageInfo->metadataType));
CHECK_AND_RETURN_RET_LOG(iterMetadataType != HDR_METADATA_TYPE_MAP.end(), false,
"dst HDR_METADATA_TYPE_MAP find failed!");
outputInfo.metadataType = iterMetadataType->second;
auto iterColorSpace = COLORSPACE_MAP.find(static_cast<ImagePixelmapColorspace>(sourceImageInfo->colorSpace));
CHECK_AND_RETURN_RET_LOG(iterColorSpace != COLORSPACE_MAP.end(), false, "src colorSpace find failed!");
inputInfo.colorSpace = iterColorSpace->second;
iterColorSpace = COLORSPACE_MAP.find(static_cast<ImagePixelmapColorspace>(destinationImageInfo->colorSpace));
CHECK_AND_RETURN_RET_LOG(iterColorSpace != COLORSPACE_MAP.end(), false, "dst colorSpace find failed!");
outputInfo.colorSpace = iterColorSpace->second;
return isDecompositionSupported_(inputInfo, outputInfo);
}
bool ImageProcessingCapiImpl::CheckMetadataGenerationSupport(const ImageProcessing_ColorSpaceInfo* sourceImageInfo)
{
CHECK_AND_RETURN_RET_LOG(sourceImageInfo != nullptr, false, "sourceImageInfo is nullptr!");
auto status = LoadAlgo();
CHECK_AND_RETURN_RET_LOG(status == IMAGE_PROCESSING_SUCCESS, false, "LoadAlgo faild");
OHOS::Media::VideoProcessingEngine::ColorSpaceInfo inputInfo;
auto iterPixelFormat = IMAGE_FORMAT_MAP.find(static_cast<OHOS::Media::PixelFormat>(sourceImageInfo->pixelFormat));
CHECK_AND_RETURN_RET_LOG(iterPixelFormat != IMAGE_FORMAT_MAP.end(), false, "src IMAGE_FORMAT_MAP find failed!");
inputInfo.pixelFormat = iterPixelFormat->second;
auto iterMetadataType = HDR_METADATA_TYPE_MAP.find(static_cast<ImagePixelmapHdrMetadataType>(
sourceImageInfo->metadataType));
CHECK_AND_RETURN_RET_LOG(iterMetadataType != HDR_METADATA_TYPE_MAP.end(), false,
"src HDR_METADATA_TYPE_MAP find failed!");
inputInfo.metadataType = iterMetadataType->second;
auto iterColorSpace = COLORSPACE_MAP.find(static_cast<ImagePixelmapColorspace>(sourceImageInfo->colorSpace));
CHECK_AND_RETURN_RET_LOG(iterColorSpace != COLORSPACE_MAP.end(), false, "dst colorSpace find failed!");
inputInfo.colorSpace = iterColorSpace->second;
return isMetadataGenSupported_(inputInfo);
}
bool ImageProcessingCapiImpl::IsColorSpaceConversionSupported(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo)
{
LoadLibrary();
auto flag = CheckColorSpaceConversionSupport(sourceImageInfo, destinationImageInfo);
UnloadLibrary();
return flag;
}
bool ImageProcessingCapiImpl::IsCompositionSupported(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* sourceGainmapInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo)
{
LoadLibrary();
auto flag = CheckCompositionSupport(sourceImageInfo, sourceGainmapInfo, destinationImageInfo);
UnloadLibrary();
return flag;
}
bool ImageProcessingCapiImpl::IsDecompositionSupported(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationGainmapInfo)
{
LoadLibrary();
auto flag = CheckDecompositionSupport(sourceImageInfo, destinationImageInfo, destinationGainmapInfo);
UnloadLibrary();
return flag;
}
bool ImageProcessingCapiImpl::IsMetadataGenerationSupported(const ImageProcessing_ColorSpaceInfo* sourceImageInfo)
{
LoadLibrary();
auto flag = CheckMetadataGenerationSupport(sourceImageInfo);
return flag;
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::Create(OH_ImageProcessing** imageProcessor, int type)
{
return OH_ImageProcessing::Create(imageProcessor, type, openglContext_, openclContext_);
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::Destroy(OH_ImageProcessing* imageProcessor)
{
return OH_ImageProcessing::Destroy(imageProcessor);
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::SetParameter(OH_ImageProcessing* imageProcessor,
const OH_AVFormat* parameter)
{
return CallImageProcessing(imageProcessor, [&parameter](std::shared_ptr<IImageProcessingNative>& obj) {
return obj->SetParameter(parameter);
});
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::GetParameter(OH_ImageProcessing* imageProcessor,
OH_AVFormat* parameter)
{
return CallImageProcessing(imageProcessor, [&parameter](std::shared_ptr<IImageProcessingNative>& obj) {
return obj->GetParameter(parameter);
});
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::ConvertColorSpace(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage)
{
return CallImageProcessing(imageProcessor, [&sourceImage, &destinationImage](
std::shared_ptr<IImageProcessingNative>& obj) {
return obj->ConvertColorSpace(sourceImage, destinationImage);
});
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::Compose(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage, OH_PixelmapNative* sourceGainmap, OH_PixelmapNative* destinationImage)
{
return CallImageProcessing(imageProcessor, [&sourceImage, &sourceGainmap, &destinationImage](
std::shared_ptr<IImageProcessingNative>& obj) {
return obj->Compose(sourceImage, sourceGainmap, destinationImage);
});
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::Decompose(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage,
OH_PixelmapNative* destinationGainmap)
{
return CallImageProcessing(imageProcessor, [&sourceImage, &destinationImage, &destinationGainmap](
std::shared_ptr<IImageProcessingNative>& obj) {
return obj->Decompose(sourceImage, destinationImage, destinationGainmap);
});
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::GenerateMetadata(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage)
{
return CallImageProcessing(imageProcessor, [&sourceImage](
std::shared_ptr<IImageProcessingNative>& obj) {
return obj->GenerateMetadata(sourceImage);
});
}
ImageProcessing_ErrorCode ImageProcessingCapiImpl::EnhanceDetail(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage)
{
return CallImageProcessing(imageProcessor, [&sourceImage, &destinationImage](
std::shared_ptr<IImageProcessingNative>& obj) {
return obj->Process(sourceImage, destinationImage);
});
}
IImageProcessingNdk* CreateImageProcessingNdk()
{
return new(std::nothrow) ImageProcessingCapiImpl();
}
void DestroyImageProcessingNdk(IImageProcessingNdk* obj)
{
CHECK_AND_RETURN_LOG(obj != nullptr, "VPE image processing is null!");
ImageProcessingCapiImpl* impl = static_cast<ImageProcessingCapiImpl*>(obj);
delete impl;
}
@@ -0,0 +1,61 @@
/*
* 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 "image_processing_factory.h"
#include <functional>
#include <unordered_map>
#include "vpe_log.h"
#include "image_processing_native_template.h"
#include "metadata_generator_image_native.h"
#include "detail_enhancer_image_native.h"
#include "colorspace_converter_image_native.h"
using namespace OHOS::Media::VideoProcessingEngine;
namespace {
template <typename T>
std::shared_ptr<IImageProcessingNative> Create()
{
return ImageProcessingNativeTemplate<T>::Create();
}
// NOTE: Add VPE feature type like below.
// VPE feature map begin
const std::unordered_map<int, std::function<std::shared_ptr<IImageProcessingNative>()>> CREATORS = {
{ IMAGE_PROCESSING_TYPE_DETAIL_ENHANCER, Create<DetailEnhancerImageNative> },
{ IMAGE_PROCESSING_TYPE_COLOR_SPACE_CONVERSION, Create<ColorspaceConverterImageNative> },
{ IMAGE_PROCESSING_TYPE_COMPOSITION, Create<ColorspaceConverterImageNative> },
{ IMAGE_PROCESSING_TYPE_DECOMPOSITION, Create<ColorspaceConverterImageNative> },
{ IMAGE_PROCESSING_TYPE_METADATA_GENERATION, Create<MetadataGeneratorImageNative> },
// ...
};
// VPE feature map end
}
bool ImageProcessingFactory::IsValid(int type)
{
return CREATORS.find(type) != CREATORS.end();
}
std::shared_ptr<IImageProcessingNative> ImageProcessingFactory::CreateImageProcessing(int type)
{
auto it = CREATORS.find(type);
if (it == CREATORS.end()) {
VPE_LOGE("Unknown type:%{public}d!", type);
return nullptr;
}
return it->second();
}
@@ -0,0 +1,69 @@
/*
* 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 "image_processing_impl.h"
#include "image_processing_factory.h"
#include "vpe_log.h"
using namespace OHOS::Media::VideoProcessingEngine;
ImageProcessing_ErrorCode OH_ImageProcessing::Create(OH_ImageProcessing** instance, int type,
std::shared_ptr<OpenGLContext> openglContext,
ClContext *openclContext)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr && *instance == nullptr, IMAGE_PROCESSING_ERROR_INVALID_INSTANCE,
"VPE image processing instance is null or *instance is not null!");
CHECK_AND_RETURN_RET_LOG(ImageProcessingFactory::IsValid(type), IMAGE_PROCESSING_ERROR_INVALID_PARAMETER,
"VPE image processing type(%{public}d) is invalid!", type);
*instance = new(std::nothrow) OH_ImageProcessing(type);
CHECK_AND_RETURN_RET_LOG(*instance != nullptr, IMAGE_PROCESSING_ERROR_NO_MEMORY,
"VPE image processing out of memory!");
auto obj = (*instance)->GetImageProcessing();
CHECK_AND_RETURN_RET_LOG(obj != nullptr, IMAGE_PROCESSING_ERROR_CREATE_FAILED,
"VPE image processing constructor failed!");
obj->opengclContext_ = openclContext;
obj->openglContext_ = openglContext;
return obj->Initialize();
}
ImageProcessing_ErrorCode OH_ImageProcessing::Destroy(OH_ImageProcessing* instance)
{
CHECK_AND_RETURN_RET_LOG(instance != nullptr, IMAGE_PROCESSING_ERROR_INVALID_INSTANCE,
"VPE image processing instance is null!");
auto obj = instance->GetImageProcessing();
CHECK_AND_RETURN_RET_LOG(obj != nullptr, IMAGE_PROCESSING_ERROR_INVALID_PARAMETER,
"VPE image processing instance is empty!");
auto errorCode = obj->Deinitialize();
delete instance;
instance = nullptr;
return errorCode;
}
OH_ImageProcessing::OH_ImageProcessing(int type)
{
imageProcessing_ = ImageProcessingFactory::CreateImageProcessing(type);
}
OH_ImageProcessing::~OH_ImageProcessing()
{
imageProcessing_ = nullptr;
}
std::shared_ptr<IImageProcessingNative> OH_ImageProcessing::GetImageProcessing()
{
return imageProcessing_;
}
@@ -0,0 +1,182 @@
/*
* 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 "image_processing_native_base.h"
#include "common/native_mfmagic.h"
#include "pixelmap_native_impl.h"
#include "image_environment_native.h"
#include "vpe_log.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
ImageProcessingNativeBase::ImageProcessingNativeBase()
{
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Initialize()
{
CHECK_AND_RETURN_RET_LOG(!isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already init!");
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(!isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already init!");
auto result = InitializeInner();
isInitialized_ = true;
return result;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Deinitialize()
{
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already deinit!");
std::lock_guard<std::mutex> lock(lock_);
CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
"Already deinit!");
auto result = DeinitializeInner();
isInitialized_ = false;
return result;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::SetParameter(const OH_AVFormat* parameter)
{
CHECK_AND_RETURN_RET_LOG(parameter != nullptr, IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
return SetParameter(parameter->format_);
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::GetParameter(OH_AVFormat* parameter)
{
CHECK_AND_RETURN_RET_LOG(parameter != nullptr, IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
return GetParameter(parameter->format_);
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Process(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage)
{
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
auto destPixelmap = destinationImage->GetInnerPixelmap();
auto sourePixelmap = sourceImage->GetInnerPixelmap();
return Process(sourePixelmap, destPixelmap);
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::ConvertColorSpace(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage)
{
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
auto destPixelmap = destinationImage->GetInnerPixelmap();
return ConvertColorSpace(sourceImage->GetInnerPixelmap(), destPixelmap);
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Compose(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* sourceGainmap, OH_PixelmapNative* destinationImage)
{
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr && sourceGainmap != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
auto destPixelmap = destinationImage->GetInnerPixelmap();
return Compose(sourceImage->GetInnerPixelmap(), sourceGainmap->GetInnerPixelmap(), destPixelmap);
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Decompose(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage, OH_PixelmapNative* destinationGainmap)
{
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr && destinationGainmap != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
auto destPixelmap = destinationImage->GetInnerPixelmap();
auto destGainmapPixelmap = destinationGainmap->GetInnerPixelmap();
return Decompose(sourceImage->GetInnerPixelmap(), destPixelmap, destGainmapPixelmap);
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::GenerateMetadata(OH_PixelmapNative* sourceImage)
{
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
return GenerateMetadata(sourceImage->GetInnerPixelmap());
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::EnhanceDetail(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage)
{
CHECK_AND_RETURN_RET_LOG(sourceImage != nullptr && destinationImage != nullptr,
IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
auto destPixelmap = destinationImage->GetInnerPixelmap();
return EnhanceDetail(sourceImage->GetInnerPixelmap(), destPixelmap);
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::InitializeInner()
{
return ImageEnvironmentNative::Get().InitializeByDefault();
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::DeinitializeInner()
{
return ImageEnvironmentNative::Get().DeinitializeByDefault();
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::SetParameter([[maybe_unused]] const OHOS::Media::Format& parameter)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::GetParameter([[maybe_unused]] OHOS::Media::Format& parameter)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Process(
[[maybe_unused]] const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
[[maybe_unused]] std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::ConvertColorSpace(
[[maybe_unused]] const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
[[maybe_unused]] std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Compose(
[[maybe_unused]] const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
[[maybe_unused]] const std::shared_ptr<OHOS::Media::PixelMap>& sourceGainmap,
[[maybe_unused]] std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::Decompose(
[[maybe_unused]] const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
[[maybe_unused]] std::shared_ptr<OHOS::Media::PixelMap>& destinationImage,
[[maybe_unused]] std::shared_ptr<OHOS::Media::PixelMap>& destinationGainmap)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::GenerateMetadata(
[[maybe_unused]] const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
ImageProcessing_ErrorCode ImageProcessingNativeBase::EnhanceDetail(
[[maybe_unused]] const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
[[maybe_unused]] std::shared_ptr<OHOS::Media::PixelMap>& destinationImage)
{
return IMAGE_PROCESSING_SUCCESS;
}
@@ -0,0 +1,106 @@
/*
* 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 "image_processing_utils.h"
#include <unordered_map>
#include "algorithm_utils.h"
#include "surface_buffer_impl.h"
#include "surface_type.h"
#include "vpe_log.h"
#include "vpe_utils_common.h"
using namespace OHOS;
using namespace OHOS::Media::VideoProcessingEngine;
namespace {
const std::unordered_map<VPEAlgoErrCode, ImageProcessing_ErrorCode> ERROR_MAP = {
{ VPE_ALGO_ERR_OK, IMAGE_PROCESSING_SUCCESS },
{ VPE_ALGO_ERR_NO_MEMORY, IMAGE_PROCESSING_ERROR_NO_MEMORY },
{ VPE_ALGO_ERR_INVALID_OPERATION, IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED },
{ VPE_ALGO_ERR_INVALID_VAL, IMAGE_PROCESSING_ERROR_INVALID_VALUE },
{ VPE_ALGO_ERR_UNKNOWN, IMAGE_PROCESSING_ERROR_UNKNOWN },
{ VPE_ALGO_ERR_INVALID_PARAM, IMAGE_PROCESSING_ERROR_INVALID_PARAMETER },
{ VPE_ALGO_ERR_INIT_FAILED, IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED },
{ VPE_ALGO_ERR_EXTENSION_NOT_FOUND, IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING },
{ VPE_ALGO_ERR_EXTENSION_INIT_FAILED, IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED },
{ VPE_ALGO_ERR_EXTENSION_PROCESS_FAILED, IMAGE_PROCESSING_ERROR_PROCESS_FAILED },
{ VPE_ALGO_ERR_NOT_IMPLEMENTED, IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING },
{ VPE_ALGO_ERR_OPERATION_NOT_SUPPORTED, IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED },
{ VPE_ALGO_ERR_INVALID_STATE, IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED },
{ VPE_ALGO_ERR_EXTEND_START, IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED },
};
const std::unordered_map<ImageProcessing_ErrorCode, std::string> CAPI_ERROR_STR_MAP = {
{ IMAGE_PROCESSING_SUCCESS, VPE_TO_STR(IMAGE_PROCESSING_SUCCESS) },
{ IMAGE_PROCESSING_ERROR_INVALID_PARAMETER, VPE_TO_STR(IMAGE_PROCESSING_ERROR_INVALID_PARAMETER) },
{ IMAGE_PROCESSING_ERROR_UNKNOWN, VPE_TO_STR(IMAGE_PROCESSING_ERROR_UNKNOWN) },
{ IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED, VPE_TO_STR(IMAGE_PROCESSING_ERROR_INITIALIZE_FAILED) },
{ IMAGE_PROCESSING_ERROR_CREATE_FAILED, VPE_TO_STR(IMAGE_PROCESSING_ERROR_CREATE_FAILED) },
{ IMAGE_PROCESSING_ERROR_PROCESS_FAILED, VPE_TO_STR(IMAGE_PROCESSING_ERROR_PROCESS_FAILED) },
{ IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING, VPE_TO_STR(IMAGE_PROCESSING_ERROR_UNSUPPORTED_PROCESSING) },
{ IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED, VPE_TO_STR(IMAGE_PROCESSING_ERROR_OPERATION_NOT_PERMITTED) },
{ IMAGE_PROCESSING_ERROR_NO_MEMORY, VPE_TO_STR(IMAGE_PROCESSING_ERROR_NO_MEMORY) },
{ IMAGE_PROCESSING_ERROR_INVALID_INSTANCE, VPE_TO_STR(IMAGE_PROCESSING_ERROR_INVALID_INSTANCE) },
{ IMAGE_PROCESSING_ERROR_INVALID_VALUE, VPE_TO_STR(IMAGE_PROCESSING_ERROR_INVALID_VALUE) }
};
}
ImageProcessing_ErrorCode ImageProcessingUtils::InnerErrorToCAPI(VPEAlgoErrCode errorCode)
{
auto it = ERROR_MAP.find(errorCode);
if (it == ERROR_MAP.end()) [[unlikely]] {
VPE_LOGE("Invalid error code:%{public}d", errorCode);
return IMAGE_PROCESSING_ERROR_UNKNOWN;
}
return it->second;
}
std::string ImageProcessingUtils::ToString(ImageProcessing_ErrorCode errorCode)
{
auto it = CAPI_ERROR_STR_MAP.find(errorCode);
if (it == CAPI_ERROR_STR_MAP.end()) [[unlikely]] {
VPE_LOGE("Invalid error code:%{public}d", errorCode);
return "Unsupported error:" + std::to_string(static_cast<int>(errorCode));
}
return it->second;
}
sptr<SurfaceBuffer> ImageProcessingUtils::GetSurfaceBufferFromPixelMap(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
return VpeUtils::GetSurfaceBufferFromPixelMap(pixelmap);
}
ImageProcessing_ErrorCode ImageProcessingUtils::ConvertPixelmapToSurfaceBuffer(
const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap, sptr<SurfaceBuffer> bufferImpl)
{
return VpeUtils::ConvertPixelmapToSurfaceBuffer(pixelmap, bufferImpl) ?
IMAGE_PROCESSING_SUCCESS : IMAGE_PROCESSING_ERROR_PROCESS_FAILED;
}
ImageProcessing_ErrorCode ImageProcessingUtils::ConvertSurfaceBufferToPixelmap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
return VpeUtils::ConvertSurfaceBufferToPixelmap(buffer, pixelmap) ?
IMAGE_PROCESSING_SUCCESS : IMAGE_PROCESSING_ERROR_PROCESS_FAILED;
}
ImageProcessing_ErrorCode ImageProcessingUtils::SetSurfaceBufferToPixelMap(const sptr<SurfaceBuffer>& buffer,
std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
{
return VpeUtils::SetSurfaceBufferToPixelMap(buffer, pixelmap) ?
IMAGE_PROCESSING_SUCCESS : IMAGE_PROCESSING_ERROR_PROCESS_FAILED;
}
@@ -0,0 +1,59 @@
/*
* 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 IMAGE_ENVIRONMENT_NATIVE_H
#define IMAGE_ENVIRONMENT_NATIVE_H
#include <cinttypes>
#include <mutex>
#include "image_processing_types.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class ImageEnvironmentNative {
public:
static ImageEnvironmentNative& Get();
ImageProcessing_ErrorCode Initialize();
ImageProcessing_ErrorCode Deinitialize();
ImageProcessing_ErrorCode InitializeByDefault();
ImageProcessing_ErrorCode DeinitializeByDefault();
private:
ImageEnvironmentNative() = default;
virtual ~ImageEnvironmentNative() = default;
ImageEnvironmentNative(const ImageEnvironmentNative&) = delete;
ImageEnvironmentNative& operator=(const ImageEnvironmentNative&) = delete;
ImageEnvironmentNative(ImageEnvironmentNative&&) = delete;
ImageEnvironmentNative& operator=(ImageEnvironmentNative&&) = delete;
ImageProcessing_ErrorCode InitializeLocked();
ImageProcessing_ErrorCode DeinitializeLocked();
ImageProcessing_ErrorCode InitializeEnvLocked();
ImageProcessing_ErrorCode DeinitializeEnvLocked();
std::mutex lock_{};
// Guarded by lock_ begin
bool isExplicitInit_{};
uint32_t referenceCount_{};
// Guarded by lock_ end
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // IMAGE_ENVIRONMENT_NATIVE_H
@@ -0,0 +1,164 @@
/*
* 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 IMAGE_PROCESSING_CAPI_IMPL_H
#define IMAGE_PROCESSING_CAPI_IMPL_H
#include "image_processing_capi_interface.h"
#include "frame_info.h"
#include <dlfcn.h>
#include <atomic>
#include <functional>
#include <mutex>
#include "image_processing_native_template.h"
#include "image_processing_types.h"
#include "pixelmap_native_impl.h"
#include "detail_enhancer_image.h"
#include "colorspace_converter.h"
#include "colorspace_converter_image_native.h"
#include <unordered_map>
#include "detail_enhancer_common.h"
#include "detail_enhancer_image_fwk.h"
#include "image_processing_utils.h"
#include "surface_buffer.h"
#include "surface_buffer_impl.h"
#include "surface_type.h"
#include "vpe_log.h"
const std::map<OHOS::Media::PixelFormat, OHOS::GraphicPixelFormat> IMAGE_FORMAT_MAP = {
{ OHOS::Media::PixelFormat::RGBA_8888, OHOS::GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888 },
{ OHOS::Media::PixelFormat::BGRA_8888, OHOS::GraphicPixelFormat::GRAPHIC_PIXEL_FMT_BGRA_8888 },
{ OHOS::Media::PixelFormat::RGBA_1010102, OHOS::GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_1010102 },
{ OHOS::Media::PixelFormat::YCBCR_P010, OHOS::GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_P010 },
{ OHOS::Media::PixelFormat::YCRCB_P010, OHOS::GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCRCB_P010 },
};
typedef enum {
NONE = 0,
BASE = 1,
GAINMAP = 2,
ALTERNATE = 3,
} ImagePixelmapHdrMetadataType;
const std::map<ImagePixelmapHdrMetadataType,
OHOS::HDI::Display::Graphic::Common::V1_0::CM_HDR_Metadata_Type> HDR_METADATA_TYPE_MAP = {
{ NONE, OHOS::HDI::Display::Graphic::Common::V1_0::CM_METADATA_NONE },
{ BASE, OHOS::HDI::Display::Graphic::Common::V1_0::CM_IMAGE_HDR_VIVID_DUAL },
{ GAINMAP, OHOS::HDI::Display::Graphic::Common::V1_0::CM_IMAGE_HDR_VIVID_DUAL },
{ ALTERNATE, OHOS::HDI::Display::Graphic::Common::V1_0::CM_IMAGE_HDR_VIVID_SINGLE },
};
typedef enum {
UNKNOWN = 0,
ADOBE_RGB_1998 = 1,
DCI_P3 = 2,
DISPLAY_P3 = 3,
SRGB = 4,
BT709 = 5,
BT601_EBU = 6,
BT2020_HLG = 9,
BT2020_PQ = 10,
P3_HLG = 11,
DISPLAY_P3_LIMIT = 14,
SRGB_LIMIT = 15,
BT2020_HLG_LIMIT = 19,
BT2020_PQ_LIMIT = 20,
} ImagePixelmapColorspace;
const std::map<ImagePixelmapColorspace, OHOS::HDI::Display::Graphic::Common::V1_0::CM_ColorSpaceType> COLORSPACE_MAP = {
{ SRGB, OHOS::HDI::Display::Graphic::Common::V1_0::CM_SRGB_FULL },
{ SRGB_LIMIT, OHOS::HDI::Display::Graphic::Common::V1_0::CM_SRGB_LIMIT },
{ DISPLAY_P3, OHOS::HDI::Display::Graphic::Common::V1_0::CM_P3_FULL },
{ DISPLAY_P3_LIMIT, OHOS::HDI::Display::Graphic::Common::V1_0::CM_P3_LIMIT },
{ BT2020_HLG, OHOS::HDI::Display::Graphic::Common::V1_0::CM_BT2020_HLG_FULL },
{ BT2020_HLG_LIMIT, OHOS::HDI::Display::Graphic::Common::V1_0::CM_BT2020_HLG_LIMIT },
{ BT2020_PQ, OHOS::HDI::Display::Graphic::Common::V1_0::CM_BT2020_PQ_FULL },
{ BT2020_PQ_LIMIT, OHOS::HDI::Display::Graphic::Common::V1_0::CM_BT2020_PQ_LIMIT },
{ P3_HLG, OHOS::HDI::Display::Graphic::Common::V1_0::CM_P3_HLG_LIMIT },
{ ADOBE_RGB_1998, OHOS::HDI::Display::Graphic::Common::V1_0::CM_ADOBERGB_FULL },
};
class ImageProcessingCapiImpl : public IImageProcessingNdk {
public:
ImageProcessingCapiImpl() = default;
virtual ~ImageProcessingCapiImpl() = default;
ImageProcessingCapiImpl(const ImageProcessingCapiImpl&) = delete;
ImageProcessingCapiImpl& operator=(const ImageProcessingCapiImpl&) = delete;
ImageProcessingCapiImpl(ImageProcessingCapiImpl&&) = delete;
ImageProcessingCapiImpl& operator=(ImageProcessingCapiImpl&&) = delete;
ImageProcessing_ErrorCode InitializeEnvironment() final;
ImageProcessing_ErrorCode DeinitializeEnvironment() final;
bool IsColorSpaceConversionSupported(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo) final;
bool IsCompositionSupported(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* sourceGainmapInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo) final;
bool IsDecompositionSupported(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationGainmapInfo) final;
bool IsMetadataGenerationSupported(const ImageProcessing_ColorSpaceInfo* sourceImageInfo) final;
ImageProcessing_ErrorCode Create(OH_ImageProcessing** imageProcessor, int32_t type) final;
ImageProcessing_ErrorCode Destroy(OH_ImageProcessing* imageProcessor) final;
ImageProcessing_ErrorCode SetParameter(OH_ImageProcessing* imageProcessor,
const OH_AVFormat* parameter) final;
ImageProcessing_ErrorCode GetParameter(OH_ImageProcessing* imageProcessor, OH_AVFormat* parameter) final;
ImageProcessing_ErrorCode ConvertColorSpace(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage) final;
ImageProcessing_ErrorCode Compose(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage, OH_PixelmapNative* sourceGainmap, OH_PixelmapNative* destinationImage) final;
ImageProcessing_ErrorCode Decompose(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage,
OH_PixelmapNative* destinationGainmap) final;
ImageProcessing_ErrorCode GenerateMetadata(OH_ImageProcessing* imageProcessor,
OH_PixelmapNative* sourceImage) final;
ImageProcessing_ErrorCode EnhanceDetail(OH_ImageProcessing* imageProcessor, OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage) final;
private:
ImageProcessing_ErrorCode LoadAlgo();
void LoadLibrary();
void UnloadLibrary();
bool CheckColorSpaceConversionSupport(
const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo);
bool CheckCompositionSupport(const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* sourceGainmapInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo);
bool CheckDecompositionSupport(const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationImageInfo,
const ImageProcessing_ColorSpaceInfo* destinationGainmapInfo);
bool CheckMetadataGenerationSupport(const ImageProcessing_ColorSpaceInfo* sourceImageInfo);
void* mLibHandle{};
using LibFunction = bool (*)(const OHOS::Media::VideoProcessingEngine::ColorSpaceInfo inputInfo,
const OHOS::Media::VideoProcessingEngine::ColorSpaceInfo outputInfo);
using LibMetaFunction = bool (*)(const OHOS::Media::VideoProcessingEngine::ColorSpaceInfo inputInfo);
LibFunction isColorSpaceConversionSupported_{nullptr};
LibFunction isCompositionSupported_{nullptr};
LibFunction isDecompositionSupported_{nullptr};
LibMetaFunction isMetadataGenSupported_{nullptr};
std::mutex lock_;
int32_t usedInstance_ { 0 };
ClContext *openclContext_ {nullptr};
ImageProcessing_ErrorCode OpenCLInit();
std::shared_ptr<OpenGLContext> openglContext_ {nullptr};
ImageProcessing_ErrorCode OpenGLInit();
};
extern "C" IImageProcessingNdk* CreateImageProcessingNdk();
extern "C" void DestroyImageProcessingNdk(IImageProcessingNdk* obj);
#endif // IMAGE_PROCESSING_CAPI_IMPL_H
@@ -0,0 +1,38 @@
/*
* 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 IMAGE_PROCESSING_FACTORY_H
#define IMAGE_PROCESSING_FACTORY_H
#include <memory>
#include "image_processing_interface.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
/**
* Factory class for creating image processing object.
*/
class ImageProcessingFactory {
public:
static bool IsValid(int type);
static std::shared_ptr<IImageProcessingNative> CreateImageProcessing(int type);
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // IMAGE_PROCESSING_FACTORY_H
@@ -0,0 +1,39 @@
/*
* 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 IMAGE_PROCESSING_IMPL_H
#define IMAGE_PROCESSING_IMPL_H
#include <memory>
#include "image_processing_interface.h"
struct OH_ImageProcessing {
public:
static ImageProcessing_ErrorCode Create(OH_ImageProcessing** instance, int type,
std::shared_ptr<OpenGLContext> openglContext,
ClContext *openclContext);
static ImageProcessing_ErrorCode Destroy(OH_ImageProcessing* instance);
std::shared_ptr<OHOS::Media::VideoProcessingEngine::IImageProcessingNative> GetImageProcessing();
private:
OH_ImageProcessing(int type);
~OH_ImageProcessing();
std::shared_ptr<OHOS::Media::VideoProcessingEngine::IImageProcessingNative> imageProcessing_{};
};
#endif // IMAGE_PROCESSING_IMPL_H
@@ -0,0 +1,59 @@
/*
* 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 IMAGE_PROCESSING_INTERFACE_H
#define IMAGE_PROCESSING_INTERFACE_H
#include "image_processing_types.h"
#include "algorithm_common.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
class IImageProcessingNative {
public:
virtual ImageProcessing_ErrorCode Initialize() = 0;
virtual ImageProcessing_ErrorCode Deinitialize() = 0;
virtual ImageProcessing_ErrorCode SetParameter(const OH_AVFormat* parameter) = 0;
virtual ImageProcessing_ErrorCode GetParameter(OH_AVFormat* parameter) = 0;
virtual ImageProcessing_ErrorCode Process(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage) = 0;
virtual ImageProcessing_ErrorCode ConvertColorSpace(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage) = 0;
virtual ImageProcessing_ErrorCode Compose(OH_PixelmapNative* sourceImage, OH_PixelmapNative* sourceGainmap,
OH_PixelmapNative* destinationImage) = 0;
virtual ImageProcessing_ErrorCode Decompose(OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage,
OH_PixelmapNative* destinationGainmap) = 0;
virtual ImageProcessing_ErrorCode GenerateMetadata(OH_PixelmapNative* sourceImage) = 0;
virtual ImageProcessing_ErrorCode EnhanceDetail(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage) = 0;
protected:
IImageProcessingNative() = default;
virtual ~IImageProcessingNative() = default;
IImageProcessingNative(const IImageProcessingNative&) = delete;
IImageProcessingNative& operator=(const IImageProcessingNative&) = delete;
IImageProcessingNative(IImageProcessingNative&&) = delete;
IImageProcessingNative& operator=(IImageProcessingNative&&) = delete;
public:
ClContext *opengclContext_ {nullptr};
std::shared_ptr<OpenGLContext> openglContext_ {nullptr};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // IMAGE_PROCESSING_INTERFACE_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 IMAGE_PROCESSING_NATIVE_BASE_H
#define IMAGE_PROCESSING_NATIVE_BASE_H
#include "common/native_mfmagic.h"
#include "pixelmap_native_impl.h"
#include "pixel_map.h"
#include "image_processing_interface.h"
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
/**
* Base implementaion for image processing.
*/
class ImageProcessingNativeBase : public IImageProcessingNative {
public:
ImageProcessing_ErrorCode Initialize() final;
ImageProcessing_ErrorCode Deinitialize() final;
ImageProcessing_ErrorCode SetParameter(const OH_AVFormat* parameter) final;
ImageProcessing_ErrorCode GetParameter(OH_AVFormat* parameter) final;
ImageProcessing_ErrorCode Process(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage) final;
ImageProcessing_ErrorCode ConvertColorSpace(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage) final;
ImageProcessing_ErrorCode Compose(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* sourceGainmap, OH_PixelmapNative* destinationImage) final;
ImageProcessing_ErrorCode Decompose(OH_PixelmapNative* sourceImage,
OH_PixelmapNative* destinationImage, OH_PixelmapNative* destinationGainmap) final;
ImageProcessing_ErrorCode GenerateMetadata(OH_PixelmapNative* sourceImage) final;
ImageProcessing_ErrorCode EnhanceDetail(OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage) final;
protected:
explicit ImageProcessingNativeBase();
virtual ~ImageProcessingNativeBase() = default;
ImageProcessingNativeBase(const ImageProcessingNativeBase&) = delete;
ImageProcessingNativeBase& operator=(const ImageProcessingNativeBase&) = delete;
ImageProcessingNativeBase(ImageProcessingNativeBase&&) = delete;
ImageProcessingNativeBase& operator=(ImageProcessingNativeBase&&) = delete;
virtual ImageProcessing_ErrorCode InitializeInner();
virtual ImageProcessing_ErrorCode DeinitializeInner();
virtual ImageProcessing_ErrorCode SetParameter(const OHOS::Media::Format& parameter);
virtual ImageProcessing_ErrorCode GetParameter(OHOS::Media::Format& parameter);
virtual ImageProcessing_ErrorCode Process(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage);
virtual ImageProcessing_ErrorCode ConvertColorSpace(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage);
virtual ImageProcessing_ErrorCode Compose(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
const std::shared_ptr<OHOS::Media::PixelMap>& sourceGainmap,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage);
virtual ImageProcessing_ErrorCode Decompose(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationGainmap);
virtual ImageProcessing_ErrorCode GenerateMetadata(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage);
virtual ImageProcessing_ErrorCode EnhanceDetail(const std::shared_ptr<OHOS::Media::PixelMap>& sourceImage,
std::shared_ptr<OHOS::Media::PixelMap>& destinationImage);
private:
mutable std::mutex lock_{};
// Guarded by lock_ begin
std::atomic<bool> isInitialized_{false};
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // IMAGE_PROCESSING_NATIVE_BASE_H
@@ -0,0 +1,58 @@
/*
* 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 IMAGE_PROCESSING_NATIVE_TEMPLATE_H
#define IMAGE_PROCESSING_NATIVE_TEMPLATE_H
#include <memory>
#include "nocopyable.h"
#include "image_processing_native_base.h"
#define DEFINE_WITH_DISALLOW_COPY_AND_MOVE(className) \
className([[maybe_unused]] Protected mask) \
: ImageProcessingNativeTemplate<className>() {} \
virtual ~className() = default; \
DISALLOW_COPY_AND_MOVE(className)
namespace OHOS {
namespace Media {
namespace VideoProcessingEngine {
/**
* Base implementaion for image processing.
*/
template <typename T>
class ImageProcessingNativeTemplate : public ImageProcessingNativeBase, public std::enable_shared_from_this<T> {
public:
static inline std::shared_ptr<T> Create()
{
return std::make_shared<T>(Protected());
}
protected:
struct Protected { explicit Protected() = default; };
explicit ImageProcessingNativeTemplate() : ImageProcessingNativeBase() {}
virtual ~ImageProcessingNativeTemplate() = default;
ImageProcessingNativeTemplate(const ImageProcessingNativeTemplate&) = delete;
ImageProcessingNativeTemplate& operator=(const ImageProcessingNativeTemplate&) = delete;
ImageProcessingNativeTemplate(ImageProcessingNativeTemplate&&) = delete;
ImageProcessingNativeTemplate& operator=(ImageProcessingNativeTemplate&&) = delete;
};
} // namespace VideoProcessingEngine
} // namespace Media
} // namespace OHOS
#endif // IMAGE_PROCESSING_NATIVE_TEMPLATE_H

Some files were not shown because too many files have changed in this diff Show More