• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #undef LOG_DOMAIN
17 #define LOG_DOMAIN 0xD002B3F
18 #undef LOG_TAG
19 #define LOG_TAG "VpeNapi"
20 
21 #include "detail_enhance_napi_formal.h"
22 
23 #include <algorithm>
24 
25 #include "image_napi_utils.h"
26 #include "media_errors.h"
27 #include "memory_manager.h"
28 #include "native_avformat.h"
29 #include "pixelmap_native_impl.h"
30 #include "pixelmap_native.h"
31 
32 #include "detail_enhancer_common.h"
33 #include "vpe_log.h"
34 #include "vpe_trace.h"
35 #include "vpe_utils.h"
36 
37 namespace {
38 constexpr uint32_t NUM_0 = 0;
39 constexpr uint32_t NUM_1 = 1;
40 constexpr uint32_t NUM_2 = 2;
41 constexpr uint32_t NUM_3 = 3;
42 constexpr uint32_t NUM_4 = 4;
43 constexpr uint32_t NUM_5 = 5;
44 constexpr uint32_t NUM_6 = 6;
45 constexpr uint32_t NUM_7 = 7;
46 constexpr uint32_t NUM_8 = 8;
47 constexpr uint32_t NUM_9 = 9;
48 constexpr int32_t NEW_INSTANCE_ARGC = 1;
49 constexpr int32_t MIN_WIDTH_CONTRAST = 720; // min support width 720, consistent with fwk
50 constexpr int32_t MIN_HEIGHT_CONTRAST = 720; // min support height 720, consistent with fwk
51 constexpr int32_t MAX_RESOLUTION_CONTRAST = 20000; // max support resolution 20000, consistent with fwk
52 constexpr int32_t MIN_RESOLUTION_DETAIL = 32; // min support resolution 32, consistent with fwk
53 constexpr int32_t MAX_RESOLUTION_DETAIL = 8192; // max support resolution 8192, consistent with fwk
54 constexpr float ROUNDING_OPERATOR = 0.5;
55 const std::string CLASS_NAME = "ImageProcessor";
56 static std::mutex g_imageProcessorMutex{std::mutex()};
57 static std::mutex g_contrastLock{std::mutex()};
58 }
59 
60 namespace OHOS {
61 namespace Media {
62 using namespace VideoProcessingEngine;
63 using namespace std::chrono;
64 thread_local napi_ref VpeNapi::constructor_ = nullptr;
65 thread_local napi_ref VpeNapi::qualityLevelTypeRef_ = nullptr;
66 thread_local std::shared_ptr<VpeNapi::DetailEnhanceContext> VpeNapi::detailContext_ = nullptr;
67 thread_local std::shared_ptr<VpeNapi::ContrastEnhanceContext> VpeNapi::contrastContext_ = nullptr;
68 static std::shared_ptr<DetailEnhancerImage> g_detailEnh{};
69 static std::shared_ptr<ContrastEnhancerImage> g_contrastEnh{};
70 
71 struct QualityLevelEnum {
72     std::string name;
73     int32_t numVal;
74     std::string strVal;
75 };
76 static std::vector<struct QualityLevelEnum> g_qualityLevels = {
77     {"NONE",   OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_NONE,   ""},
78     {"LOW",    OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_LOW,    ""},
79     {"MEDIUM", OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_MEDIUM, ""},
80     {"HIGH",   OHOS::Media::VideoProcessingEngine::DETAIL_ENH_LEVEL_HIGH,   ""},
81 };
82 
ThrowExceptionError(napi_env env,const int32_t errCode,const std::string errMsg)83 void VpeNapi::ThrowExceptionError(napi_env env, const int32_t errCode, const std::string errMsg)
84 {
85     std::string errCodeStr = std::to_string(errCode);
86     napi_throw_error(env, errCodeStr.c_str(), errMsg.c_str());
87 }
88 
PrepareNapiEnv(napi_env env,napi_callback_info info,NapiValues * nVal)89 bool VpeNapi::PrepareNapiEnv(napi_env env, napi_callback_info info, NapiValues* nVal)
90 {
91     CHECK_AND_RETURN_RET_LOG(nVal != nullptr, false, "nVal == nullptr");
92     if (napi_get_undefined(env, &(nVal->result)) != napi_ok) {
93         VPE_LOGE("Get undefined result failed");
94         return false;
95     }
96     nVal->status = napi_get_cb_info(env, info, &(nVal->argc), nVal->argv, &(nVal->thisVar), nullptr);
97     if (nVal->status != napi_ok) {
98         VPE_LOGE("fail to napi_get_cb_info");
99         return false;
100     }
101     return true;
102 }
103 
ParserImageType(napi_env env,napi_value argv)104 ImageType VpeNapi::ParserImageType(napi_env env, napi_value argv)
105 {
106     napi_value constructor = nullptr;
107     napi_value global = nullptr;
108     napi_status ret = napi_invalid_arg;
109     napi_get_global(env, &global);
110     ret = napi_get_named_property(env, global, "PixelMap", &constructor);
111     if (ret != napi_ok) {
112         VPE_LOGI("Get VpeNapi property failed!");
113         return ImageType::TYPE_UNKNOWN;
114     }
115     bool isInstance = false;
116     ret = napi_instanceof(env, argv, constructor, &isInstance);
117     if (ret == napi_ok && isInstance) {
118         return ImageType::TYPE_PIXEL_MAP;
119     }
120     return ImageType::TYPE_UNKNOWN;
121 }
122 
ConfigResolutionBasedOnRatio(napi_env env,napi_value & nVal,std::shared_ptr<VpeNapi::DetailEnhanceContext> context)123 bool VpeNapi::ConfigResolutionBasedOnRatio(napi_env env, napi_value& nVal,
124     std::shared_ptr<VpeNapi::DetailEnhanceContext> context)
125 {
126     CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context == nullptr");
127     double zoomRatio;
128     if (napi_ok != napi_get_value_double(env, nVal, &zoomRatio)) {
129         VPE_LOGE("Arg 1 type mismatch");
130         return false;
131     }
132     CHECK_AND_RETURN_RET_LOG(context->inputPixelMap != nullptr, false, "context->inputPixelMap == nullptr");
133     context->xArg = zoomRatio * context->inputPixelMap->GetWidth();
134     context->yArg = zoomRatio * context->inputPixelMap->GetHeight();
135     VPE_LOGE("config resolution with ratio :%{public}d, %{public}d",
136         static_cast<int>(context->xArg), static_cast<int>(context->yArg));
137     return true;
138 }
139 
ConfigResolution(napi_env env,napi_value & width,napi_value & height,std::shared_ptr<VpeNapi::DetailEnhanceContext> context)140 bool VpeNapi::ConfigResolution(napi_env env, napi_value& width, napi_value& height,
141     std::shared_ptr<VpeNapi::DetailEnhanceContext> context)
142 {
143     CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context == nullptr");
144     CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_double(env, width, &(context->xArg)),
145         false, "Arg 1 type mismatch");
146     CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_double(env, height, &(context->yArg)),
147         false, "Arg 2 type mismatch");
148     return true;
149 }
150 
ParseDetailEnhanceParameter(napi_env env,napi_callback_info info)151 bool VpeNapi::ParseDetailEnhanceParameter(napi_env env, napi_callback_info info)
152 {
153     VPETrace vpeTrace("VpeNapi::DetailEnhanceParseParameter");
154     CHECK_AND_RETURN_RET_LOG(detailContext_ != nullptr, false, "detailContext_ == nullptr");
155     NapiValues nVal;
156     nVal.argc = NUM_4; // Use the maximum value to initialize argc before executing PrepareNapiEnv
157     napi_value argValue[NUM_4] = {0};
158     nVal.argv = argValue;
159     CHECK_AND_RETURN_RET_LOG(PrepareNapiEnv(env, info, &nVal), false, "PrepareNapiEnv failed");
160     if (nVal.argc != NUM_2 && nVal.argc != NUM_3 && nVal.argc != NUM_4) {
161         VPE_LOGE("Invalid args count %{public}zu", nVal.argc);
162         return false;
163     }
164     if (ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP) {
165         detailContext_->inputPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
166     } else {
167         VPE_LOGE("args0 is not pixelMap!");
168         return false;
169     }
170     CHECK_AND_RETURN_RET_LOG(detailContext_->inputPixelMap != nullptr, false, "inputPixelMap is nullptr!");
171     if (nVal.argc == NUM_2) { // 2 parameter: pixelmap scaleRatio
172         CHECK_AND_RETURN_RET_LOG(ConfigResolutionBasedOnRatio(env, nVal.argv[NUM_1], detailContext_),
173             false, "ConfigResolutionBasedOnRatio failed");
174         detailContext_->qualityLevel = DETAIL_ENH_LEVEL_LOW; // default as low level
175     }
176     if (nVal.argc == NUM_3) { // 3 parameter: pixelmap scaleRatio level / pixelmap x y
177         double valueToCheck = 0;
178         CHECK_AND_RETURN_RET_LOG(napi_get_value_double(env, nVal.argv[NUM_2], &valueToCheck) == napi_ok,
179             false, "failed to parse");
180         if (valueToCheck >= 0 && valueToCheck <= 3) { // if valueToCheck in [0,3], valueToCheck should be level.
181             CHECK_AND_RETURN_RET_LOG(ConfigResolutionBasedOnRatio(env, nVal.argv[NUM_1], detailContext_), false,
182                 "ConfigResolutionBasedOnRatio failed");
183             detailContext_->qualityLevel = static_cast<int>(valueToCheck);
184         } else {
185             CHECK_AND_RETURN_RET_LOG(ConfigResolution(env, nVal.argv[NUM_1], nVal.argv[NUM_2], detailContext_),
186                 false, "ConfigResolution failed");
187             detailContext_->qualityLevel = DETAIL_ENH_LEVEL_LOW; // default as low level
188         }
189     }
190     if (nVal.argc == NUM_4) { // 4 parameter: pixelmap x y level
191         CHECK_AND_RETURN_RET_LOG(ConfigResolution(env, nVal.argv[NUM_1], nVal.argv[NUM_2], detailContext_),
192             false, "ConfigResolution failed");
193         CHECK_AND_RETURN_RET_LOG(napi_get_value_int32(env, nVal.argv[NUM_3],
194             &(detailContext_->qualityLevel)) == napi_ok, false, "Arg 3 type mismatch");
195     }
196     return true;
197 }
198 
InitializeEnvironment(napi_env env,napi_callback_info info)199 napi_value VpeNapi::InitializeEnvironment(napi_env env, napi_callback_info info)
200 {
201     napi_value result;
202     napi_get_boolean(env, true, &result);
203     return result;
204 }
205 
DeinitializeEnvironment(napi_env env,napi_callback_info info)206 napi_value VpeNapi::DeinitializeEnvironment(napi_env env, napi_callback_info info)
207 {
208     VPETrace vpeTrace("VpeNapi::DetailEnhanceDeinitializeEnvironment");
209     napi_value result;
210     napi_get_boolean(env, true, &result);
211     return result;
212 }
213 
SetDstPixelMapInfo(PixelMap & source,void * dstPixels,uint32_t dstPixelsSize,std::unique_ptr<AbsMemory> & memory,PixelMap & dstPixelMap)214 void VpeNapi::SetDstPixelMapInfo(PixelMap& source, void* dstPixels, uint32_t dstPixelsSize,
215     std::unique_ptr<AbsMemory>& memory, PixelMap& dstPixelMap)
216 {
217     AllocatorType sourceType = source.GetAllocatorType();
218     if (sourceType != AllocatorType::DMA_ALLOC) {
219         VPE_LOGW("only support DMA");
220         return;
221     }
222     if (memory == nullptr) {
223         VPE_LOGW("Invalid memory");
224         return;
225     }
226     if (memory->extend.data == nullptr) {
227         VPE_LOGE("memory->extend.data == nullptr");
228         return;
229     }
230     dstPixelMap.SetPixelsAddr(dstPixels, memory->extend.data, memory->data.size, sourceType, nullptr);
231     if (source.GetAllocatorType() == AllocatorType::DMA_ALLOC && source.IsHdr()) {
232         sptr<SurfaceBuffer> sourceSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (source.GetFd()));
233         sptr<SurfaceBuffer> dstSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (dstPixelMap.GetFd()));
234         if (sourceSurfaceBuffer == nullptr) {
235             VPE_LOGE("sourceSurfaceBuffer == nullptr");
236             return;
237         }
238         if (dstSurfaceBuffer == nullptr) {
239             VPE_LOGE("dstSurfaceBuffer == nullptr");
240             return;
241         }
242         VpeUtils::CopySurfaceBufferInfo(sourceSurfaceBuffer, dstSurfaceBuffer);
243     }
244     OHOS::ColorManager::ColorSpace colorspace = source.InnerGetGrColorSpace();
245     dstPixelMap.InnerSetColorSpace(colorspace);
246 }
247 
AllocMemory(PixelMap & source,PixelMap & dstPixelMap,const InitializationOptions & opt)248 bool VpeNapi::AllocMemory(PixelMap& source, PixelMap& dstPixelMap, const InitializationOptions& opt)
249 {
250     if (source.GetPixels() == nullptr) {
251         VPE_LOGE("pixels of source are not available");
252         return false;
253     }
254     int32_t bufferSize = source.GetByteCount();
255     if (bufferSize <= 0) {
256         VPE_LOGE("CopyPixelMap parameter bufferSize:[%{public}d] error.", bufferSize);
257         return false;
258     }
259     ImageInfo dstImageInfo;
260     dstPixelMap.GetImageInfo(dstImageInfo);
261     MemoryData memoryData = {nullptr, static_cast<size_t>(bufferSize), "Copy ImageData",
262         dstImageInfo.size, dstImageInfo.pixelFormat};
263     std::unique_ptr<AbsMemory> memory = MemoryManager::CreateMemory(source.GetAllocatorType(), memoryData);
264     if (memory == nullptr) {
265         VPE_LOGE("invalid memory");
266         return false;
267     }
268     void* dstPixels = memory->data.data;
269     if (dstPixels == nullptr) {
270         VPE_LOGE("source crop allocate memory fail allocatetype: %{public}d ", source.GetAllocatorType());
271         return false;
272     }
273     SetDstPixelMapInfo(source, dstPixels, static_cast<size_t>(bufferSize), memory, dstPixelMap);
274     return true;
275 }
276 
CreateDstPixelMap(PixelMap & source,const InitializationOptions & opts)277 std::unique_ptr<PixelMap> VpeNapi::CreateDstPixelMap(PixelMap& source, const InitializationOptions& opts)
278 {
279     if (source.GetAllocatorType() != AllocatorType::DMA_ALLOC) {
280         VPE_LOGE("alloc type of source is not dma, create with default method");
281         return source.Create(source, opts);
282     }
283     std::unique_ptr<PixelMap> dstPixelMap = std::make_unique<PixelMap>();
284     if (dstPixelMap == nullptr) {
285         VPE_LOGE("create pixelmap pointer fail");
286         return nullptr;
287     }
288     ImageInfo srcImageInfo;
289     source.GetImageInfo(srcImageInfo);
290     ImageInfo dstImageInfo = {
291         .size = opts.size,
292         .pixelFormat = srcImageInfo.pixelFormat,
293         .alphaType = srcImageInfo.alphaType,
294     };
295     if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) {
296         return nullptr;
297     }
298     if (!AllocMemory(source, *dstPixelMap.get(), opts)) {
299         VPE_LOGE("alloc memory failed");
300         return nullptr;
301     }
302     return dstPixelMap;
303 }
304 
ConvertPixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap> & pixelmap,sptr<SurfaceBuffer> & bufferImpl)305 bool VpeNapi::ConvertPixelmapToSurfaceBuffer(const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap,
306     sptr<SurfaceBuffer>& bufferImpl)
307 {
308     BufferRequestConfig bfConfig = {};
309     bfConfig.width = pixelmap->GetWidth();
310     bfConfig.height = pixelmap->GetHeight();
311     bfConfig.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE;
312     bfConfig.strideAlignment = bfConfig.width;
313     bfConfig.format = GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888;
314     bfConfig.timeout = 0;
315     bfConfig.colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB;
316     bfConfig.transform = GraphicTransformType::GRAPHIC_ROTATE_NONE;
317     CHECK_AND_RETURN_RET_LOG((bufferImpl->Alloc(bfConfig) == GSERROR_OK), false, "invalid OH_PixelmapNative image");
318     return true;
319 }
320 
GetSurfaceBufferFromDMAPixelMap(const std::shared_ptr<OHOS::Media::PixelMap> & pixelmap)321 sptr<SurfaceBuffer> VpeNapi::GetSurfaceBufferFromDMAPixelMap(
322     const std::shared_ptr<OHOS::Media::PixelMap>& pixelmap)
323 {
324     CHECK_AND_RETURN_RET_LOG(pixelmap != nullptr, nullptr, "pixelmap == nullptr");
325     if (pixelmap->GetAllocatorType() == AllocatorType::DMA_ALLOC) {
326         return reinterpret_cast<SurfaceBuffer*>(pixelmap->GetFd());
327     }
328     auto buffer = SurfaceBuffer::Create();
329     CHECK_AND_RETURN_RET_LOG(buffer != nullptr, nullptr, "get surface buffer failed!");
330     CHECK_AND_RETURN_RET_LOG(ConvertPixelmapToSurfaceBuffer(pixelmap, buffer), nullptr,
331         "get surface buffer failed!");
332     return buffer;
333 }
334 
Create(napi_env env,napi_callback_info info)335 napi_value VpeNapi::Create(napi_env env, napi_callback_info info)
336 {
337     napi_value result = nullptr;
338     napi_get_undefined(env, &result);
339     napi_value constructor = nullptr;
340     napi_status status = napi_ok;
341     status = napi_get_reference_value(env, constructor_, &constructor);
342     if (status == napi_ok) {
343         size_t argc = NEW_INSTANCE_ARGC;
344         napi_value argv[NEW_INSTANCE_ARGC] = { 0 };
345         status = napi_new_instance(env, constructor, argc, argv, &result);
346     }
347     if (status != napi_ok) {
348         VPE_LOGE("create instance failed");
349         ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "create instance failed");
350         return nullptr;
351     }
352     VPE_LOGI("create done");
353     return result;
354 }
355 
PrepareDstPixelMap(napi_env env,DetailEnhanceContext * context)356 std::shared_ptr<PixelMap> VpeNapi::PrepareDstPixelMap(napi_env env, DetailEnhanceContext* context)
357 {
358     CHECK_AND_RETURN_RET_LOG(context->inputPixelMap->GetWidth() >= MIN_RESOLUTION_DETAIL &&
359         context->inputPixelMap->GetHeight() >= MIN_RESOLUTION_DETAIL &&
360         context->inputPixelMap->GetWidth() <= MAX_RESOLUTION_DETAIL &&
361         context->inputPixelMap->GetHeight() <= MAX_RESOLUTION_DETAIL,
362         nullptr, "invalid resolution");
363     InitializationOptions opts {
364         .size = {
365             .width = static_cast<int>(context->xArg),
366             .height = static_cast<int>(context->yArg),
367         },
368     };
369     VPE_LOGD("res:w %{public}d, h %{public}d, -> w %{public}d, h %{public}d",
370         context->inputPixelMap->GetWidth(), context->inputPixelMap->GetHeight(),
371         static_cast<int>(context->xArg), static_cast<int>(context->yArg));
372     std::unique_ptr<PixelMap> outputPtr = context->inputPixelMap->Create(*context->inputPixelMap, opts);
373     if (outputPtr == nullptr) {
374         ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_INVALID_VALUE, "create failed");
375         return nullptr;
376     }
377     std::shared_ptr<PixelMap> dstPixelMap{std::move(outputPtr)};
378     return dstPixelMap;
379 }
380 
InitDetailAlgo(napi_env env)381 bool VpeNapi::InitDetailAlgo(napi_env env)
382 {
383     VPETrace vpeTrace("VpeNapi::DetailEnhanceInitAlgo");
384     if (g_detailEnh != nullptr) {
385         VPE_LOGW("DetailEnhancerImage handle has created");
386         return true;
387     }
388     g_detailEnh = DetailEnhancerImage::Create();
389     CHECK_AND_RETURN_RET_LOG(g_detailEnh != nullptr, false, "create DetailEnhancerImage failed");
390     return true;
391 }
392 
SetDetailAlgoParam(napi_env env,int level)393 bool VpeNapi::SetDetailAlgoParam(napi_env env, int level)
394 {
395     DetailEnhancerParameters param {
396         .uri = "",
397         .level = static_cast<DetailEnhancerLevel>(level),
398     };
399     if (g_detailEnh->SetParameter(param)!= VPE_ALGO_ERR_OK) {
400         ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "set parameter failed");
401         return false;
402     }
403     return true;
404 }
405 
DetailEnhanceImpl(napi_env env,DetailEnhanceContext * context)406 std::shared_ptr<PixelMap> VpeNapi::DetailEnhanceImpl(napi_env env, DetailEnhanceContext* context)
407 {
408     VPETrace vpeTrace("VpeNapi::DetailEnhanceImpl");
409     if (context == nullptr) {
410         VPE_LOGE("context == nullptr");
411         return nullptr;
412     }
413     if (context->inputPixelMap->GetPixelFormat() == PixelFormat::YCBCR_P010 ||
414         context->inputPixelMap->GetPixelFormat() == PixelFormat::YCRCB_P010) {
415         VPE_LOGI("not support P010");
416         return context->inputPixelMap;
417     }
418     if (!InitDetailAlgo(env)) {
419         VPE_LOGE("init algo failed");
420         ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "init algo failed");
421         return nullptr;
422     }
423     if (!SetDetailAlgoParam(env, context->qualityLevel)) {
424         VPE_LOGE("set detail param failed");
425         return nullptr;
426     }
427     if (context->inputPixelMap == nullptr) {
428         VPE_LOGE("*context->inputPixelMap == nullptr");
429         return nullptr;
430     }
431     auto dstPixelMap = PrepareDstPixelMap(env, context);
432     if (dstPixelMap == nullptr) {
433         VPE_LOGE("move failed");
434         return nullptr;
435     }
436     auto output = GetSurfaceBufferFromDMAPixelMap(dstPixelMap);
437     auto input = GetSurfaceBufferFromDMAPixelMap(context->inputPixelMap);
438     CHECK_AND_RETURN_RET_LOG((g_detailEnh != nullptr && g_detailEnh->Process(input, output) == VPE_ALGO_ERR_OK),
439         nullptr, "process failed");
440     return dstPixelMap;
441 }
442 
EnhanceDetailWork(napi_env env,void * data)443 void VpeNapi::EnhanceDetailWork(napi_env env, void* data)
444 {
445     DetailEnhanceContext* innerAsyncContext = reinterpret_cast<DetailEnhanceContext*>(data);
446     if (innerAsyncContext == nullptr) {
447         std::string errCodeStr = std::to_string(IMAGE_PROCESSING_ERROR_PROCESS_FAILED);
448         std::string errMsg = "innerAsyncContext is nullptr";
449         napi_throw_error(env, errCodeStr.c_str(), errMsg.c_str());
450         return;
451     }
452     innerAsyncContext->outputPixelMap = DetailEnhanceImpl(env, innerAsyncContext);
453 };
454 
EnhanceDetailCallBackWork(napi_env env,napi_status status,void * data)455 void VpeNapi::EnhanceDetailCallBackWork(napi_env env, napi_status status, void* data)
456 {
457     DetailEnhanceContext* innerAsyncContext = reinterpret_cast<DetailEnhanceContext*>(data);
458     if (innerAsyncContext == nullptr) {
459         std::string errCodeStr = std::to_string(IMAGE_PROCESSING_ERROR_PROCESS_FAILED);
460         std::string errMsg = "innerAsyncContext is nullptr";
461         napi_throw_error(env, errCodeStr.c_str(), errMsg.c_str());
462         return;
463     }
464     napi_value outputPixelMapNapi = (innerAsyncContext->outputPixelMap == nullptr) ?
465         nullptr : PixelMapNapi::CreatePixelMap(env, innerAsyncContext->outputPixelMap);
466     if (outputPixelMapNapi == nullptr) {
467         return;
468     }
469     if (innerAsyncContext->deferred) {
470         napi_resolve_deferred(env, innerAsyncContext->deferred, outputPixelMapNapi);
471     } else {
472         napi_value callback = nullptr;
473         napi_get_reference_value(env, innerAsyncContext->callbackRef, &callback);
474         napi_call_function(env, nullptr, callback, 1, &(outputPixelMapNapi), nullptr);
475         napi_delete_reference(env, innerAsyncContext->callbackRef);
476         innerAsyncContext->callbackRef = nullptr;
477     }
478     napi_delete_async_work(env, innerAsyncContext->asyncWork);
479     delete innerAsyncContext;
480 };
481 
EnhanceDetail(napi_env env,napi_callback_info info)482 napi_value VpeNapi::EnhanceDetail(napi_env env, napi_callback_info info)
483 {
484     VPETrace vpeTrace("VpeNapi::DetailEnhanceProcess");
485     if (detailContext_ == nullptr) {
486         detailContext_ = std::make_shared<DetailEnhanceContext>();
487     }
488     CHECK_AND_RETURN_RET_LOG(detailContext_ != nullptr, nullptr, "context == nullptr");
489     napi_deferred deferred;
490     napi_value promise;
491     NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
492     if (!ParseDetailEnhanceParameter(env, info)) {
493         VPE_LOGE("parse parameter failed");
494         return nullptr;
495     }
496     detailContext_->deferred = deferred;
497     napi_value resourceName;
498     napi_create_string_latin1(env, "Asynchronous processing", NAPI_AUTO_LENGTH, &resourceName);
499     napi_status status = napi_create_async_work(env, nullptr, resourceName, EnhanceDetailWork,
500         EnhanceDetailCallBackWork, reinterpret_cast<void*>(detailContext_.get()), &detailContext_->asyncWork);
501     if (status != napi_ok) {
502         VPE_LOGE("create aysnc failed");
503         return nullptr;
504     }
505     napi_queue_async_work(env, detailContext_->asyncWork);
506     return promise;
507 }
508 
EnhanceDetailSync(napi_env env,napi_callback_info info)509 napi_value VpeNapi::EnhanceDetailSync(napi_env env, napi_callback_info info)
510 {
511     VPETrace vpeTrace("VpeNapi::DetailEnhanceProcess");
512     if (detailContext_ == nullptr) {
513         detailContext_ = std::make_shared<DetailEnhanceContext>();
514     }
515     CHECK_AND_RETURN_RET_LOG(detailContext_ != nullptr, nullptr, "context == nullptr");
516     CHECK_AND_RETURN_RET_LOG(ParseDetailEnhanceParameter(env, info), nullptr, "parse parameter failed");
517     std::shared_ptr<PixelMap> outputPixelMap = DetailEnhanceImpl(env, detailContext_.get());
518     if (outputPixelMap == nullptr) {
519         VPE_LOGE("DetailEnhanceImpl processed failed");
520         return nullptr;
521     }
522     napi_value outputPixelMapNapi = PixelMapNapi::CreatePixelMap(env, outputPixelMap);
523     return outputPixelMapNapi;
524 }
525 
PrepareRect(std::shared_ptr<PixelMap> input,OHOS::Rect & displayArea,float ratio)526 OHOS::Rect VpeNapi::PrepareRect(std::shared_ptr<PixelMap> input, OHOS::Rect& displayArea, float ratio)
527 {
528     OHOS::Rect rect;
529     rect.x = static_cast<int>(displayArea.x * ratio + ROUNDING_OPERATOR);
530     rect.y = static_cast<int>(displayArea.y * ratio + ROUNDING_OPERATOR);
531     rect.w = std::min(input->GetWidth() - 1 - rect.x,
532         static_cast<int>(displayArea.w * ratio + ROUNDING_OPERATOR));
533     rect.h = std::min(input->GetHeight() - 1 - rect.y,
534         static_cast<int>(displayArea.h * ratio + ROUNDING_OPERATOR));
535     return rect;
536 }
537 
UpdateMetadataBasedOnHist(ContrastEnhanceContext * context)538 bool VpeNapi::UpdateMetadataBasedOnHist(ContrastEnhanceContext* context)
539 {
540     CHECK_AND_RETURN_RET_LOG(context->inputPixelMap != nullptr && context->oriWidth >= MIN_WIDTH_CONTRAST &&
541         context->oriHeight >= MIN_HEIGHT_CONTRAST && context->oriHeight < MAX_RESOLUTION_CONTRAST &&
542         context->oriWidth < MAX_RESOLUTION_CONTRAST, false, "unsupport resolution");
543     CHECK_AND_RETURN_RET_LOG(context->inputPixelMap->IsHdr(), false, "It's not hdr pixelmap");
544     sptr<SurfaceBuffer> surfaceBuffer = GetSurfaceBufferFromDMAPixelMap(context->inputPixelMap);
545     OHOS::Rect rect = PrepareRect(context->inputPixelMap, context->displayArea, context->fullRatio);
546     VPE_LOGI("area x:%{public}d, y:%{public}d, w:%{public}d, h:%{public}d",
547         context->displayArea.x, context->displayArea.y, context->displayArea.w, context->displayArea.h);
548     VPE_LOGI("cur pixelmap:w:%{public}d, h:%{public}d, ori pixelmap:w:%{public}d, h:%{public}d",
549         context->inputPixelMap->GetWidth(), context->inputPixelMap->GetHeight(), context->oriWidth, context->oriHeight);
550     std::tuple<int, int, double, double, double, int> pixelmapInfo =
551         std::make_tuple(context->inputPixelMap->GetUniqueId(), context->contentId,
552         context->curRatio, context->maxRatio, context->defaultRatio, context->animationDuration);
553     return g_contrastEnh->UpdateMetadataBasedOnHist(rect, surfaceBuffer, pixelmapInfo);
554 }
555 
UpdateMetadataBasedOnPixel(ContrastEnhanceContext * context)556 bool VpeNapi::UpdateMetadataBasedOnPixel(ContrastEnhanceContext* context)
557 {
558     CHECK_AND_RETURN_RET_LOG(context->inputPixelMap != nullptr &&
559         context->inputPixelMap->GetWidth() >= MIN_WIDTH_CONTRAST &&
560         context->inputPixelMap->GetHeight() >= MIN_HEIGHT_CONTRAST && context->oriHeight < MAX_RESOLUTION_CONTRAST &&
561         context->oriWidth < MAX_RESOLUTION_CONTRAST, false, "unsupport resolution");
562     OHOS::Rect completePixelmapArea = {
563         .x = 0,
564         .y = 0,
565         .w = context->oriWidth,
566         .h = context->oriHeight,
567     };
568     sptr<SurfaceBuffer> surfaceBuffer = GetSurfaceBufferFromDMAPixelMap(context->inputPixelMap);
569     VPE_LOGI("area x:%{public}d, y:%{public}d, w:%{public}d, h:%{public}d",
570         context->displayArea.x, context->displayArea.y, context->displayArea.w, context->displayArea.h);
571     return g_contrastEnh->UpdateMetadataBasedOnPixel(context->displayArea, context->curPixelmapArea,
572         completePixelmapArea, surfaceBuffer, context->fullRatio);
573 }
574 
SetDetailImage(napi_env env,napi_callback_info info)575 napi_value VpeNapi::SetDetailImage(napi_env env, napi_callback_info info)
576 {
577     VPETrace vpeTrace("VpeNapi::ContrastProcess");
578     if (contrastContext_ == nullptr) {
579         contrastContext_ = std::make_shared<ContrastEnhanceContext>();
580         VPE_LOGI("create new contrast context");
581     }
582     CHECK_AND_RETURN_RET_LOG(contrastContext_ != nullptr, nullptr, "context == nullptr");
583     NapiValues nVal;
584     CHECK_AND_RETURN_RET_LOG(ParseDetailImageParameter(env, info, nVal), nullptr, "parse parameter failed");
585     CHECK_AND_RETURN_RET_LOG(InitContrastAlgo(env), nullptr, "init contrast algo failed");
586     // 不管是不是区域解码,都先使用直方图的结果进行展示,之后再转变成bitmap的结果
587     CallCallback(env, contrastContext_.get());
588     // 如果在计算完成前坐标位置已经发生了变化,则不需要继续进行计算
589     if (contrastContext_->callbackRef == nullptr) {
590         napi_create_promise(env, &(contrastContext_->deferred), &(nVal.result));
591     }
592     napi_value resourceName;
593     napi_create_string_latin1(env, "Asynchronous processing", NAPI_AUTO_LENGTH, &resourceName);
594     napi_status status = napi_create_async_work(
595         env, nullptr, resourceName,
596         [](napi_env env, void* data) {
597             ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
598             if (innerAsyncContext == nullptr) {
599                 ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_PROCESS_FAILED, "innerAsyncContext == nullptr");
600                 return;
601             }
602             UpdateMetadataBasedOnHist(innerAsyncContext);
603         },
604         [](napi_env env, napi_status status, void* data) {
605             ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
606             CallCallback(env, innerAsyncContext);
607             if (status != napi_ok) {
608                 VPE_LOGE("process failed");
609             }
610             VPE_LOGD("process detail image done");
611         },
612         (void*)(contrastContext_.get()), &contrastContext_->asyncWork);
613     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "create aysnc failed");
614     status = napi_queue_async_work(env, contrastContext_->asyncWork);
615     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "queue aysnc work failed");
616     return nullptr;
617 }
618 
GenerateRegionHist(napi_env env,ContrastEnhanceContext * context)619 bool VpeNapi::GenerateRegionHist(napi_env env, ContrastEnhanceContext* context)
620 {
621     CHECK_AND_RETURN_RET_LOG(InitContrastAlgo(env), false, "init contrast algo failed");
622     CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context == nullptr");
623     CHECK_AND_RETURN_RET_LOG(context->lcdPixelMap != nullptr, false, "lcdPixelMap == nullptr");
624     auto input = GetSurfaceBufferFromDMAPixelMap(context->lcdPixelMap);
625     CHECK_AND_RETURN_RET_LOG(input != nullptr, false, "input == nullptr");
626     CHECK_AND_RETURN_RET_LOG(g_contrastEnh != nullptr, false, "g_contrastEnh == nullptr");
627     if (g_contrastEnh->GetRegionHist(input) != 0) { // 9ms
628         VPE_LOGE("processed failed. Clear LUT history");
629         return false;
630     }
631     return true;
632 }
633 
InitContrastAlgo(napi_env env)634 bool VpeNapi::InitContrastAlgo(napi_env env)
635 {
636     VPETrace vpeTrace("VpeNapi::DetailEnhanceInitAlgo");
637     if (g_contrastEnh != nullptr) {
638         VPE_LOGD("ContrastEnhancerImage handle has created");
639         return true;
640     }
641     g_contrastEnh = ContrastEnhancerImage::Create();
642     CHECK_AND_RETURN_RET_LOG(g_contrastEnh != nullptr, false, "create ContrastEnhancerImage failed");
643     ContrastEnhancerParameters param {
644         .uri = "",
645         .type = ADAPTIVE_FOV,
646     };
647     if (g_contrastEnh->SetParameter(param)!= VPE_ALGO_ERR_OK) {
648         ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_CREATE_FAILED, "set parameter failed");
649         return false;
650     }
651     return true;
652 }
653 
ParseRect(napi_env env,napi_value nVal,OHOS::Rect & rect)654 bool VpeNapi::ParseRect(napi_env env, napi_value nVal, OHOS::Rect& rect)
655 {
656     CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "x", rect.x), false, "Failed to parse start pos X");
657     CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "y", rect.y), false, "Failed to parse start pos Y");
658     napi_value tmpValue = nullptr;
659     CHECK_AND_RETURN_RET_LOG(GET_NODE_BY_NAME(nVal, "size", tmpValue), false, "Failed to parse resolution of rect");
660     CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(tmpValue, "height", rect.h), false, "Failed to parse height of rect");
661     CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(tmpValue, "width", rect.w), false, "Failed to parse width of rect");
662     return true;
663 }
664 
ParseSize(napi_env env,napi_value nVal)665 bool VpeNapi::ParseSize(napi_env env, napi_value nVal)
666 {
667     napi_value tmpValue = nullptr;
668     CHECK_AND_RETURN_RET_LOG(GET_NODE_BY_NAME(nVal, "size", tmpValue), false, "Failed to parse resolution of rect");
669     CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "height", contrastContext_->oriHeight),
670         false, "Failed to parse height of rect");
671     CHECK_AND_RETURN_RET_LOG(GET_INT32_BY_NAME(nVal, "width", contrastContext_->oriWidth),
672         false, "Failed to parse width of rect");
673     return true;
674 }
675 
ParseDetailImageParameter(napi_env env,napi_callback_info info,NapiValues & nVal)676 bool VpeNapi::ParseDetailImageParameter(napi_env env, napi_callback_info info, NapiValues& nVal)
677 {
678     VPETrace vpeTrace("VpeNapi::DetailEnhance");
679     std::lock_guard<std::mutex> lock(g_contrastLock);
680     nVal.argc = NUM_9;
681     napi_value argValue[NUM_9] = {0};
682     nVal.argv = argValue;
683     if (!PrepareNapiEnv(env, info, &nVal)) {
684         return false;
685     }
686     if (nVal.argc != NUM_9) {
687         VPE_LOGE("Invalid args count %{public}zu", nVal.argc);
688         return false;
689     } else {
690         CHECK_AND_RETURN_RET_LOG(ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP,
691             false, "Arg 0 type mismatch");
692         contrastContext_->inputPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
693         CHECK_AND_RETURN_RET_LOG(contrastContext_->inputPixelMap != nullptr, false,
694             "contrastContext_->srcPixelMap == nullptr, resuse history");
695         CHECK_AND_RETURN_RET_LOG(napi_get_value_int32(env, nVal.argv[NUM_1],
696             &(contrastContext_->pixelmapId)) == napi_ok, false, "Arg 1 type mismatch");
697         CHECK_AND_RETURN_RET_LOG(ParseRect(env, argValue[NUM_2], contrastContext_->curPixelmapArea), false,
698             "parse pixelmap area failed");
699         CHECK_AND_RETURN_RET_LOG(ParseRect(env, argValue[NUM_3], contrastContext_->displayArea), false,
700             "parse display area failed");
701         CHECK_AND_RETURN_RET_LOG(ParseSize(env, argValue[NUM_4]), false, "parse resolution of original image failed");
702         CHECK_AND_RETURN_RET_LOG(napi_get_value_bool(env, nVal.argv[NUM_5],
703             &(contrastContext_->genFinalEffect)) == napi_ok, false, "Arg 5 type mismatch");
704         CHECK_AND_RETURN_RET_LOG(napi_get_value_double(env, nVal.argv[NUM_6],
705             &(contrastContext_->maxRatio)) == napi_ok, false, "Arg 6 type mismatch");
706         CHECK_AND_RETURN_RET_LOG(napi_get_value_int32(env, nVal.argv[NUM_7],
707             &(contrastContext_->animationDuration)) == napi_ok, false, "Arg 7 type mismatch");
708         CHECK_AND_RETURN_RET_LOG(napi_get_value_double(env, nVal.argv[NUM_8],
709             &(contrastContext_->curRatio)) == napi_ok, false, "Arg 8 type mismatch");
710     }
711     contrastContext_->fullRatio = std::min(
712         static_cast<float>(contrastContext_->inputPixelMap->GetWidth()) /
713             static_cast<float>(contrastContext_->curPixelmapArea.w),
714         static_cast<float>(contrastContext_->inputPixelMap->GetHeight()) /
715             static_cast<float>(contrastContext_->curPixelmapArea.h));
716 
717     VPE_LOGI("res: %{public}d x %{public}d, curArea: %{public}d x %{public}d, ratio:%{puiblic}f, maxRatio:%{public}f",
718         contrastContext_->inputPixelMap->GetWidth(), contrastContext_->inputPixelMap->GetHeight(),
719         contrastContext_->curPixelmapArea.w, contrastContext_->curPixelmapArea.h,
720         contrastContext_->curRatio, contrastContext_->maxRatio);
721     return true;
722 }
723 
ParseLCDParameter(napi_env env,napi_callback_info info,NapiValues & nVal)724 bool VpeNapi::ParseLCDParameter(napi_env env, napi_callback_info info, NapiValues& nVal)
725 {
726     VPETrace vpeTrace("VpeNapi::DetailEnhance");
727     std::lock_guard<std::mutex> lock(g_contrastLock);
728     nVal.argc = NUM_3;
729     napi_value argValue[NUM_3] = {0};
730     nVal.argv = argValue;
731     if (!PrepareNapiEnv(env, info, &nVal)) {
732         return false;
733     }
734     if (nVal.argc != NUM_3) {
735         VPE_LOGE("Invalid args count %{public}zu", nVal.argc);
736         return false;
737     } else {
738         CHECK_AND_RETURN_RET_LOG(ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP,
739             false, "Arg 0 type is not pixelmap");
740         contrastContext_->lcdPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
741         CHECK_AND_RETURN_RET_LOG(contrastContext_->lcdPixelMap != nullptr, false, "pixelmap is nullptr");
742         CHECK_AND_RETURN_RET_LOG(napi_get_value_int32(env, nVal.argv[NUM_1],
743             &(contrastContext_->contentId)) == napi_ok, false, "Failed to parse lcd param. Arg 1 type mismatch");
744         CHECK_AND_RETURN_RET_LOG(napi_get_value_double(env, nVal.argv[NUM_2],
745             &(contrastContext_->defaultRatio)) == napi_ok, false, "Failed to parse lcd param. Arg 2 type mismatch");
746         CHECK_AND_RETURN_RET_LOG(contrastContext_->lcdPixelMap->GetWidth() > 0 &&
747             contrastContext_->lcdPixelMap->GetHeight() > 0, false, "invalid resolution");
748         contrastContext_->lcdWidth = static_cast<unsigned int>(contrastContext_->lcdPixelMap->GetWidth());
749         contrastContext_->lcdHeight = static_cast<unsigned int>(contrastContext_->lcdPixelMap->GetHeight());
750     }
751     VPE_LOGI("update content info: lcdWidth:%{public}d, lcdHeight:%{public}d",
752         contrastContext_->lcdWidth, contrastContext_->lcdHeight);
753     return true;
754 }
755 
SetLcdImage(napi_env env,napi_callback_info info)756 napi_value VpeNapi::SetLcdImage(napi_env env, napi_callback_info info)
757 {
758     VPE_LOGI("set lcd image");
759     VPETrace vpeTrace("VpeNapi::DetailEnhanceProcess");
760     napi_value result = nullptr;
761     if (contrastContext_ == nullptr) {
762         contrastContext_ = std::make_shared<ContrastEnhanceContext>();
763         VPE_LOGI("create new contrast context");
764     }
765     if (contrastContext_ == nullptr) {
766         VPE_LOGE("context == nullptr");
767         return result;
768     }
769     NapiValues nVal;
770     if (!ParseLCDParameter(env, info, nVal)) {
771         VPE_LOGE("parse parameter failed");
772         return result;
773     }
774     napi_value resourceName;
775     napi_create_string_latin1(env, "Asynchronous processing", NAPI_AUTO_LENGTH, &resourceName);
776     napi_status status = napi_create_async_work(
777         env, nullptr, resourceName,
778         [](napi_env env, void* data) {
779             ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
780             if (innerAsyncContext == nullptr) {
781                 ThrowExceptionError(env, IMAGE_PROCESSING_ERROR_PROCESS_FAILED, "innerAsyncContext == nullptr");
782                 return;
783             }
784             GenerateRegionHist(env, innerAsyncContext);
785         },
786         [](napi_env env, napi_status status, void* data) {
787             ContrastEnhanceContext* innerAsyncContext = reinterpret_cast<ContrastEnhanceContext*>(data);
788             CallCallback(env, innerAsyncContext);
789             if (status != napi_ok) {
790                 VPE_LOGE("Failed to generate lut baseline for pcicture %{public}d", contrastContext_->contentId);
791             }
792             VPE_LOGI("Generate lut baseline for picture %{public}d successfully. Initial scaling ratio: %{public}f",
793                 contrastContext_->contentId, contrastContext_->defaultRatio);
794         },
795         (void*)(contrastContext_.get()), &contrastContext_->asyncWork);
796     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "create aysnc failed");
797     CHECK_AND_RETURN_RET_LOG(napi_queue_async_work(env, contrastContext_->asyncWork) == napi_ok,
798         nullptr, "queue aysnc work failed");
799     return result;
800 }
801 
RegisterCallback(napi_env env,napi_callback_info info)802 napi_value VpeNapi::RegisterCallback(napi_env env, napi_callback_info info)
803 {
804     size_t argc = 1;
805     napi_value argv[1];
806     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
807     if (contrastContext_->callbackRef != nullptr) {
808         napi_delete_reference(env, contrastContext_->callbackRef);
809     }
810     napi_create_reference(env, argv[0], 1, &(contrastContext_->callbackRef));
811     return nullptr;
812 }
813 
CallCallback(napi_env env,ContrastEnhanceContext * context)814 napi_value VpeNapi::CallCallback(napi_env env, ContrastEnhanceContext* context)
815 {
816     bool noCall = true;
817     if (noCall) {
818         return nullptr;
819     }
820 
821     if (context->callbackRef != nullptr) {
822         napi_value global;
823         napi_get_global(env, &global);
824         napi_value callbackFunc;
825         napi_get_reference_value(env, context->callbackRef, &callbackFunc);
826         napi_value result;
827         napi_call_function(env, global, callbackFunc, 0, nullptr, &result);
828     }
829     return nullptr;
830 }
831 
Constructor(napi_env env,napi_callback_info info)832 napi_value VpeNapi::Constructor(napi_env env, napi_callback_info info)
833 {
834     napi_value undefineVar = nullptr;
835     napi_get_undefined(env, &undefineVar);
836 
837     napi_status status;
838     napi_value thisVar = nullptr;
839     napi_get_undefined(env, &thisVar);
840     size_t argc = NEW_INSTANCE_ARGC;
841     napi_value argv[NEW_INSTANCE_ARGC] = { 0 };
842     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
843     if (status != napi_ok || thisVar == nullptr) {
844         return undefineVar;
845     }
846     VpeNapi* pDetailEnhanceNapi = new VpeNapi();
847     status = napi_wrap_with_size(env, thisVar, reinterpret_cast<void*>(pDetailEnhanceNapi),
848         VpeNapi::Destructor, nullptr, nullptr, static_cast<size_t>(sizeof(VpeNapi)));
849     CHECK_AND_RETURN_RET_LOG(status == napi_ok, undefineVar, "Failure wrapping js to native napi");
850     return thisVar;
851 }
852 
Destructor(napi_env env,void * nativeObject,void * finalize)853 void VpeNapi::Destructor(napi_env env, void* nativeObject, void* finalize)
854 {
855     if (nativeObject != nullptr) {
856         std::lock_guard<std::mutex> lock(g_imageProcessorMutex);
857         delete reinterpret_cast<VpeNapi*>(nativeObject);
858         nativeObject = nullptr;
859     }
860 }
861 
DoInitAfter(napi_env env,napi_value exports,napi_value constructor,size_t property_count,const napi_property_descriptor * properties)862 napi_value VpeNapi::DoInitAfter(napi_env env, napi_value exports, napi_value constructor,
863     size_t property_count, const napi_property_descriptor* properties)
864 {
865     napi_value global = nullptr;
866     CHECK_AND_RETURN_RET_LOG(napi_get_global(env, &global) == napi_ok, nullptr, "Init:get global fail");
867     CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor) == napi_ok,
868         nullptr, "Init:set global named property fail");
869     CHECK_AND_RETURN_RET_LOG(napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor) == napi_ok,
870         nullptr, "set named property fail");
871     CHECK_AND_RETURN_RET_LOG(napi_define_properties(env, exports, property_count, properties) == napi_ok,
872         nullptr, "define properties fail");
873     return exports;
874 }
875 
CreateEnumTypeObject(napi_env env,napi_valuetype type,napi_ref * ref,std::vector<struct QualityLevelEnum> & imageEnumMap)876 napi_value VpeNapi::CreateEnumTypeObject(napi_env env, napi_valuetype type, napi_ref* ref,
877     std::vector<struct QualityLevelEnum>& imageEnumMap)
878 {
879     napi_value result = nullptr;
880     napi_status status;
881     int32_t refCount = 1;
882     std::string propName;
883     status = napi_create_object(env, &result);
884     if (status == napi_ok) {
885         for (auto imgEnum : imageEnumMap) {
886             napi_value enumNapiValue = nullptr;
887             if (type == napi_string) {
888                 status = napi_create_string_utf8(env, imgEnum.strVal.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
889             } else if (type == napi_number) {
890                 status = napi_create_int32(env, imgEnum.numVal, &enumNapiValue);
891             } else {
892                 VPE_LOGE("Unsupported type %{public}d!", type);
893             }
894             if (status == napi_ok && enumNapiValue != nullptr) {
895                 status = napi_set_named_property(env, result, imgEnum.name.c_str(), enumNapiValue);
896             }
897             if (status != napi_ok) {
898                 VPE_LOGE("Failed to add named prop!");
899                 break;
900             }
901         }
902         if (status == napi_ok) {
903             status = napi_create_reference(env, result, refCount, ref);
904             if (status == napi_ok) {
905                 return result;
906             }
907         }
908     }
909     VPE_LOGE("CreateEnumTypeObject is Failed!");
910     napi_get_undefined(env, &result);
911     return result;
912 }
913 
RegisterNapi()914 std::vector<napi_property_descriptor> VpeNapi::RegisterNapi()
915 {
916     std::vector<napi_property_descriptor> props = {
917         DECLARE_NAPI_FUNCTION("enhanceDetail", VpeNapi::EnhanceDetail),
918         DECLARE_NAPI_FUNCTION("enhanceDetailSync", VpeNapi::EnhanceDetailSync),
919         DECLARE_NAPI_FUNCTION("setLcdImage", VpeNapi::SetLcdImage),
920         DECLARE_NAPI_FUNCTION("setDetailImage", VpeNapi::SetDetailImage),
921         DECLARE_NAPI_FUNCTION("registerCallback", VpeNapi::RegisterCallback)
922     };
923     return props;
924 }
925 
Init(napi_env env,napi_value exports)926 napi_value VpeNapi::Init(napi_env env, napi_value exports)
927 {
928     std::vector<napi_property_descriptor> props = VpeNapi::RegisterNapi();
929     napi_value constructor = nullptr;
930     CHECK_AND_RETURN_RET_LOG(napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
931         VpeNapi::Constructor, nullptr, props.size(), props.data(), &constructor) == napi_ok,
932         nullptr, "define class fail");
933     CHECK_AND_RETURN_RET_LOG(napi_create_reference(env, constructor, 1, &constructor_) == napi_ok,
934         nullptr, "create reference fail");
935 
936     napi_value qualityLevel = CreateEnumTypeObject(env, napi_number, &qualityLevelTypeRef_, g_qualityLevels);
937     CHECK_AND_RETURN_RET_LOG(qualityLevel != nullptr, nullptr, "CreateEnumTypeObject failed");
938     napi_property_descriptor desc[] = {
939         DECLARE_NAPI_PROPERTY("QualityLevel", qualityLevel),
940         DECLARE_NAPI_FUNCTION("create", VpeNapi::Create),
941         DECLARE_NAPI_FUNCTION("initializeEnvironment", VpeNapi::InitializeEnvironment),
942         DECLARE_NAPI_FUNCTION("deinitializeEnvironment", VpeNapi::DeinitializeEnvironment),
943     };
944     auto result = DoInitAfter(env, exports, constructor, sizeof(desc) / sizeof(desc[0]), desc);
945     return result;
946 }
947 }
948 }