!66 merge master into master

新增AIHDR查询接口

Created-by: zhuyicheng666
Commit-by: zhuyicheng666
Merged-by: openharmony_ci
Description: ### 一、内容说明(相关的Issue)
https://gitcode.com/openharmony/multimedia_video_processing_engine/issues/44


### 二、建议测试周期和提测地址  
  建议测试完成时间:xxxx.xx.xx  
  投产上线时间:xxxx.xx.xx  
  提测地址:CI环境/压测环境  
  测试账号:  

### 三、变更内容
  * 3.1 关联PR列表

  * 3.2 数据库和部署说明  
    1. 常规更新 
    2. 重启unicorn
    3. 重启sidekiq
    4. 迁移任务:是否有迁移任务,没有写 "无"
    5. rake脚本:`bundle exec xxx RAILS_ENV = production`;没有写 "无"

  * 3.4 其他技术优化内容(做了什么,变更了什么)
    - 重构了 xxxx 代码
    - xxxx 算法优化


  * 3.5 废弃通知(什么字段、方法弃用?)



  * 3.6  后向不兼容变更(是否有无法向后兼容的变更?)


  
### 四、研发自测点(自测哪些?冒烟用例全部自测?)
  自测测试结论:


### 五、测试关注点(需要提醒QA重点关注的、可能会忽略的地方)
  检查点:

| 需求名称 | 是否影响xx公共模块 | 是否需要xx功能 | 需求升级是否依赖其他子产品 |
|------|------------|----------|---------------|
| xxx  | 否          | 需要       | 不需要           |
|      |            |          |               |

  接口测试:

  性能测试:

  并发测试:

  其他:



