1 /*
2 * Copyright (C) 2022 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 #include "image_creator_napi.h"
17 #include <uv.h>
18 #include "media_errors.h"
19 #include "image_log.h"
20 #include "image_napi_utils.h"
21 #include "image_creator_context.h"
22 #include "image_napi.h"
23 #include "image_creator_manager.h"
24
25 using std::string;
26 using std::shared_ptr;
27 using std::unique_ptr;
28 using std::vector;
29 using std::make_shared;
30 using std::make_unique;
31
32 #undef LOG_DOMAIN
33 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
34
35 #undef LOG_TAG
36 #define LOG_TAG "ImageCreatorNapi"
37
38 namespace {
39 constexpr int32_t TEST_WIDTH = 8192;
40 constexpr int32_t TEST_HEIGHT = 8;
41 constexpr int32_t TEST_FORMAT = 4;
42 constexpr int32_t TEST_CAPACITY = 8;
43 }
44
45 namespace OHOS {
46 namespace Media {
47 static const std::string CLASS_NAME = "ImageCreator";
48 shared_ptr<ImageCreator> ImageCreatorNapi::staticInstance_ = nullptr;
49 thread_local napi_ref ImageCreatorNapi::sConstructor_ = nullptr;
50 static bool g_isCreatorTest = false;
51 static std::shared_ptr<ImageCreatorReleaseListener> g_listener = nullptr;
52
53 const int ARGS0 = 0;
54 const int ARGS1 = 1;
55 const int ARGS2 = 2;
56 const int ARGS3 = 3;
57 const int ARGS4 = 4;
58 const int PARAM0 = 0;
59 const int PARAM1 = 1;
60 const int PARAM2 = 2;
61 const int PARAM3 = 3;
62
ImageCreatorNapi()63 ImageCreatorNapi::ImageCreatorNapi():env_(nullptr)
64 {}
65
~ImageCreatorNapi()66 ImageCreatorNapi::~ImageCreatorNapi()
67 {
68 release();
69 }
70
CommonCallbackRoutine(napi_env env,Contextc & context,const napi_value & valueParam,bool isRelease=true)71 static void CommonCallbackRoutine(napi_env env, Contextc &context, const napi_value &valueParam, bool isRelease = true)
72 {
73 IMAGE_FUNCTION_IN();
74 napi_value result[2] = {0};
75 napi_value retVal;
76 napi_value callback = nullptr;
77
78 napi_get_undefined(env, &result[0]);
79 napi_get_undefined(env, &result[1]);
80
81 if (context->status == SUCCESS) {
82 result[1] = valueParam;
83 }
84
85 if (context->deferred) {
86 if (context->status == SUCCESS) {
87 napi_resolve_deferred(env, context->deferred, result[1]);
88 } else {
89 napi_reject_deferred(env, context->deferred, result[0]);
90 }
91 } else {
92 napi_create_uint32(env, context->status, &result[0]);
93 napi_get_reference_value(env, context->callbackRef, &callback);
94 napi_call_function(env, nullptr, callback, PARAM2, result, &retVal);
95 }
96
97 if (isRelease) {
98 if (context->callbackRef != nullptr) {
99 napi_delete_reference(env, context->callbackRef);
100 context->callbackRef = nullptr;
101 }
102
103 napi_delete_async_work(env, context->work);
104
105 delete context;
106 context = nullptr;
107 }
108 IMAGE_FUNCTION_OUT();
109 }
110
NativeRelease()111 void ImageCreatorNapi::NativeRelease()
112 {
113 if (imageCreator_ != nullptr) {
114 imageCreator_->~ImageCreator();
115 imageCreator_ = nullptr;
116 }
117 }
118
Init(napi_env env,napi_value exports)119 napi_value ImageCreatorNapi::Init(napi_env env, napi_value exports)
120 {
121 IMAGE_FUNCTION_IN();
122 napi_property_descriptor props[] = {
123 DECLARE_NAPI_FUNCTION("dequeueImage", JsDequeueImage),
124 DECLARE_NAPI_FUNCTION("queueImage", JsQueueImage),
125 DECLARE_NAPI_FUNCTION("on", JsOn),
126 DECLARE_NAPI_FUNCTION("off", JsOff),
127 DECLARE_NAPI_FUNCTION("release", JsRelease),
128
129 #ifdef IMAGE_DEBUG_FLAG
130 DECLARE_NAPI_GETTER("test", JsTest),
131 #endif
132 DECLARE_NAPI_GETTER("capacity", JsGetCapacity),
133 DECLARE_NAPI_GETTER("format", JsGetFormat),
134 DECLARE_NAPI_GETTER("size", JsGetSize),
135 };
136 napi_property_descriptor static_prop[] = {
137 DECLARE_NAPI_STATIC_FUNCTION("createImageCreator", JSCreateImageCreator),
138 };
139
140 napi_value constructor = nullptr;
141 size_t props_count = IMG_ARRAY_SIZE(props);
142 size_t static_props_count = IMG_ARRAY_SIZE(static_prop);
143
144 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
145 napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor,
146 nullptr, props_count, props, &constructor)),
147 nullptr,
148 IMAGE_ERR("define class fail")
149 );
150
151 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
152 napi_create_reference(env, constructor, 1, &sConstructor_)),
153 nullptr,
154 IMAGE_ERR("create reference fail")
155 );
156
157 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
158 napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
159 nullptr,
160 IMAGE_ERR("set named property fail")
161 );
162 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
163 napi_define_properties(env, exports, static_props_count, static_prop)),
164 nullptr,
165 IMAGE_ERR("define properties fail")
166 );
167
168 IMAGE_DEBUG("Init success");
169
170 IMAGE_FUNCTION_OUT();
171 return exports;
172 }
173
Constructor(napi_env env,napi_callback_info info)174 napi_value ImageCreatorNapi::Constructor(napi_env env, napi_callback_info info)
175 {
176 napi_value undefineVar = nullptr;
177 napi_get_undefined(env, &undefineVar);
178
179 napi_status status;
180 napi_value thisVar = nullptr;
181
182 IMAGE_FUNCTION_IN();
183 status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
184 if (status == napi_ok && thisVar != nullptr) {
185 std::unique_ptr<ImageCreatorNapi> reference = std::make_unique<ImageCreatorNapi>();
186 if (reference != nullptr) {
187 reference->env_ = env;
188 if (!g_isCreatorTest) {
189 reference->imageCreator_ = staticInstance_;
190 }
191 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(reference.get()),
192 ImageCreatorNapi::Destructor, nullptr, nullptr);
193 if (status == napi_ok) {
194 IMAGE_FUNCTION_OUT();
195 reference.release();
196 return thisVar;
197 } else {
198 IMAGE_ERR("Failure wrapping js to native napi");
199 }
200 }
201 }
202
203 return undefineVar;
204 }
205
Destructor(napi_env env,void * nativeObject,void * finalize)206 void ImageCreatorNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
207 {
208 }
209
isTest(const int32_t * args,const int32_t len)210 static bool isTest(const int32_t* args, const int32_t len)
211 {
212 if ((args[PARAM0] == TEST_WIDTH) &&
213 (args[PARAM1] == TEST_HEIGHT) &&
214 (args[PARAM2] == TEST_FORMAT) &&
215 (args[PARAM3] == TEST_CAPACITY) &&
216 (len == ARGS4)) {
217 return true;
218 }
219 return false;
220 }
JSCreateImageCreator(napi_env env,napi_callback_info info)221 napi_value ImageCreatorNapi::JSCreateImageCreator(napi_env env, napi_callback_info info)
222 {
223 napi_status status;
224 napi_value constructor = nullptr;
225 napi_value result = nullptr;
226 napi_value thisVar = nullptr;
227 size_t argc = ARGS4;
228 napi_value argv[ARGS4] = {0};
229 int32_t args[ARGS4] = {0};
230
231 IMAGE_FUNCTION_IN();
232 napi_get_undefined(env, &result);
233 status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
234 if (status != napi_ok || ((argc != ARGS3) && (argc != ARGS4))) {
235 std::string errMsg = "Invailed arg counts ";
236 return ImageNapiUtils::ThrowExceptionError(env, COMMON_ERR_INVALID_PARAMETER,
237 errMsg.append(std::to_string(argc)));
238 }
239 std::string errMsg;
240 if (!ImageNapiUtils::ParseImageCreatorReceiverArgs(env, argc, argv, args, errMsg)) {
241 return ImageNapiUtils::ThrowExceptionError(env, COMMON_ERR_INVALID_PARAMETER, errMsg);
242 }
243 int32_t len = sizeof(args) / sizeof(args[PARAM0]);
244 if (isTest(args, len)) {
245 g_isCreatorTest = true;
246 }
247 status = napi_get_reference_value(env, sConstructor_, &constructor);
248 if (IMG_IS_OK(status)) {
249 if (!g_isCreatorTest) {
250 staticInstance_ = ImageCreator::CreateImageCreator(args[PARAM0],
251 args[PARAM1], args[PARAM2], args[PARAM3]);
252 }
253 status = napi_new_instance(env, constructor, 0, nullptr, &result);
254 if (status == napi_ok) {
255 IMAGE_FUNCTION_OUT();
256 return result;
257 } else {
258 IMAGE_ERR("New instance could not be obtained");
259 }
260 }
261 return result;
262 }
263
CheckArgs(const ImageCreatorCommonArgs & args)264 static bool CheckArgs(const ImageCreatorCommonArgs &args)
265 {
266 if (args.async != CreatorCallType::GETTER) {
267 if (args.queryArgs == nullptr) {
268 IMAGE_ERR("No query args function");
269 return false;
270 }
271 }
272
273 if (args.async != CreatorCallType::ASYNC || args.asyncLater) {
274 if (args.nonAsyncBack == nullptr) {
275 IMAGE_ERR("No non async back function");
276 return false;
277 }
278 }
279 return true;
280 }
281
PrepareOneArg(ImageCreatorCommonArgs & args,struct ImageCreatorInnerContext & ic)282 static bool PrepareOneArg(ImageCreatorCommonArgs &args, struct ImageCreatorInnerContext &ic)
283 {
284 if (ic.argc == ARGS1) {
285 auto argType = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
286 if (argType == napi_function) {
287 napi_create_reference(args.env, ic.argv[PARAM0], ic.refCount, &(ic.context->callbackRef));
288 } else {
289 IMAGE_ERR("Unsupport arg 0 type: %{public}d", argType);
290 return false;
291 }
292 }
293
294 if (ic.context->callbackRef == nullptr) {
295 napi_create_promise(args.env, &(ic.context->deferred), &(ic.result));
296 } else {
297 napi_get_undefined(args.env, &ic.result);
298 }
299 return true;
300 }
301
JSCommonProcess(ImageCreatorCommonArgs & args)302 napi_value ImageCreatorNapi::JSCommonProcess(ImageCreatorCommonArgs &args)
303 {
304 IMAGE_FUNCTION_IN();
305 struct ImageCreatorInnerContext ic;
306 ic.argc = args.argc;
307 ic.argv.resize(ic.argc);
308 napi_get_undefined(args.env, &ic.result);
309 IMG_NAPI_CHECK_RET(CheckArgs(args), ic.result);
310
311 IMG_JS_ARGS(args.env, args.info, ic.status, ic.argc, &(ic.argv[0]), ic.thisVar);
312
313 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(ic.status), ic.result, IMAGE_ERR("fail to napi_get_cb_info"));
314
315 if (args.async != CreatorCallType::STATIC) {
316 ic.context = std::make_unique<ImageCreatorAsyncContext>();
317 if (ic.context == nullptr) {
318 return ic.result;
319 }
320 ic.status = napi_unwrap(args.env, ic.thisVar, reinterpret_cast<void**>(&(ic.context->constructor_)));
321
322 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->constructor_),
323 ic.result, IMAGE_ERR("fail to unwrap context"));
324 if (ic.context->constructor_ == nullptr) {
325 return ic.result;
326 }
327 if (!g_isCreatorTest) {
328 ic.context->creator_ = ic.context->constructor_->imageCreator_;
329
330 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->creator_),
331 ic.result, IMAGE_ERR("empty native creator"));
332 }
333 }
334 if (args.async != CreatorCallType::GETTER && !args.queryArgs(args, ic)) {
335 return ic.result;
336 }
337 if (args.async == CreatorCallType::ASYNC) {
338 if (args.asyncLater) {
339 args.nonAsyncBack(args, ic);
340 } else {
341 napi_value _resource = nullptr;
342 napi_create_string_utf8((args.env), (args.name.c_str()), NAPI_AUTO_LENGTH, &_resource);
343 (ic.status) = napi_create_async_work(args.env, nullptr, _resource,
344 ([](napi_env env, void *data) {}),
345 (reinterpret_cast<napi_async_complete_callback>(args.callBack)),
346 static_cast<void *>((ic.context).get()), &(ic.context->work));
347 napi_queue_async_work((args.env), (ic.context->work));
348 ic.context.release();
349 }
350 } else {
351 args.nonAsyncBack(args, ic);
352 }
353 IMAGE_FUNCTION_OUT();
354 return ic.result;
355 }
356
BuildJsSize(napi_env env,int32_t width,int32_t height)357 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
358 {
359 napi_value result = nullptr;
360 napi_value sizeWith = nullptr;
361 napi_value sizeHeight = nullptr;
362
363 napi_create_object(env, &result);
364
365 napi_create_int32(env, width, &sizeWith);
366 napi_set_named_property(env, result, "width", sizeWith);
367
368 napi_create_int32(env, height, &sizeHeight);
369 napi_set_named_property(env, result, "height", sizeHeight);
370 return result;
371 }
372
JsGetSize(napi_env env,napi_callback_info info)373 napi_value ImageCreatorNapi::JsGetSize(napi_env env, napi_callback_info info)
374 {
375 IMAGE_FUNCTION_IN();
376 ImageCreatorCommonArgs args = {
377 .env = env, .info = info,
378 .async = CreatorCallType::GETTER,
379 };
380 args.argc = ARGS0;
381
382 args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
383 napi_get_undefined(args.env, &(ic.result));
384 if (g_isCreatorTest) {
385 ic.result = BuildJsSize(args.env, TEST_WIDTH, TEST_HEIGHT);
386 return true;
387 }
388
389 auto native = ic.context->constructor_->imageCreator_;
390 if (native == nullptr) {
391 IMAGE_ERR("Native instance is nullptr");
392 return false;
393 }
394
395 if (native->iraContext_ == nullptr) {
396 IMAGE_ERR("Image creator context is nullptr");
397 return false;
398 }
399 ic.result = BuildJsSize(args.env,
400 native->iraContext_->GetWidth(),
401 native->iraContext_->GetHeight());
402 return true;
403 };
404
405 return JSCommonProcess(args);
406 }
407
JsGetCapacity(napi_env env,napi_callback_info info)408 napi_value ImageCreatorNapi::JsGetCapacity(napi_env env, napi_callback_info info)
409 {
410 IMAGE_FUNCTION_IN();
411 ImageCreatorCommonArgs args = {
412 .env = env, .info = info,
413 .async = CreatorCallType::GETTER,
414 };
415 args.argc = ARGS0;
416
417 args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
418 napi_get_undefined(args.env, &(ic.result));
419 if (g_isCreatorTest) {
420 napi_create_int32(args.env, TEST_CAPACITY, &(ic.result));
421 return true;
422 }
423 auto native = ic.context->constructor_->imageCreator_;
424 if (native == nullptr) {
425 IMAGE_ERR("Native instance is nullptr");
426 return false;
427 }
428
429 if (native->iraContext_ == nullptr) {
430 IMAGE_ERR("Image creator context is nullptr");
431 return false;
432 }
433 napi_create_int32(args.env, native->iraContext_->GetCapicity(), &(ic.result));
434 return true;
435 };
436
437 return JSCommonProcess(args);
438 }
439
JsGetFormat(napi_env env,napi_callback_info info)440 napi_value ImageCreatorNapi::JsGetFormat(napi_env env, napi_callback_info info)
441 {
442 IMAGE_FUNCTION_IN();
443 ImageCreatorCommonArgs args = {
444 .env = env, .info = info,
445 .async = CreatorCallType::GETTER,
446 };
447 args.argc = ARGS0;
448
449 args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
450 napi_get_undefined(args.env, &(ic.result));
451 if (g_isCreatorTest) {
452 napi_create_int32(args.env, TEST_FORMAT, &(ic.result));
453 return true;
454 }
455 auto native = ic.context->constructor_->imageCreator_;
456 if (native == nullptr) {
457 IMAGE_ERR("Native instance is nullptr");
458 return false;
459 }
460
461 if (native->iraContext_ == nullptr) {
462 IMAGE_ERR("Image creator context is nullptr");
463 return false;
464 }
465 napi_create_int32(args.env, native->iraContext_->GetFormat(), &(ic.result));
466 return true;
467 };
468
469 return JSCommonProcess(args);
470 }
471
472 #ifdef IMAGE_DEBUG_FLAG
TestAcquireBuffer(OHOS::sptr<OHOS::IConsumerSurface> & creatorSurface,int32_t & fence,int64_t & timestamp,OHOS::Rect & damage,std::shared_ptr<ImageCreator> imageCreator)473 static void TestAcquireBuffer(OHOS::sptr<OHOS::IConsumerSurface> &creatorSurface, int32_t &fence,
474 int64_t ×tamp, OHOS::Rect &damage, std::shared_ptr<ImageCreator> imageCreator)
475 {
476 OHOS::sptr<OHOS::SurfaceBuffer> buffer;
477 if (creatorSurface == nullptr) {
478 IMAGE_ERR("Creator Surface is nullptr");
479 return;
480 }
481 creatorSurface->AcquireBuffer(buffer, fence, timestamp, damage);
482 if (buffer == nullptr) {
483 IMAGE_ERR("Creator Surface is nullptr");
484 return;
485 }
486 IMAGE_ERR("...AcquireBuffer...");
487 InitializationOptions opts;
488 opts.size.width = creatorSurface->GetDefaultWidth();
489 opts.size.height = creatorSurface->GetDefaultHeight();
490 opts.pixelFormat = OHOS::Media::PixelFormat::BGRA_8888;
491 opts.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
492 opts.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
493 opts.editable = true;
494 imageCreator->SaveSenderBufferAsImage(buffer, opts);
495 }
496
DoTest(std::shared_ptr<ImageCreator> imageCreator)497 static void DoTest(std::shared_ptr<ImageCreator> imageCreator)
498 {
499 if (imageCreator == nullptr || imageCreator->iraContext_ == nullptr) {
500 IMAGE_ERR("image creator is nullptr");
501 return;
502 }
503 std::string creatorKey = imageCreator->iraContext_->GetCreatorKey();
504 IMAGE_ERR("CreatorKey = %{public}s", creatorKey.c_str());
505 OHOS::sptr<OHOS::IConsumerSurface> creatorSurface = ImageCreator::getSurfaceById(creatorKey);
506 IMAGE_ERR("getDefaultWidth = %{public}d", creatorSurface->GetDefaultWidth());
507 IMAGE_ERR("getDefaultHeight = %{public}d", creatorSurface->GetDefaultHeight());
508 int32_t flushFence = 0;
509 int64_t timestamp = 0;
510 OHOS::Rect damage = {};
511 IMAGE_ERR("TestAcquireBuffer 1...");
512 TestAcquireBuffer(creatorSurface, flushFence, timestamp, damage, imageCreator);
513 }
514 static void DoCallBackAfterWork(uv_work_t *work, int status);
JsTest(napi_env env,napi_callback_info info)515 napi_value ImageCreatorNapi::JsTest(napi_env env, napi_callback_info info)
516 {
517 IMAGE_FUNCTION_IN();
518 ImageCreatorCommonArgs args = {
519 .env = env, .info = info,
520 .async = CreatorCallType::GETTER,
521 };
522 args.argc = ARGS0;
523
524 args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
525 DoTest(ic.context->creator_);
526 if (g_isCreatorTest && g_listener != nullptr) {
527 unique_ptr<uv_work_t> work = make_unique<uv_work_t>();
528 work->data = reinterpret_cast<void *>(g_listener->context.get());
529 DoCallBackAfterWork(work.release(), ARGS0);
530 g_listener = nullptr;
531 }
532 return true;
533 };
534
535 return JSCommonProcess(args);
536 }
537 #endif
538
JsDequeueImage(napi_env env,napi_callback_info info)539 napi_value ImageCreatorNapi::JsDequeueImage(napi_env env, napi_callback_info info)
540 {
541 IMAGE_FUNCTION_IN();
542 ImageCreatorCommonArgs args = {
543 .env = env, .info = info,
544 .async = CreatorCallType::ASYNC,
545 .name = "JsDequeueImage",
546 .callBack = nullptr,
547 .argc = ARGS1,
548 .queryArgs = PrepareOneArg,
549 };
550
551 args.callBack = [](napi_env env, napi_status status, Contextc context) {
552 IMAGE_LINE_IN();
553 napi_value result = nullptr;
554 napi_get_undefined(env, &result);
555 if (g_isCreatorTest) {
556 result = ImageNapi::Create(env);
557 context->status = SUCCESS;
558 CommonCallbackRoutine(env, context, result);
559 return;
560 }
561
562 auto native = context->constructor_->imageCreator_;
563 if (native != nullptr) {
564 result = ImageNapi::Create(env, native->DequeueNativeImage());
565 if (result == nullptr) {
566 IMAGE_ERR("ImageNapi Create failed");
567 }
568 } else {
569 IMAGE_ERR("Native instance is nullptr");
570 }
571
572 if (result == nullptr) {
573 napi_get_undefined(env, &result);
574 context->status = ERR_IMAGE_INIT_ABNORMAL;
575 } else {
576 context->status = SUCCESS;
577 }
578
579 IMAGE_LINE_OUT();
580 CommonCallbackRoutine(env, context, result);
581 };
582
583 return JSCommonProcess(args);
584 }
585
IsTestImageArgs(napi_env env,napi_value value)586 static bool IsTestImageArgs(napi_env env, napi_value value)
587 {
588 if (g_isCreatorTest) {
589 ImageNapi* image = nullptr;
590 napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&image));
591 return (status == napi_ok && image != nullptr);
592 }
593 return false;
594 }
595
JsQueueArgs(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<NativeImage> & imageNapi_,napi_ref * callbackRef)596 static bool JsQueueArgs(napi_env env, size_t argc, napi_value* argv,
597 std::shared_ptr<NativeImage> &imageNapi_, napi_ref* callbackRef)
598 {
599 if (argc == ARGS1 || argc == ARGS2) {
600 auto argType0 = ImageNapiUtils::getType(env, argv[PARAM0]);
601 if (argType0 == napi_object) {
602 imageNapi_ = ImageNapi::GetNativeImage(env, argv[PARAM0]);
603 if (imageNapi_ == nullptr && !IsTestImageArgs(env, argv[PARAM0])) {
604 ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
605 "Could not get queue type object");
606 return false;
607 }
608 } else {
609 std::string errMsg = "Unsupport args0 type: ";
610 ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
611 errMsg.append(std::to_string(argType0)));
612 return false;
613 }
614 if (argc == ARGS2) {
615 auto argType1 = ImageNapiUtils::getType(env, argv[PARAM1]);
616 if (argType1 == napi_function) {
617 int32_t refCount = 1;
618 napi_create_reference(env, argv[PARAM1], refCount, callbackRef);
619 } else {
620 std::string errMsg = "Unsupport args1 type: ";
621 ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
622 errMsg.append(std::to_string(argType1)));
623 return false;
624 }
625 }
626 } else {
627 std::string errMsg = "Invailed argc: ";
628 ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
629 errMsg.append(std::to_string(argc)));
630 return false;
631 }
632 return true;
633 }
634
JsQueueImageCallBack(napi_env env,napi_status status,ImageCreatorAsyncContext * context)635 void ImageCreatorNapi::JsQueueImageCallBack(napi_env env, napi_status status,
636 ImageCreatorAsyncContext* context)
637 {
638 IMAGE_FUNCTION_IN();
639 napi_value result = nullptr;
640 napi_get_undefined(env, &result);
641 if (g_isCreatorTest) {
642 context->status = SUCCESS;
643 CommonCallbackRoutine(env, context, result);
644 return;
645 }
646
647 auto native = context->constructor_->imageCreator_;
648 if (native == nullptr || context->imageNapi_ == nullptr) {
649 IMAGE_ERR("Native instance is nullptr");
650 context->status = ERR_IMAGE_INIT_ABNORMAL;
651 } else {
652 if (SUCCESS != context->imageNapi_->CombineYUVComponents()) {
653 IMAGE_ERR("JsQueueImageCallBack: try to combine componests");
654 }
655 native->QueueNativeImage(context->imageNapi_);
656 context->status = SUCCESS;
657 }
658 IMAGE_LINE_OUT();
659 CommonCallbackRoutine(env, context, result);
660 }
661
JsQueueImage(napi_env env,napi_callback_info info)662 napi_value ImageCreatorNapi::JsQueueImage(napi_env env, napi_callback_info info)
663 {
664 IMAGE_FUNCTION_IN();
665 napi_value result = nullptr;
666 napi_value thisVar = nullptr;
667 size_t argc = ARGS2;
668 napi_value argv[ARGS2] = {0};
669
670 napi_get_undefined(env, &result);
671
672 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
673 if (status != napi_ok) {
674 IMAGE_ERR("fail to napi_get_cb_info %{public}d", status);
675 return result;
676 }
677
678 unique_ptr<ImageCreatorAsyncContext> context = make_unique<ImageCreatorAsyncContext>();
679 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
680 if (status != napi_ok || context->constructor_ == nullptr) {
681 IMAGE_ERR("fail to unwrap constructor_ %{public}d", status);
682 return result;
683 }
684
685 if (!JsQueueArgs(env, argc, argv, context->imageNapi_, &(context->callbackRef))) {
686 return result;
687 }
688 if (context->callbackRef == nullptr) {
689 napi_create_promise(env, &(context->deferred), &result);
690 }
691
692 napi_value resource = nullptr;
693 napi_create_string_utf8(env, "JsQueueImage", NAPI_AUTO_LENGTH, &resource);
694 status = napi_create_async_work(
695 env, nullptr, resource, [](napi_env env, void* data) {},
696 reinterpret_cast<napi_async_complete_callback>(JsQueueImageCallBack),
697 static_cast<void *>(context.get()), &(context->work));
698 if (status != napi_ok) {
699 IMAGE_ERR("fail to create async work %{public}d", status);
700 return result;
701 }
702
703 status = napi_queue_async_work(env, context->work);
704 if (status != napi_ok) {
705 IMAGE_ERR("fail to queue async work %{public}d", status);
706 return result;
707 }
708 context.release();
709
710 IMAGE_FUNCTION_OUT();
711 return result;
712 }
713
CheckOnParam0(napi_env env,napi_value value,const std::string & refStr)714 static bool CheckOnParam0(napi_env env, napi_value value, const std::string& refStr)
715 {
716 bool ret = true;
717 size_t bufLength = 0;
718 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength);
719 if (status != napi_ok || bufLength > PATH_MAX) {
720 return false;
721 }
722
723 char *buffer = static_cast<char *>(malloc((bufLength + 1) * sizeof(char)));
724 if (buffer == nullptr) {
725 return false;
726 }
727
728 status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength);
729 if (status != napi_ok) {
730 free(buffer);
731 return false;
732 }
733
734 std::string strValue = buffer;
735 if (strValue.compare(refStr) != 0) {
736 IMAGE_ERR("strValue is %{public}s", strValue.c_str());
737 ret = false;
738 }
739
740 strValue = "";
741 free(buffer);
742 buffer = nullptr;
743 return ret;
744 }
745
JsOnQueryArgs(ImageCreatorCommonArgs & args,ImageCreatorInnerContext & ic)746 static bool JsOnQueryArgs(ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic)
747 {
748 if (ic.argc == ARGS2) {
749 auto argType0 = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
750 auto argType1 = ImageNapiUtils::getType(args.env, ic.argv[PARAM1]);
751 if (argType0 == napi_string && argType1 == napi_function) {
752 if (!ImageNapiUtils::GetUtf8String(args.env, ic.argv[PARAM0], ic.onType)) {
753 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
754 "Could not get On type string");
755 return false;
756 }
757
758 if (!CheckOnParam0(args.env, ic.argv[PARAM0], "imageRelease")) {
759 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
760 "Unsupport PARAM0");
761 return false;
762 }
763
764 napi_create_reference(args.env, ic.argv[PARAM1], ic.refCount, &(ic.context->callbackRef));
765 } else {
766 std::string errMsg = "Unsupport args type: ";
767 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
768 errMsg.append(std::to_string(argType0)).append(std::to_string(argType1)));
769 return false;
770 }
771 } else {
772 std::string errMsg = "Invailed argc: ";
773 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
774 errMsg.append(std::to_string(ic.argc)));
775 return false;
776 }
777
778 napi_get_undefined(args.env, &ic.result);
779 return true;
780 }
DoCallBackAfterWork(uv_work_t * work,int status)781 static void DoCallBackAfterWork(uv_work_t *work, int status)
782 {
783 IMAGE_LINE_IN();
784 Contextc context = reinterpret_cast<Contextc>(work->data);
785 if (context == nullptr) {
786 IMAGE_ERR("context is empty");
787 } else {
788 if (context->env != nullptr && context->callbackRef != nullptr) {
789 napi_handle_scope scope = nullptr;
790 napi_open_handle_scope(context->env, &scope);
791 if (scope == nullptr) {
792 delete work;
793 return;
794 }
795 napi_value result[PARAM2] = {0};
796 napi_value retVal = nullptr;
797 napi_value callback = nullptr;
798 napi_create_uint32(context->env, SUCCESS, &result[0]);
799 napi_get_undefined(context->env, &result[1]);
800 napi_get_reference_value(context->env, context->callbackRef, &callback);
801 if (callback != nullptr) {
802 napi_call_function(context->env, nullptr, callback, PARAM2, result, &retVal);
803 } else {
804 IMAGE_ERR("napi_get_reference_value callback is empty");
805 }
806 napi_close_handle_scope(context->env, scope);
807 } else {
808 IMAGE_ERR("env or callbackRef is empty");
809 }
810 }
811 delete work;
812 IMAGE_LINE_OUT();
813 }
DoCallBack(shared_ptr<ImageCreatorAsyncContext> context,string name,CompleteCreatorCallback callBack)814 void ImageCreatorNapi::DoCallBack(shared_ptr<ImageCreatorAsyncContext> context,
815 string name, CompleteCreatorCallback callBack)
816 {
817 IMAGE_FUNCTION_IN();
818 if (context == nullptr || context->env == nullptr) {
819 IMAGE_ERR("gContext or env is empty");
820 return;
821 }
822
823 uv_loop_s *loop = nullptr;
824 napi_get_uv_event_loop(context->env, &loop);
825 if (loop == nullptr) {
826 IMAGE_ERR("napi_get_uv_event_loop failed");
827 return;
828 }
829
830 unique_ptr<uv_work_t> work = make_unique<uv_work_t>();
831 if (work == nullptr) {
832 IMAGE_ERR("DoCallBack: No memory");
833 return;
834 }
835
836 work->data = reinterpret_cast<void *>(context.get());
837 int ret = uv_queue_work(loop, work.get(), [] (uv_work_t *work) {}, DoCallBackAfterWork);
838 if (ret != 0) {
839 IMAGE_ERR("Failed to execute DoCallBack work queue");
840 } else {
841 work.release();
842 }
843 IMAGE_FUNCTION_OUT();
844 }
845
JsOn(napi_env env,napi_callback_info info)846 napi_value ImageCreatorNapi::JsOn(napi_env env, napi_callback_info info)
847 {
848 IMAGE_FUNCTION_IN();
849 ImageCreatorCommonArgs args = {
850 .env = env, .info = info,
851 .async = CreatorCallType::ASYNC,
852 .name = "JsOn",
853 };
854 args.argc = ARGS2;
855 args.asyncLater = true;
856 args.queryArgs = JsOnQueryArgs;
857 args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
858 IMAGE_LINE_IN();
859 if (g_isCreatorTest) {
860 g_listener = make_shared<ImageCreatorReleaseListener>();
861 g_listener->context = std::move(ic.context);
862 g_listener->context->env = args.env;
863 g_listener->name = args.name;
864 return true;
865 }
866 napi_get_undefined(args.env, &(ic.result));
867
868 auto native = ic.context->constructor_->imageCreator_;
869 if (native == nullptr) {
870 IMAGE_ERR("Native instance is nullptr");
871 ic.context->status = ERR_IMAGE_INIT_ABNORMAL;
872 return false;
873 }
874 shared_ptr<ImageCreatorReleaseListener> listener = make_shared<ImageCreatorReleaseListener>();
875 listener->context = std::move(ic.context);
876 listener->context->env = args.env;
877 listener->name = args.name;
878
879 native->RegisterBufferReleaseListener((std::shared_ptr<SurfaceBufferReleaseListener> &)listener);
880
881 IMAGE_LINE_OUT();
882 return true;
883 };
884
885 return JSCommonProcess(args);
886 }
887
JsOffOneArg(napi_env env,napi_callback_info info)888 napi_value ImageCreatorNapi::JsOffOneArg(napi_env env, napi_callback_info info)
889 {
890 ImageCreatorCommonArgs args = {
891 .env = env, .info = info, .async = CreatorCallType::ASYNC,
892 .name = "JsOff", .argc = ARGS1, .asyncLater = true,
893 };
894
895 args.queryArgs = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
896 if (ic.argc != ARGS1) {
897 std::string errMsg = "Invalid argc: ";
898 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
899 errMsg.append(std::to_string(ic.argc)));
900 return false;
901 }
902 auto argType = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
903 if (argType != napi_string) {
904 std::string errMsg = "Unsupport args type: ";
905 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
906 errMsg.append(std::to_string(argType)));
907 return false;
908 }
909 if (!ImageNapiUtils::GetUtf8String(args.env, ic.argv[PARAM0], ic.onType)) {
910 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
911 "Could not get On type string");
912 return false;
913 }
914 if (!CheckOnParam0(args.env, ic.argv[PARAM0], "imageRelease")) {
915 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
916 "Unsupport PARAM0");
917 return false;
918 }
919 napi_get_undefined(args.env, &ic.result);
920 return true;
921 };
922
923 args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
924 IMAGE_LINE_IN();
925 napi_get_undefined(args.env, &ic.result);
926
927 if (g_isCreatorTest && g_listener != nullptr) {
928 g_listener.reset();
929 } else {
930 if (ic.context != nullptr && ic.context->constructor_ != nullptr
931 && ic.context->constructor_->imageCreator_ != nullptr) {
932 ic.context->constructor_->imageCreator_->UnRegisterBufferReleaseListener();
933 }
934 }
935 ic.context->status = SUCCESS;
936 napi_create_uint32(args.env, ic.context->status, &ic.result);
937 IMAGE_LINE_OUT();
938 return true;
939 };
940
941 return JSCommonProcess(args);
942 }
943
JsOffTwoArgs(napi_env env,napi_callback_info info)944 napi_value ImageCreatorNapi::JsOffTwoArgs(napi_env env, napi_callback_info info)
945 {
946 napi_value result = nullptr;
947 napi_get_undefined(env, &result);
948
949 ImageCreatorCommonArgs args = {
950 .env = env, .info = info, .async = CreatorCallType::ASYNC,
951 .name = "JsOff", .argc = ARGS2, .queryArgs = JsOnQueryArgs,
952 };
953
954 args.callBack = [](napi_env env, napi_status status, Contextc context) {
955 IMAGE_LINE_IN();
956 napi_value result = nullptr;
957 napi_get_undefined(env, &result);
958 context->constructor_->imageCreator_->UnRegisterBufferReleaseListener();
959 context->status = SUCCESS;
960 CommonCallbackRoutine(env, context, result);
961 IMAGE_LINE_OUT();
962 };
963
964 JSCommonProcess(args);
965 napi_create_uint32(args.env, SUCCESS, &result);
966 return result;
967 }
968
JsOff(napi_env env,napi_callback_info info)969 napi_value ImageCreatorNapi::JsOff(napi_env env, napi_callback_info info)
970 {
971 IMAGE_FUNCTION_IN();
972 struct ImageCreatorInnerContext ic;
973 ic.argc = ARGS2;
974 ic.argv.resize(ic.argc);
975 napi_get_undefined(env, &ic.result);
976 IMG_JS_ARGS(env, info, ic.status, ic.argc, &(ic.argv[0]), ic.thisVar);
977 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(ic.status), ic.result, IMAGE_ERR("fail to napi_get_cb_info"));
978
979 if (ic.argc == ARGS1) {
980 return JsOffOneArg(env, info);
981 } else if (ic.argc == ARGS2) {
982 return JsOffTwoArgs(env, info);
983 } else {
984 IMAGE_ERR("invalid argument count");
985 return ic.result;
986 }
987 }
988
JsRelease(napi_env env,napi_callback_info info)989 napi_value ImageCreatorNapi::JsRelease(napi_env env, napi_callback_info info)
990 {
991 IMAGE_FUNCTION_IN();
992 ImageCreatorCommonArgs args = {
993 .env = env, .info = info,
994 .async = CreatorCallType::ASYNC,
995 .name = "JsRelease",
996 .callBack = nullptr,
997 .argc = ARGS1,
998 .queryArgs = PrepareOneArg,
999 };
1000
1001 args.callBack = [](napi_env env, napi_status status, Contextc context) {
1002 IMAGE_LINE_IN();
1003 napi_value result = nullptr;
1004 napi_get_undefined(env, &result);
1005
1006 context->constructor_->NativeRelease();
1007 context->status = SUCCESS;
1008
1009 IMAGE_LINE_OUT();
1010 CommonCallbackRoutine(env, context, result);
1011 };
1012
1013 return JSCommonProcess(args);
1014 }
1015
release()1016 void ImageCreatorNapi::release()
1017 {
1018 if (!isRelease) {
1019 NativeRelease();
1020 isRelease = true;
1021 }
1022 }
1023 } // namespace Media
1024 } // namespace OHOS
1025