See merge request: openharmony/multimedia_video_processing_engine!66
This commit is contained in:
openharmony_ci
2026-08-18 17:45:47 +08:00
14 changed files with 927 additions and 13 deletions
+3 -1
View File
@@ -56,7 +56,9 @@
"//foundation/multimedia/video_processing_engine/framework:videoprocessingengine",
"//foundation/multimedia/video_processing_engine/services:video_processing_service_group",
"//foundation/multimedia/video_processing_engine/interfaces/kits/taihe:video_processing_engine_taihe_gen_only",
"//foundation/multimedia/video_processing_engine/interfaces/kits/taihe:video_processing_engine_taihe_group"
"//foundation/multimedia/video_processing_engine/interfaces/kits/taihe:video_processing_engine_taihe_group",
"//foundation/multimedia/video_processing_engine/interfaces/kits/taihe:video_processing_taihe_group",
"//foundation/multimedia/video_processing_engine/framework:videoprocessing_napi"
],
"inner_kits": [
{
+45
View File
@@ -541,3 +541,48 @@ ohos_shared_library("videoprocessingenginenapi") {
relative_install_dir = "module/multimedia"
part_name = "video_processing_engine"
}
ohos_shared_library("videoprocessing_napi") {
branch_protector_ret = "pac_ret"
sanitize = {
cfi = true
cfi_cross_dso = true
cfi_vcall_icall_only = true
debug = false
}
defines = [ ]
include_dirs = [
"$DFX_DIR/include",
"$INTERFACES_DIR/kits/js",
"$INTERFACES_INNER_API_DIR",
"$ALGORITHM_COMMON_DIR/include/",
"$INTERFACES_CAPI_DIR",
"$SERVICES_DIR/utils/include",
]
sources = [
"$INTERFACES_DIR/kits/js/native_module_ohos_video_processing.cpp",
"$INTERFACES_DIR/kits/js/video_processor_napi.cpp",
]
deps = [
":videoprocessingengine",
]
cflags = VIDEO_PROCESSING_ENGINE_CFLAGS
external_deps = [
"c_utils:utils",
"drivers_interface_display:libdisplay_commontype_proxy_2.1",
"hilog:libhilog",
"hitrace:hitrace_meter",
"ipc:ipc_napi",
"media_foundation:native_media_core",
"media_foundation:media_foundation",
"napi:ace_napi",
]
subsystem_name = "multimedia"
relative_install_dir = "module/multimedia"
part_name = "video_processing_engine"
}
@@ -48,6 +48,19 @@ std::unordered_map<uint32_t, std::function<bool(const OHOS::Media::Format& param
std::unordered_map<uint32_t, std::function<bool(const sptr<Surface>& surface)>> g_isSurfaceSupporteds = {
{ VIDEO_TYPE_AUTO_EFFECT_AISR, &AutoEffectAisrVideo::IsSurfaceSupported },
};
std::unordered_map<uint32_t, std::function<int32_t(VpeVideo::SettingsChangeCallback)>>
g_registerSettingsChangeCallback = {
// NOTE: Add feature altorithm GetParameter here. Every time a new client is created for communication
// Feature altorithm header GetParameter begin
// Feature altorithm header GetParameter end
};
std::unordered_map<uint32_t, std::function<int32_t(void)>> g_unregisterSettingsChangeCallback = {
// NOTE: Add feature altorithm GetParameter here. Every time a new client is created for communication
// Feature altorithm header GetParameter begin
// Feature altorithm header GetParameter end
};
}
std::shared_ptr<VpeVideo> VpeVideo::Create(uint32_t type)
@@ -145,3 +158,23 @@ VPEAlgoErrCode VpeVideo::RenderOutputBufferAtTime([[maybe_unused]] uint32_t inde
{
return VPE_ALGO_ERR_OK;
}
int32_t VpeVideo::RegisterSettingsChangeCallback(uint32_t type, SettingsChangeCallback callback)
{
auto it = g_registerSettingsChangeCallback.find(type);
if (it == g_registerSettingsChangeCallback.end()) {
VPE_LOGE("Unsupported type: 0x%{public}x", type);
return VPE_ALGO_ERR_INVALID_PARAM;
}
return it->second(callback);
}
int32_t VpeVideo::UnregisterSettingsChangeCallback(uint32_t type)
{
auto it = g_unregisterSettingsChangeCallback.find(type);
if (it == g_unregisterSettingsChangeCallback.end()) {
VPE_LOGE("Unsupported type: 0x%{public}x", type);
return VPE_ALGO_ERR_INVALID_PARAM;
}
return it->second();
}
+4
View File
@@ -31,6 +31,7 @@ namespace Media {
namespace VideoProcessingEngine {
class __attribute__((visibility("default"))) VpeVideo {
public:
using SettingsChangeCallback = std::function<void(int32_t feature, int32_t tag, int32_t param)>;
/**
* @brief Create a VpeVideo object.
* @param type Use VIDEO_TYPE_XXX to specify the processing type. For details, see {@link VpeVideoType}.
@@ -57,6 +58,9 @@ public:
*/
static bool IsSupported(void);
static int32_t RegisterSettingsChangeCallback(uint32_t type, SettingsChangeCallback callback);
static int32_t UnregisterSettingsChangeCallback(uint32_t type);
/**
* @brief Register callback object.
* @param callback Callback object to be registered. For details, see {@link VpeVideoCallback}.
@@ -35,7 +35,7 @@ static napi_value Export(napi_env env, napi_value exports)
/*
* module define
*/
static napi_module videoProcessingModule = {
static napi_module videoProcessingEngineModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
@@ -48,9 +48,9 @@ static napi_module videoProcessingModule = {
/*
* module register
*/
extern "C" __attribute__((constructor)) void VideoProcessingModule(void)
extern "C" __attribute__((constructor)) void RegisterVideoProcessingEngineModule(void)
{
napi_module_register(&videoProcessingModule);
napi_module_register(&videoProcessingEngineModule);
}
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,51 @@
/*
* 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 "native_module_ohos_video_processing.h"
#include "video_processor_napi.h"
namespace OHOS {
namespace Media {
/*
* Function registering all props and functions of multimedia.videoProcessing module
*/
static napi_value Export(napi_env env, napi_value exports)
{
VideoProcessorNapi::Init(env, exports);
return exports;
}
/*
* module define
*/
static napi_module videoProcessingModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Export,
.nm_modname = "multimedia.videoProcessing",
.nm_priv = nullptr,
.reserved = {0},
};
/*
* module register
*/
extern "C" __attribute__((constructor)) void RegisterVideoProcessingModule(void)
{
napi_module_register(&videoProcessingModule);
}
} // namespace Media
} // namespace OHOS
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NATIVE_MODULE_OHOS_VIDEO_PROCESSING_H
#define NATIVE_MODULE_OHOS_VIDEO_PROCESSING_H
#include "napi/native_api.h"
#include "napi/native_node_api.h"
#endif
+335
View File
@@ -0,0 +1,335 @@
/*
* 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 "VideoProcessorNapi"
#include "video_processor_napi.h"
#include <algorithm>
#include "algorithm_video.h"
#include "video_processing_types.h"
#include "vpe_log.h"
#include "vpe_trace.h"
namespace {
constexpr uint32_t NUM_1 = 1;
const char VIDEO_PROCESSOR_CLASS_NAME[] = "VideoProcessor";
}
namespace OHOS {
namespace Media {
using namespace VideoProcessingEngine;
using namespace std::chrono;
thread_local napi_ref VideoProcessorNapi::constructor_ = nullptr;
std::vector<napi_ref> VideoProcessorNapi::g_statusCallbacks{};
std::mutex VideoProcessorNapi::g_statusCallbacksLock{};
napi_threadsafe_function VideoProcessorNapi::g_statusTsfn = nullptr;
struct StatusCallbackData {
bool aiHdrEnabled;
};
void VideoProcessorNapi::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());
}
napi_value VideoProcessorNapi::Constructor(napi_env env, napi_callback_info info)
{
napi_status status;
napi_value thisVar = nullptr;
size_t argc = NUM_1;
napi_value argv[NUM_1] = {0};
status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
if (status != napi_ok || thisVar == nullptr) {
return nullptr;
}
VideoProcessorNapi* pVideoProcessorNapi = new VideoProcessorNapi();
CHECK_AND_RETURN_RET_LOG(pVideoProcessorNapi != nullptr, nullptr, "pVideoProcessorNapi == nullptr");
status = napi_wrap_with_size(env, thisVar, reinterpret_cast<void*>(pVideoProcessorNapi),
VideoProcessorNapi::Destructor, nullptr, nullptr, static_cast<size_t>(sizeof(VideoProcessorNapi)));
CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failure wrapping js to native napi");
return thisVar;
}
void VideoProcessorNapi::Destructor(napi_env env, void* nativeObject, void* finalize)
{
if (nativeObject != nullptr) {
delete reinterpret_cast<VideoProcessorNapi*>(nativeObject);
nativeObject = nullptr;
}
}
static napi_value BuildStatusObject(napi_env env, bool aiHdrEnabled)
{
napi_value jsStatus = nullptr;
CHECK_AND_RETURN_RET_LOG(napi_create_object(env, &jsStatus) == napi_ok, nullptr,
"BuildStatusObject: create jsStatus failed");
napi_value jsAiHdrStatus;
CHECK_AND_RETURN_RET_LOG(napi_create_object(env, &jsAiHdrStatus) == napi_ok, nullptr,
"BuildStatusObject: create jsAiHdrStatus failed");
napi_value jsAiHdrEnabled;
CHECK_AND_RETURN_RET_LOG(napi_get_boolean(env, aiHdrEnabled, &jsAiHdrEnabled) == napi_ok, nullptr,
"BuildStatusObject: get boolean failed");
CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, jsAiHdrStatus, "enabled", jsAiHdrEnabled) == napi_ok, nullptr,
"BuildStatusObject: set enabled failed");
CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, jsStatus, "aiHdr", jsAiHdrStatus) == napi_ok, nullptr,
"BuildStatusObject: set aiHdr failed");
return jsStatus;
}
static void InvokeCallback(napi_env env, napi_ref callbackRef, napi_value jsStatus)
{
CHECK_AND_RETURN_LOG(jsStatus != nullptr, "jsStatus is nullptr");
napi_value global;
CHECK_AND_RETURN_LOG(napi_get_global(env, &global) == napi_ok, "InvokeCallback: get global failed");
napi_value callbackFunc;
CHECK_AND_RETURN_LOG(napi_get_reference_value(env, callbackRef, &callbackFunc) == napi_ok,
"InvokeCallback: get reference value failed");
napi_value argv[NUM_1] = {jsStatus};
napi_value callbackResult;
CHECK_AND_RETURN_LOG(napi_call_function(env, global, callbackFunc, NUM_1, argv, &callbackResult) == napi_ok,
"InvokeCallback: call function failed");
}
void VideoProcessorNapi::NotifyCallback(napi_env env, napi_ref callbackRef, bool aiHdrEnabled)
{
napi_value jsStatus = BuildStatusObject(env, aiHdrEnabled);
CHECK_AND_RETURN_LOG(jsStatus != nullptr, "NotifyCallback: jsStatus is nullptr");
InvokeCallback(env, callbackRef, jsStatus);
VPE_LOGI("NotifyCallback: aiHdrEnabled=%{public}d", aiHdrEnabled);
}
void VideoProcessorNapi::StatusTsfnCallJs(napi_env env, napi_value jsCallback, void* context, void* data)
{
std::unique_ptr<StatusCallbackData> callbackDataPtr;
CHECK_AND_RETURN_LOG(data != nullptr, "StatusTsfnCallJs data is nullptr");
callbackDataPtr.reset(static_cast<StatusCallbackData*>(data));
napi_value jsStatus = BuildStatusObject(env, callbackDataPtr->aiHdrEnabled);
CHECK_AND_RETURN_LOG(jsStatus != nullptr, "StatusTsfnCallJs: jsStatus is nullptr");
std::lock_guard<std::mutex> lock(g_statusCallbacksLock);
for (auto& callbackRef : g_statusCallbacks) {
InvokeCallback(env, callbackRef, jsStatus);
}
VPE_LOGI("StatusTsfnCallJs: aiHdrEnabled=%{public}d, callbackCount=%{public}zu",
callbackDataPtr->aiHdrEnabled, g_statusCallbacks.size());
}
void VideoProcessorNapi::StatusTsfnFinalize(napi_env env, void* data, void* hint)
{
VPE_LOGI("StatusTsfnFinalize");
}
napi_value VideoProcessorNapi::GetStatus(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VideoProcessorNapi::GetStatus");
napi_value result;
napi_get_undefined(env, &result);
napi_deferred deferred;
napi_value promise;
CHECK_AND_RETURN_RET_LOG(napi_create_promise(env, &deferred, &promise) == napi_ok, result,
"GetStatus: create promise failed");
napi_value jsStatus;
CHECK_AND_RETURN_RET_LOG(napi_create_object(env, &jsStatus) == napi_ok, result,
"GetStatus: create jsStatus failed");
napi_value jsAiHdrStatus;
CHECK_AND_RETURN_RET_LOG(napi_create_object(env, &jsAiHdrStatus) == napi_ok, result,
"GetStatus: create jsAiHdrStatus failed");
Media::Format parameter{};
bool aiHdrEnabled = VpeVideo::IsSupported(VIDEO_TYPE_AIHDR_ENHANCER, parameter);
napi_value jsAiHdrEnabled;
CHECK_AND_RETURN_RET_LOG(napi_get_boolean(env, aiHdrEnabled, &jsAiHdrEnabled) == napi_ok, result,
"GetStatus: get boolean failed");
CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, jsAiHdrStatus, "enabled", jsAiHdrEnabled) == napi_ok, result,
"GetStatus: set enabled failed");
CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, jsStatus, "aiHdr", jsAiHdrStatus) == napi_ok, result,
"GetStatus: set aiHdr failed");
CHECK_AND_RETURN_RET_LOG(napi_resolve_deferred(env, deferred, jsStatus) == napi_ok, result,
"GetStatus: resolve deferred failed");
VPE_LOGI("GetStatus: aiHdrEnabled=%{public}d", aiHdrEnabled);
return promise;
}
bool VideoProcessorNapi::ValidateCallback(napi_env env, napi_value callbackValue)
{
napi_valuetype callbackType;
napi_typeof(env, callbackValue, &callbackType);
if (callbackType != napi_function) {
VPE_LOGE("Callback arg is not function");
ThrowExceptionError(env, VIDEO_PROCESSING_ERROR_INVALID_VALUE, "Callback arg is not function");
return false;
}
return true;
}
void VideoProcessorNapi::RegisterObserver(napi_env env)
{
CHECK_AND_RETURN_LOG(g_statusTsfn == nullptr, "RegisterObserver: already registered");
napi_value cbName;
std::string callbackName = "StatusChange";
CHECK_AND_RETURN_LOG(napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName) == napi_ok,
"RegisterObserverIf: create string failed");
CHECK_AND_RETURN_LOG(napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0,
1, nullptr, StatusTsfnFinalize, nullptr, StatusTsfnCallJs, &g_statusTsfn) == napi_ok,
"RegisterObserverIf: create threadsafe function failed");
napi_threadsafe_function tsfnCopy = g_statusTsfn;
VpeVideo::RegisterSettingsChangeCallback(VIDEO_TYPE_AIHDR_ENHANCER,
[tsfnCopy](int32_t feature, int32_t tag, int32_t param) {
VPE_LOGI("Settings changed, calling TSFN");
auto* callbackData = new StatusCallbackData{(param != 0)};
if (tsfnCopy != nullptr) {
napi_call_threadsafe_function(tsfnCopy, callbackData, napi_tsfn_blocking);
}
});
}
void VideoProcessorNapi::UnregisterObserver()
{
if (g_statusCallbacks.empty()) {
VpeVideo::UnregisterSettingsChangeCallback(VIDEO_TYPE_AIHDR_ENHANCER);
if (g_statusTsfn != nullptr) {
napi_release_threadsafe_function(g_statusTsfn, napi_tsfn_release);
g_statusTsfn = nullptr;
}
}
}
napi_value VideoProcessorNapi::OnStatusChange(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VideoProcessorNapi::OnStatusChange");
napi_value result;
napi_get_undefined(env, &result);
size_t argc = NUM_1;
napi_value argv[NUM_1] = {0};
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (argc != NUM_1 || !ValidateCallback(env, argv[0])) {
return result;
}
napi_ref callbackRef = nullptr;
if (napi_create_reference(env, argv[0], 1, &callbackRef) != napi_ok) {
VPE_LOGE("Create callback reference failed");
ThrowExceptionError(env, VIDEO_PROCESSING_ERROR_INVALID_VALUE, "Create callback reference failed");
return result;
}
size_t callbackSize = 0;
{
std::lock_guard<std::mutex> lock(g_statusCallbacksLock);
if (g_statusCallbacks.empty()) {
RegisterObserver(env);
}
g_statusCallbacks.push_back(callbackRef);
callbackSize = g_statusCallbacks.size();
}
Media::Format parameter{};
bool aiHdrEnabled = VpeVideo::IsSupported(VIDEO_TYPE_AIHDR_ENHANCER, parameter);
NotifyCallback(env, callbackRef, aiHdrEnabled);
VPE_LOGI("OnStatusChange done, callbackCount=%{public}zu", callbackSize);
return result;
}
void VideoProcessorNapi::RemoveCallbackRef(napi_env env, napi_value callback)
{
auto it = std::find_if(g_statusCallbacks.begin(), g_statusCallbacks.end(),
[env, callback](napi_ref ref) {
napi_value refFunc;
CHECK_AND_RETURN_RET_LOG(napi_get_reference_value(env, ref, &refFunc) == napi_ok, false,
"RemoveCallbackRef: get reference value failed");
bool isEqual = false;
CHECK_AND_RETURN_RET_LOG(napi_strict_equals(env, callback, refFunc, &isEqual) == napi_ok, false,
"RemoveCallbackRef: strict equals failed");
return isEqual;
});
CHECK_AND_RETURN_LOG(it != g_statusCallbacks.end(), "RemoveCallbackRef: callback not found");
CHECK_AND_RETURN_LOG(napi_delete_reference(env, *it) == napi_ok,
"RemoveCallbackRef: delete reference failed");
g_statusCallbacks.erase(it);
}
napi_value VideoProcessorNapi::OffStatusChange(napi_env env, napi_callback_info info)
{
VPETrace vpeTrace("VideoProcessorNapi::OffStatusChange");
napi_value result;
napi_get_undefined(env, &result);
size_t argc = NUM_1;
napi_value argv[NUM_1] = {0};
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (argc > NUM_1) {
VPE_LOGE("Invalid args count %{public}zu", argc);
ThrowExceptionError(env, VIDEO_PROCESSING_ERROR_INVALID_VALUE, "Invalid args count");
return result;
}
std::lock_guard<std::mutex> lock(g_statusCallbacksLock);
if (argc == NUM_1) {
if (!ValidateCallback(env, argv[0])) {
return result;
}
RemoveCallbackRef(env, argv[0]);
} else {
for (auto& ref : g_statusCallbacks) {
napi_delete_reference(env, ref);
}
g_statusCallbacks.clear();
}
UnregisterObserver();
VPE_LOGI("OffStatusChange done, remainingCallbacks=%{public}zu", g_statusCallbacks.size());
return result;
}
napi_value VideoProcessorNapi::Init(napi_env env, napi_value exports)
{
napi_property_descriptor props[] = {
DECLARE_NAPI_FUNCTION("getStatus", VideoProcessorNapi::GetStatus),
DECLARE_NAPI_FUNCTION("onStatusChange", VideoProcessorNapi::OnStatusChange),
DECLARE_NAPI_FUNCTION("offStatusChange", VideoProcessorNapi::OffStatusChange)
};
napi_value constructor = nullptr;
CHECK_AND_RETURN_RET_LOG(napi_define_class(env, VIDEO_PROCESSOR_CLASS_NAME, sizeof(VIDEO_PROCESSOR_CLASS_NAME),
VideoProcessorNapi::Constructor, nullptr, sizeof(props) / sizeof(props[0]), props, &constructor) == napi_ok,
nullptr, "define class fail");
CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, exports, VIDEO_PROCESSOR_CLASS_NAME, constructor) == napi_ok,
nullptr, "set named property fail");
CHECK_AND_RETURN_RET_LOG(napi_create_reference(env, constructor, 1, &constructor_) == napi_ok,
nullptr, "create reference fail");
napi_property_descriptor moduleFuncs[] = {
DECLARE_NAPI_FUNCTION("createVideoProcessor", VideoProcessorNapi::CreateVideoProcessor),
};
napi_define_properties(env, exports, sizeof(moduleFuncs) / sizeof(moduleFuncs[0]), moduleFuncs);
return exports;
}
napi_value VideoProcessorNapi::CreateVideoProcessor(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_value constructor = nullptr;
CHECK_AND_RETURN_RET_LOG(napi_get_reference_value(env, constructor_, &constructor) == napi_ok,
nullptr, "CreateVideoProcessor: get constructor failed");
size_t argc = NUM_1;
napi_value argv[NUM_1] = {0};
CHECK_AND_RETURN_RET_LOG(napi_new_instance(env, constructor, argc, argv, &result) == napi_ok,
nullptr, "CreateVideoProcessor: new instance failed");
VPE_LOGI("create done");
return result;
}
}
}
+58
View File
@@ -0,0 +1,58 @@
/*
* 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 VIDEO_PROCESSOR_NAPI_H
#define VIDEO_PROCESSOR_NAPI_H
#include "algorithm_video.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"
namespace OHOS {
namespace Media {
class VideoProcessorNapi {
public:
VideoProcessorNapi() = default;
~VideoProcessorNapi() = default;
static napi_value Init(napi_env env, napi_value exports);
static napi_value CreateVideoProcessor(napi_env env, napi_callback_info info);
static napi_value GetStatus(napi_env env, napi_callback_info info);
static napi_value OnStatusChange(napi_env env, napi_callback_info info);
static napi_value OffStatusChange(napi_env env, napi_callback_info info);
private:
static thread_local napi_ref constructor_;
static std::vector<napi_ref> g_statusCallbacks;
static std::mutex g_statusCallbacksLock;
static napi_threadsafe_function g_statusTsfn;
static napi_value Constructor(napi_env env, napi_callback_info info);
static void Destructor(napi_env env, void* nativeObject, void* finalize);
static void ThrowExceptionError(napi_env env, const int32_t errCode, const std::string errMsg);
static void NotifyCallback(napi_env env, napi_ref callbackRef, bool aiHdrEnabled);
static void StatusTsfnCallJs(napi_env env, napi_value jsCallback, void* context, void* data);
static void StatusTsfnFinalize(napi_env env, void* data, void* hint);
static bool ValidateCallback(napi_env env, napi_value callbackValue);
static void RegisterObserver(napi_env env);
static void UnregisterObserver();
static void RemoveCallbackRef(napi_env env, napi_value callback);
};
}
}
#endif
+116 -9
View File
@@ -18,8 +18,10 @@ import("//foundation/multimedia/video_processing_engine/config.gni")
subsystem_name = "multimedia"
part_name = "video_processing_engine"
taihe_generated_file_path = "$taihe_file_path/out/$subsystem_name/$part_name"
# =============== videoProcessingEngine Module ===============
videoProcessingEngine = "videoProcessingEngine"
video_processing_engine_taihe_generated_file_path = "$taihe_file_path/out/$subsystem_name/$part_name/$videoProcessingEngine"
config("video_processing_engine_taihe_config") {
visibility = [ ":*" ]
include_dirs = [ "include" ]
@@ -36,17 +38,17 @@ copy_taihe_idl("copy_video_processing_engine_taihe") {
}
ohos_taihe("run_taihe") {
taihe_generated_file_path = "$taihe_generated_file_path"
taihe_generated_file_path = "$video_processing_engine_taihe_generated_file_path"
deps = [ ":copy_video_processing_engine_taihe" ]
outputs = [
"$taihe_generated_file_path/src/ohos.multimedia.videoProcessingEngine.ani.cpp",
"$taihe_generated_file_path/src/ohos.multimedia.videoProcessingEngine.abi.c",
"$video_processing_engine_taihe_generated_file_path/src/ohos.multimedia.videoProcessingEngine.ani.cpp",
"$video_processing_engine_taihe_generated_file_path/src/ohos.multimedia.videoProcessingEngine.abi.c",
]
}
generate_static_abc("video_processing_engine_taihe_abc") {
base_url = "$taihe_generated_file_path"
files = [ "$taihe_generated_file_path/@ohos.multimedia.videoProcessingEngine.ets" ]
base_url = "$video_processing_engine_taihe_generated_file_path"
files = [ "$video_processing_engine_taihe_generated_file_path/@ohos.multimedia.videoProcessingEngine.ets" ]
is_boot_abc = "True"
device_dst_file = "/system/framework/video_processing_engine_taihe_abc.abc"
dependencies = [ ":run_taihe" ]
@@ -72,7 +74,7 @@ group("video_processing_engine_taihe_gen_only") {
}
taihe_shared_library("video_processing_engine_taihe") {
taihe_generated_file_path = "$taihe_generated_file_path"
taihe_generated_file_path = "$video_processing_engine_taihe_generated_file_path"
subsystem_name = "$subsystem_name"
part_name = "$part_name"
@@ -113,6 +115,7 @@ taihe_shared_library("video_processing_engine_taihe") {
"media_foundation:native_media_core",
"media_foundation:media_foundation",
"runtime_core:ani_helpers",
"napi:ace_napi",
]
cflags = [
@@ -131,7 +134,7 @@ taihe_shared_library("video_processing_engine_taihe") {
}
taihe_shared_library("video_processing_engine_taihe_core") {
taihe_generated_file_path = "$taihe_generated_file_path"
taihe_generated_file_path = "$video_processing_engine_taihe_generated_file_path"
subsystem_name = "$subsystem_name"
part_name = "$part_name"
shlib_type = "ani"
@@ -147,4 +150,108 @@ taihe_shared_library("video_processing_engine_taihe_core") {
ubsan = true
debug = false
}
}
}
# =============== videoProcessing Module ===============
videoProcessing = "videoProcessing"
video_processing_taihe_generated_file_path = "$taihe_file_path/out/$subsystem_name/$part_name/$videoProcessing"
config("video_processing_taihe_config") {
visibility = [ ":*" ]
include_dirs = [ "include" ]
}
copy_taihe_idl("copy_video_processing_taihe") {
sources = [
"$INTERFACES_DIR/kits/taihe/idl/ohos.multimedia.videoProcessing.taihe",
]
}
ohos_taihe("run_taihe_video_processing") {
taihe_generated_file_path = "$video_processing_taihe_generated_file_path"
deps = [ ":copy_video_processing_taihe" ]
outputs = [
"$video_processing_taihe_generated_file_path/src/ohos.multimedia.videoProcessing.ani.cpp",
"$video_processing_taihe_generated_file_path/src/ohos.multimedia.videoProcessing.abi.c",
]
}
generate_static_abc("video_processing_taihe_abc") {
base_url = "$video_processing_taihe_generated_file_path"
files = [ "$video_processing_taihe_generated_file_path/@ohos.multimedia.videoProcessing.ets" ]
is_boot_abc = "True"
device_dst_file = "/system/framework/video_processing_taihe_abc.abc"
dependencies = [ ":run_taihe_video_processing" ]
}
ohos_prebuilt_etc("video_processing_etc") {
source = "$target_out_dir/video_processing_taihe_abc.abc"
module_install_dir = "framework"
part_name = "$part_name"
subsystem_name = "$subsystem_name"
deps = [ ":video_processing_taihe_abc" ]
}
group("video_processing_taihe_gen_only") {
deps = [ ":run_taihe_video_processing" ]
}
group("video_processing_taihe_group") {
deps = [
":video_processing_etc",
":video_processing_taihe_native",
]
}
taihe_shared_library("video_processing_taihe_native") {
taihe_generated_file_path = "$video_processing_taihe_generated_file_path"
subsystem_name = "$subsystem_name"
part_name = "$part_name"
public_configs = [ ":video_processing_taihe_config" ]
include_dirs = [
"include",
"$DFX_DIR/include",
"$INTERFACES_DIR/kits/js",
"$INTERFACES_INNER_API_DIR",
"$CAPI_DIR/image_processing/include/",
"$ALGORITHM_COMMON_DIR/include/",
"$INTERFACES_CAPI_DIR",
]
sources = get_target_outputs(":run_taihe_video_processing")
sources += [
"src/video_processing_taihe.cpp",
"src/video_processing_ani_constructor.cpp",
]
deps = [
":run_taihe_video_processing",
"$VIDEO_PROCESSING_ENGINE_ROOT_DIR/framework:videoprocessingengine",
]
external_deps = [
"c_utils:utils",
"drivers_interface_display:libdisplay_commontype_proxy_2.1",
"hilog:libhilog",
"hitrace:hitrace_meter",
"ipc:ipc_napi",
"media_foundation:native_media_core",
"media_foundation:media_foundation",
"runtime_core:ani_helpers",
"napi:ace_napi",
]
cflags = [
"-DIMAGE_DEBUG_FLAG",
"-DIMAGE_COLORSPACE_FLAG",
]
sanitize = {
boundary_sanitize = true
cfi = true
cfi_cross_dso = true
integer_overflow = true
ubsan = true
debug = false
}
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2026 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.
*/
@!namespace("@ohos.multimedia.videoProcessing", "videoProcessing")
@!sts_export_default
@!sts_inject("""
static { loadLibraryWithPermissionCheck("video_processing_taihe_native.z", "@ohos.multimedia.videoProcessing"); }
""")
struct VideoProcessorAiHdrStatus {
@optional enabled: Optional<bool>;
}
struct VideoProcessorStatus {
@optional aiHdr: Optional<VideoProcessorAiHdrStatus>;
}
interface VideoProcessor {
@rename("getStatus") @promise GetStatus(): VideoProcessorStatus;
@rename("onStatusChange") OnStatusChange(callback: (status: VideoProcessorStatus) => void): void;
@rename("offStatusChange") OffStatusChange(@optional callback: Optional<(status: VideoProcessorStatus) => void>): void;
}
function createVideoProcessor(): VideoProcessor;
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2026 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 FRAMEWORKS_KITS_TAIHE_INCLUDE_VIDEO_PROCESSING_TAIHE_H
#define FRAMEWORKS_KITS_TAIHE_INCLUDE_VIDEO_PROCESSING_TAIHE_H
#include "ohos.multimedia.videoProcessing.impl.hpp"
#include "ohos.multimedia.videoProcessing.proj.hpp"
#include <mutex>
#include <vector>
#include <functional>
#include "taihe/runtime.hpp"
namespace ANI::Vp {
using namespace taihe;
namespace taiheVp = ::ohos::multimedia::videoProcessing;
class VideoProcessorImpl {
public:
VideoProcessorImpl() = default;
~VideoProcessorImpl() = default;
taiheVp::VideoProcessorStatus GetStatus();
void OnStatusChange(
taihe::callback_view<void(const taiheVp::VideoProcessorStatus&)> callback);
void OffStatusChange(
taihe::optional_view<taihe::callback<void(const taiheVp::VideoProcessorStatus&)>> callback);
private:
bool GetCurrentAiHdrEnabled();
void TriggerSingleCallback(const taihe::callback<void(const taiheVp::VideoProcessorStatus&)>& callback,
bool aiHdrEnabled);
void StatusChangeCallback(int32_t feature, int32_t tag, int32_t param);
static std::vector<taihe::callback<void(const taiheVp::VideoProcessorStatus&)>> g_statusCallbacks;
static std::mutex g_statusCallbacksLock;
static bool g_isListenerRegistered;
};
}
#endif
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2026 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 "ohos.multimedia.videoProcessing.ani.hpp"
#if __has_include(<ani.h>)
#include <ani.h>
#elif __has_include(<ani/ani.h>)
#include <ani/ani.h>
#else
#error "ani.h not found. Please ensure the Ani SDK is correctly installed."
#endif
ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
{
ani_env* env;
if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
return ANI_ERROR;
}
ani_status status = ANI_OK;
if (ANI_OK != ohos::multimedia::videoProcessing::ANIRegister(env)) {
std::cerr << "Error from ohos::multimedia::videoProcessing::ANIRegister" << std::endl;
status = ANI_ERROR;
}
*result = ANI_VERSION_1;
return status;
}
@@ -0,0 +1,129 @@
/*
* Copyright (C) 2026 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_processing_taihe.h"
#include "algorithm_video.h"
#include "vpe_log.h"
#include "vpe_trace.h"
#include "taihe/runtime.hpp"
using namespace taihe;
using namespace OHOS::Media::VideoProcessingEngine;
using namespace ANI;
using namespace ANI::Vp;
namespace ANI::Vp {
std::vector<taihe::callback<void(const taiheVp::VideoProcessorStatus&)>> VideoProcessorImpl::g_statusCallbacks;
std::mutex VideoProcessorImpl::g_statusCallbacksLock;
taiheVp::VideoProcessor createVideoProcessor()
{
return taihe::make_holder<VideoProcessorImpl, taiheVp::VideoProcessor>();
}
}
bool VideoProcessorImpl::GetCurrentAiHdrEnabled()
{
OHOS::Media::Format parameter;
return VpeVideo::IsSupported(VIDEO_TYPE_AIHDR_ENHANCER, parameter);
}
void VideoProcessorImpl::StatusChangeCallback(int32_t feature, int32_t tag, int32_t param)
{
VPE_LOGI("StatusChangeCallback: feature=%{public}d, param=%{public}d", feature, param);
bool aiHdrEnabled = (param != 0);
std::lock_guard<std::mutex> lock(g_statusCallbacksLock);
taiheVp::VideoProcessorAiHdrStatus aiHdrStatus;
aiHdrStatus.enabled.emplace(aiHdrEnabled);
taiheVp::VideoProcessorStatus status;
status.aiHdr.emplace(aiHdrStatus);
for (auto& callback : g_statusCallbacks) {
callback(status);
}
VPE_LOGI("StatusChangeCallback: notified %{public}zu callbacks, aiHdrEnabled=%{public}d",
g_statusCallbacks.size(), aiHdrEnabled);
}
void VideoProcessorImpl::TriggerSingleCallback(
const taihe::callback<void(const taiheVp::VideoProcessorStatus&)>& callback, bool aiHdrEnabled)
{
taiheVp::VideoProcessorAiHdrStatus aiHdrStatus;
aiHdrStatus.enabled.emplace(aiHdrEnabled);
taiheVp::VideoProcessorStatus status;
status.aiHdr.emplace(aiHdrStatus);
callback(status);
VPE_LOGI("TriggerSingleCallback: aiHdrEnabled=%{public}d", aiHdrEnabled);
}
taiheVp::VideoProcessorStatus VideoProcessorImpl::GetStatus()
{
taiheVp::VideoProcessorAiHdrStatus aiHdrStatus;
bool aiHdrEnabled = GetCurrentAiHdrEnabled();
aiHdrStatus.enabled.emplace(aiHdrEnabled);
taiheVp::VideoProcessorStatus status;
status.aiHdr.emplace(aiHdrStatus);
VPE_LOGI("GetStatus: aiHdrEnabled=%{public}d", aiHdrEnabled);
return status;
}
void VideoProcessorImpl::OnStatusChange(
taihe::callback_view<void(const taiheVp::VideoProcessorStatus&)> callback)
{
VPETrace vpeTrace("VideoProcessorImpl::OnStatusChange");
size_t callbackSize = 0;
{
std::lock_guard<std::mutex> lock(g_statusCallbacksLock);
if (g_statusCallbacks.empty()) {
VpeVideo::RegisterSettingsChangeCallback(VIDEO_TYPE_AIHDR_ENHANCER,
[this](int32_t feature, int32_t tag, int32_t param) {
StatusChangeCallback(feature, tag, param);
});
}
g_statusCallbacks.push_back(callback);
callbackSize = g_statusCallbacks.size();
}
bool aiHdrEnabled = GetCurrentAiHdrEnabled();
TriggerSingleCallback(callback, aiHdrEnabled);
VPE_LOGI("OnStatusChange done, callbackCount=%{public}zu", callbackSize);
}
void VideoProcessorImpl::OffStatusChange(
taihe::optional_view<taihe::callback<void(const taiheVp::VideoProcessorStatus&)>> callback)
{
VPETrace vpeTrace("VideoProcessorImpl::OffStatusChange");
std::lock_guard<std::mutex> lock(g_statusCallbacksLock);
if (callback.has_value()) {
auto it = std::find_if(g_statusCallbacks.begin(), g_statusCallbacks.end(),
[&callback](const taihe::callback<void(const taiheVp::VideoProcessorStatus&)>& item) {
return item == callback.value();
});
if (it != g_statusCallbacks.end()) {
g_statusCallbacks.erase(it);
}
} else {
g_statusCallbacks.clear();
}
if (g_statusCallbacks.empty()) {
VpeVideo::UnregisterSettingsChangeCallback(VIDEO_TYPE_AIHDR_ENHANCER);
}
VPE_LOGI("OffStatusChange done, remainingCallbacks=%{public}zu", g_statusCallbacks.size());
}
// NOLINTBEGIN
TH_EXPORT_CPP_API_createVideoProcessor(createVideoProcessor);
// NOLINTEND