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_napi.h"
17 #include "media_errors.h"
18 #include "hilog/log.h"
19 #include "image_format.h"
20 #include "image_napi_utils.h"
21
22 using OHOS::HiviewDFX::HiLog;
23 using std::string;
24 using std::shared_ptr;
25 using std::unique_ptr;
26 using std::vector;
27 using std::make_shared;
28 using std::make_unique;
29
30 namespace {
31 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "ImageNapi"};
32 }
33
34 namespace OHOS {
35 namespace Media {
36 static const std::string CLASS_NAME = "ImageNapi";
37 static const std::string SURFACE_DATA_SIZE_TAG = "dataSize";
38 std::shared_ptr<ImageReceiver> ImageNapi::staticImageReceiverInstance_ = nullptr;
39 std::shared_ptr<ImageCreator> ImageNapi::staticImageCreatorInstance_ = nullptr;
40 sptr<SurfaceBuffer> ImageNapi::staticInstance_ = nullptr;
41 thread_local napi_ref ImageNapi::sConstructor_ = nullptr;
42 static bool receiverTest = false;
43
44 const int ARGS0 = 0;
45 const int ARGS1 = 1;
46 const int ARGS2 = 2;
47 const int PARAM0 = 0;
48 const int PARAM1 = 1;
49 const int PARAM2 = 2;
50 const int NUM0 = 0;
51 const int NUM1 = 1;
52 const int NUM2 = 2;
53
ImageNapi()54 ImageNapi::ImageNapi():env_(nullptr)
55 {}
56
~ImageNapi()57 ImageNapi::~ImageNapi()
58 {
59 release();
60 }
61 struct YUV422SPData {
62 std::vector<uint8_t> y;
63 std::vector<uint8_t> u;
64 std::vector<uint8_t> v;
65 uint64_t ySize;
66 uint64_t uvSize;
67 };
68
69
YUV422SPDataCopy(uint8_t * surfaceBuffer,uint64_t bufferSize,YUV422SPData & data,bool flip)70 static void YUV422SPDataCopy(uint8_t* surfaceBuffer, uint64_t bufferSize,
71 YUV422SPData &data, bool flip)
72 {
73 uint64_t ui = NUM0, vi = NUM0;
74 for (uint64_t i = NUM0; i < bufferSize; i++) {
75 if (i < data.ySize) {
76 if (flip) {
77 surfaceBuffer[i] = data.y[i];
78 } else {
79 data.y[i] = surfaceBuffer[i];
80 }
81 continue;
82 }
83 if (vi >= data.uvSize || ui >= data.uvSize) {
84 // Over write buffer size.
85 continue;
86 }
87 if (i % NUM2 == NUM1) {
88 if (flip) {
89 surfaceBuffer[i] = data.v[vi++];
90 } else {
91 data.v[vi++] = surfaceBuffer[i];
92 }
93 } else {
94 if (flip) {
95 surfaceBuffer[i] = data.u[ui++];
96 } else {
97 data.u[ui++] = surfaceBuffer[i];
98 }
99 }
100 }
101 }
102
GetSurfaceDataSize(sptr<SurfaceBuffer> surface)103 static uint64_t GetSurfaceDataSize(sptr<SurfaceBuffer> surface)
104 {
105 if (surface == nullptr) {
106 HiLog::Error(LABEL, "Nullptr surface");
107 return NUM0;
108 }
109
110 uint64_t bufferSize = surface->GetSize();
111 auto surfaceExtraData = surface->GetExtraData();
112 if (surfaceExtraData == nullptr) {
113 HiLog::Error(LABEL, "Nullptr surface extra data. return buffer size %{public}" PRIu64, bufferSize);
114 return bufferSize;
115 }
116
117 int32_t extraDataSize = NUM0;
118 auto res = surfaceExtraData->ExtraGet(SURFACE_DATA_SIZE_TAG, extraDataSize);
119 if (res != NUM0) {
120 HiLog::Error(LABEL, "Surface ExtraGet dataSize error %{public}d", res);
121 return bufferSize;
122 } else if (extraDataSize <= NUM0) {
123 HiLog::Error(LABEL, "Surface ExtraGet dataSize Ok, but size <= 0");
124 return bufferSize;
125 } else if (static_cast<uint64_t>(extraDataSize) > bufferSize) {
126 HiLog::Error(LABEL,
127 "Surface ExtraGet dataSize Ok,but dataSize %{public}d is bigger than bufferSize %{public}" PRIu64,
128 extraDataSize, bufferSize);
129 return bufferSize;
130 }
131 HiLog::Info(LABEL, "Surface ExtraGet dataSize %{public}d", extraDataSize);
132 return extraDataSize;
133 }
134
ProcessYUV422SP(ImageNapi * imageNapi,sptr<SurfaceBuffer> surface)135 static uint32_t ProcessYUV422SP(ImageNapi* imageNapi, sptr<SurfaceBuffer> surface)
136 {
137 IMAGE_FUNCTION_IN();
138 uint8_t* surfaceBuffer = static_cast<uint8_t*>(surface->GetVirAddr());
139 if (surfaceBuffer == nullptr) {
140 HiLog::Error(LABEL, "Nullptr surface buffer");
141 return ERR_IMAGE_DATA_ABNORMAL;
142 }
143 uint64_t surfaceSize = GetSurfaceDataSize(surface);
144 if (surfaceSize == NUM0) {
145 HiLog::Error(LABEL, "Surface size is 0");
146 return ERR_IMAGE_DATA_ABNORMAL;
147 }
148 if (surface->GetHeight() <= NUM0 || surface->GetWidth() <= NUM0) {
149 HiLog::Error(LABEL, "Invaild width %{public}" PRId32 " height %{public}" PRId32,
150 surface->GetWidth(), surface->GetHeight());
151 return ERR_IMAGE_DATA_ABNORMAL;
152 }
153 uint64_t ySize = static_cast<uint64_t>(surface->GetHeight() * surface->GetWidth());
154 uint64_t uvStride = static_cast<uint64_t>((surface->GetWidth() + NUM1) / NUM2);
155 uint64_t uvSize = static_cast<uint64_t>(surface->GetHeight() * uvStride);
156 if (surfaceSize < (ySize + uvSize * NUM2)) {
157 HiLog::Error(LABEL, "Surface size %{public}" PRIu64 " < y plane %{public}" PRIu64
158 " + uv plane %{public}" PRIu64, surfaceSize, ySize, uvSize * NUM2);
159 return ERR_IMAGE_DATA_ABNORMAL;
160 }
161
162 Component* y = imageNapi->CreateComponentData(ComponentType::YUV_Y, ySize, surface->GetWidth(), NUM1);
163 Component* u = imageNapi->CreateComponentData(ComponentType::YUV_U, uvSize, uvStride, NUM2);
164 Component* v = imageNapi->CreateComponentData(ComponentType::YUV_V, uvSize, uvStride, NUM2);
165 if ((y == nullptr) || (u == nullptr) || (v == nullptr)) {
166 HiLog::Error(LABEL, "Create Component failed");
167 return ERR_IMAGE_DATA_ABNORMAL;
168 }
169 struct YUV422SPData data;
170 data.ySize = ySize;
171 data.uvSize = uvSize;
172 data.y = y->raw;
173 data.u = u->raw;
174 data.v = v->raw;
175 YUV422SPDataCopy(surfaceBuffer, surfaceSize, data, false);
176 return SUCCESS;
177 }
SplitSurfaceToComponent(ImageNapi * imageNapi,sptr<SurfaceBuffer> surface)178 static uint32_t SplitSurfaceToComponent(ImageNapi* imageNapi, sptr<SurfaceBuffer> surface)
179 {
180 auto surfaceFormat = surface->GetFormat();
181 switch (surfaceFormat) {
182 case int32_t(ImageFormat::YCBCR_422_SP):
183 case int32_t(PIXEL_FMT_YCBCR_422_SP):
184 return ProcessYUV422SP(imageNapi, surface);
185 default:
186 break;
187 }
188 // Unsupport split component
189 return ERR_IMAGE_DATA_UNSUPPORT;
190 }
191
CommonCallbackRoutine(napi_env env,ImageAsyncContext * & context,const napi_value & valueParam)192 static void CommonCallbackRoutine(napi_env env, ImageAsyncContext* &context,
193 const napi_value &valueParam)
194 {
195 IMAGE_FUNCTION_IN();
196 napi_value result[2] = {0};
197 napi_value retVal;
198 napi_value callback = nullptr;
199
200 napi_get_undefined(env, &result[0]);
201 napi_get_undefined(env, &result[1]);
202
203 if (context == nullptr) {
204 IMAGE_ERR("context is nullptr");
205 return;
206 }
207
208 if (context->status == SUCCESS) {
209 result[1] = valueParam;
210 }
211
212 if (context->deferred) {
213 if (context->status == SUCCESS) {
214 napi_resolve_deferred(env, context->deferred, result[1]);
215 } else {
216 ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
217 "There is generic napi failure!");
218 napi_reject_deferred(env, context->deferred, result[0]);
219 }
220 } else {
221 if (context->status == SUCCESS) {
222 napi_create_uint32(env, context->status, &result[0]);
223 } else {
224 ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
225 "There is generic napi failure!");
226 }
227 napi_get_reference_value(env, context->callbackRef, &callback);
228 napi_call_function(env, nullptr, callback, PARAM2, result, &retVal);
229 napi_delete_reference(env, context->callbackRef);
230 }
231
232 napi_delete_async_work(env, context->work);
233
234 delete context;
235 context = nullptr;
236 IMAGE_FUNCTION_OUT();
237 }
238
NativeRelease()239 void ImageNapi::NativeRelease()
240 {
241 if (imageReceiver_ != nullptr) {
242 imageReceiver_->ReleaseBuffer(sSurfaceBuffer_);
243 imageReceiver_ = nullptr;
244 }
245 sSurfaceBuffer_ = nullptr;
246 if (componentData_.size() > 0) {
247 for (auto iter = componentData_.begin(); iter != componentData_.end(); iter++) {
248 iter->second = nullptr;
249 componentData_.erase(iter);
250 }
251 }
252 }
253
Init(napi_env env,napi_value exports)254 napi_value ImageNapi::Init(napi_env env, napi_value exports)
255 {
256 IMAGE_FUNCTION_IN();
257 napi_property_descriptor props[] = {
258 DECLARE_NAPI_GETTER("clipRect", JSGetClipRect),
259 DECLARE_NAPI_GETTER("size", JsGetSize),
260 DECLARE_NAPI_GETTER("format", JsGetFormat),
261 DECLARE_NAPI_FUNCTION("getComponent", JsGetComponent),
262 DECLARE_NAPI_FUNCTION("release", JsRelease),
263 };
264 napi_value constructor = nullptr;
265
266 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
267 napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor,
268 nullptr, IMG_ARRAY_SIZE(props), props, &constructor)),
269 nullptr,
270 IMAGE_ERR("define class fail")
271 );
272
273 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
274 napi_create_reference(env, constructor, 1, &sConstructor_)),
275 nullptr,
276 IMAGE_ERR("create reference fail")
277 );
278
279 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
280 napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
281 nullptr,
282 IMAGE_ERR("set named property fail")
283 );
284
285 IMAGE_DEBUG("Init success");
286
287 IMAGE_FUNCTION_OUT();
288 return exports;
289 }
290
GetImageSource(napi_env env,napi_value image)291 std::shared_ptr<ImageNapi> ImageNapi::GetImageSource(napi_env env, napi_value image)
292 {
293 std::unique_ptr<ImageNapi> imageNapi = std::make_unique<ImageNapi>();
294
295 napi_status status = napi_unwrap(env, image, reinterpret_cast<void**>(&imageNapi));
296 if (!IMG_IS_OK(status)) {
297 IMAGE_ERR("GetImage napi unwrap failed");
298 return nullptr;
299 }
300
301 if (imageNapi == nullptr) {
302 IMAGE_ERR("GetImage imageNapi is nullptr");
303 return nullptr;
304 }
305 IMAGE_ERR("get nativeImage");
306
307 return imageNapi;
308 }
309
Constructor(napi_env env,napi_callback_info info)310 napi_value ImageNapi::Constructor(napi_env env, napi_callback_info info)
311 {
312 napi_value undefineVar = nullptr;
313 napi_get_undefined(env, &undefineVar);
314
315 napi_status status;
316 napi_value thisVar = nullptr;
317
318 IMAGE_FUNCTION_IN();
319 status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
320 if (status == napi_ok && thisVar != nullptr) {
321 std::unique_ptr<ImageNapi> reference = std::make_unique<ImageNapi>();
322 if (reference != nullptr) {
323 reference->env_ = env;
324 reference->sSurfaceBuffer_ = staticInstance_;
325 reference->imageReceiver_ = staticImageReceiverInstance_;
326 staticImageReceiverInstance_ = nullptr;
327 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(reference.get()),
328 ImageNapi::Destructor, nullptr, nullptr);
329 if (status == napi_ok) {
330 IMAGE_FUNCTION_OUT();
331 reference.release();
332 return thisVar;
333 } else {
334 IMAGE_ERR("Failure wrapping js to native napi");
335 }
336 }
337 }
338
339 return undefineVar;
340 }
341
Destructor(napi_env env,void * nativeObject,void * finalize)342 void ImageNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
343 {
344 }
345
Create(napi_env env,sptr<SurfaceBuffer> surfaceBuffer,std::shared_ptr<ImageReceiver> imageReceiver)346 napi_value ImageNapi::Create(napi_env env, sptr<SurfaceBuffer> surfaceBuffer,
347 std::shared_ptr<ImageReceiver> imageReceiver)
348 {
349 napi_status status;
350 napi_value constructor = nullptr, result = nullptr;
351
352 IMAGE_FUNCTION_IN();
353 if (surfaceBuffer == nullptr) {
354 IMAGE_ERR("surfaceBuffer is nullptr");
355 return result;
356 }
357
358 napi_get_undefined(env, &result);
359
360 status = napi_get_reference_value(env, sConstructor_, &constructor);
361 if (IMG_IS_OK(status)) {
362 staticInstance_ = surfaceBuffer;
363 staticImageReceiverInstance_ = imageReceiver;
364 status = napi_new_instance(env, constructor, 0, nullptr, &result);
365 if (status == napi_ok) {
366 IMAGE_FUNCTION_OUT();
367 return result;
368 } else {
369 IMAGE_ERR("New instance could not be obtained");
370 }
371 }
372
373 IMAGE_ERR("Failed to get reference of constructor");
374 return result;
375 }
376
Create(napi_env env,std::shared_ptr<ImageReceiver> imageReceiver)377 napi_value ImageNapi::Create(napi_env env, std::shared_ptr<ImageReceiver> imageReceiver)
378 {
379 receiverTest = true;
380 napi_status status;
381 napi_value constructor = nullptr, result = nullptr;
382
383 IMAGE_FUNCTION_IN();
384
385 napi_get_undefined(env, &result);
386 status = napi_get_reference_value(env, sConstructor_, &constructor);
387 if (IMG_IS_OK(status)) {
388 staticInstance_ = nullptr;
389 staticImageReceiverInstance_ = imageReceiver;
390 status = napi_new_instance(env, constructor, 0, nullptr, &result);
391 if (status == napi_ok) {
392 IMAGE_FUNCTION_OUT();
393 return result;
394 } else {
395 IMAGE_ERR("New instance could not be obtained");
396 }
397 }
398
399 IMAGE_ERR("Failed to get reference of constructor");
400 return result;
401 }
402
CreateBufferToImage(napi_env env,sptr<SurfaceBuffer> surfaceBuffer,std::shared_ptr<ImageCreator> imageCreator)403 napi_value ImageNapi::CreateBufferToImage(napi_env env, sptr<SurfaceBuffer> surfaceBuffer,
404 std::shared_ptr<ImageCreator> imageCreator)
405 {
406 napi_status status;
407 napi_value constructor = nullptr, result = nullptr;
408
409 IMAGE_FUNCTION_IN();
410 if (surfaceBuffer == nullptr) {
411 IMAGE_ERR("surfaceBuffer is nullptr");
412 return result;
413 }
414
415 napi_get_undefined(env, &result);
416
417 status = napi_get_reference_value(env, sConstructor_, &constructor);
418 if (IMG_IS_OK(status)) {
419 staticInstance_ = surfaceBuffer;
420 staticImageCreatorInstance_ = imageCreator;
421 status = napi_new_instance(env, constructor, 0, nullptr, &result);
422 if (status == napi_ok) {
423 IMAGE_FUNCTION_OUT();
424 return result;
425 } else {
426 IMAGE_ERR("New instance could not be obtained");
427 }
428 }
429
430 IMAGE_ERR("Failed to get reference of constructor");
431 return result;
432 }
433
UnwarpContext(napi_env env,napi_callback_info info)434 unique_ptr<ImageAsyncContext> ImageNapi::UnwarpContext(napi_env env, napi_callback_info info)
435 {
436 napi_status status;
437 napi_value thisVar = nullptr;
438 size_t argc = ARGS0;
439
440 IMAGE_FUNCTION_IN();
441
442 status = napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr);
443 if (status != napi_ok) {
444 IMAGE_ERR("fail to napi_get_cb_info %{public}d", status);
445 return nullptr;
446 }
447
448 unique_ptr<ImageAsyncContext> context = make_unique<ImageAsyncContext>();
449 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
450 if (status != napi_ok || context->constructor_ == nullptr) {
451 IMAGE_ERR("fail to unwrap constructor_ %{public}d", status);
452 return nullptr;
453 }
454 return context;
455 }
456
BuildIntProperty(napi_env env,const std::string & name,int32_t val,napi_value result)457 static void BuildIntProperty(napi_env env, const std::string &name,
458 int32_t val, napi_value result)
459 {
460 napi_value nVal;
461 napi_create_int32(env, val, &nVal);
462 napi_set_named_property(env, result, name.c_str(), nVal);
463 }
464
BuildJsSize(napi_env env,int32_t width,int32_t height)465 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
466 {
467 napi_value result = nullptr;
468
469 napi_create_object(env, &result);
470
471 BuildIntProperty(env, "width", width, result);
472 BuildIntProperty(env, "height", height, result);
473 return result;
474 }
475
BuildJsRegion(napi_env env,int32_t width,int32_t height,int32_t x,int32_t y)476 static napi_value BuildJsRegion(napi_env env, int32_t width,
477 int32_t height, int32_t x, int32_t y)
478 {
479 napi_value result = nullptr;
480
481 napi_create_object(env, &result);
482
483 napi_set_named_property(env, result, "size", BuildJsSize(env, width, height));
484
485 BuildIntProperty(env, "x", x, result);
486 BuildIntProperty(env, "y", y, result);
487 return result;
488 }
489
JSGetClipRect(napi_env env,napi_callback_info info)490 napi_value ImageNapi::JSGetClipRect(napi_env env, napi_callback_info info)
491 {
492 napi_value result = nullptr;
493 unique_ptr<ImageAsyncContext> context;
494
495 IMAGE_FUNCTION_IN();
496 napi_get_undefined(env, &result);
497 context = UnwarpContext(env, info);
498 if (context == nullptr) {
499 return result;
500 }
501
502 if (context->constructor_ == nullptr) {
503 IMAGE_ERR("Image context is nullptr");
504 return result;
505 }
506 auto surfaceBuffer = context->constructor_->sSurfaceBuffer_;
507
508 if (surfaceBuffer == nullptr && receiverTest == false) {
509 IMAGE_ERR("Image surface buffer is nullptr");
510 return result;
511 }
512
513 if (surfaceBuffer != nullptr && receiverTest == false) {
514 return BuildJsRegion(env, surfaceBuffer->GetWidth(), surfaceBuffer->GetHeight(), NUM0, NUM0);
515 } else {
516 const int32_t WIDTH = 8192;
517 const int32_t HEIGHT = 8;
518 return BuildJsRegion(env, WIDTH, HEIGHT, NUM0, NUM0);
519 }
520 }
521
JsGetSize(napi_env env,napi_callback_info info)522 napi_value ImageNapi::JsGetSize(napi_env env, napi_callback_info info)
523 {
524 napi_value result = nullptr;
525 unique_ptr<ImageAsyncContext> context;
526
527 IMAGE_FUNCTION_IN();
528 napi_get_undefined(env, &result);
529 context = UnwarpContext(env, info);
530 if (context == nullptr) {
531 return result;
532 }
533
534 if (context->constructor_ == nullptr) {
535 IMAGE_ERR("Image context is nullptr");
536 return result;
537 }
538 auto surfaceBuffer = context->constructor_->sSurfaceBuffer_;
539
540 if (surfaceBuffer == nullptr && receiverTest == false) {
541 IMAGE_ERR("Image surface buffer is nullptr");
542 return result;
543 }
544
545 if (surfaceBuffer == nullptr && receiverTest == true) {
546 const int32_t WIDTH = 8192;
547 const int32_t HEIGHT = 8;
548 return BuildJsSize(env, WIDTH, HEIGHT);
549 } else {
550 return BuildJsSize(env, surfaceBuffer->GetWidth(), surfaceBuffer->GetHeight());
551 }
552 }
553
JsGetFormat(napi_env env,napi_callback_info info)554 napi_value ImageNapi::JsGetFormat(napi_env env, napi_callback_info info)
555 {
556 napi_value result = nullptr;
557 unique_ptr<ImageAsyncContext> context;
558
559 IMAGE_FUNCTION_IN();
560 napi_get_undefined(env, &result);
561 context = UnwarpContext(env, info);
562 if (context == nullptr) {
563 return result;
564 }
565
566 if (context->constructor_ == nullptr) {
567 IMAGE_ERR("Image context is nullptr");
568 return result;
569 }
570
571 auto surfaceBuffer = context->constructor_->sSurfaceBuffer_;
572 if (surfaceBuffer == nullptr && receiverTest == false) {
573 IMAGE_ERR("Image surface buffer is nullptr");
574 return result;
575 }
576
577 if (surfaceBuffer == nullptr && receiverTest == true) {
578 const int32_t FORMAT = 12;
579 napi_create_int32(env, FORMAT, &result);
580 } else {
581 napi_create_int32(env, surfaceBuffer->GetFormat(), &result);
582 }
583 return result;
584 }
585
JSReleaseCallBack(napi_env env,napi_status status,ImageAsyncContext * context)586 static void JSReleaseCallBack(napi_env env, napi_status status,
587 ImageAsyncContext* context)
588 {
589 IMAGE_FUNCTION_IN();
590 napi_value result = nullptr;
591 napi_get_undefined(env, &result);
592
593 if (context == nullptr) {
594 IMAGE_ERR("context is nullptr");
595 return;
596 }
597 context->constructor_->NativeRelease();
598 context->status = SUCCESS;
599
600 IMAGE_FUNCTION_OUT();
601 CommonCallbackRoutine(env, context, result);
602 }
603
JsRelease(napi_env env,napi_callback_info info)604 napi_value ImageNapi::JsRelease(napi_env env, napi_callback_info info)
605 {
606 IMAGE_FUNCTION_IN();
607 napi_status status;
608 napi_value result = nullptr, thisVar = nullptr;
609 size_t argc = ARGS1;
610 napi_value argv[ARGS1] = {0};
611
612 napi_get_undefined(env, &result);
613
614 status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
615 if (status != napi_ok) {
616 IMAGE_ERR("fail to napi_get_cb_info %{public}d", status);
617 return result;
618 }
619
620 unique_ptr<ImageAsyncContext> context = UnwarpContext(env, info);
621 if (context == nullptr) {
622 IMAGE_ERR("fail to unwrap constructor_ %{public}d", status);
623 return result;
624 }
625
626 if (argc == ARGS1) {
627 auto argType = ImageNapiUtils::getType(env, argv[PARAM0]);
628 if (argType == napi_function) {
629 int32_t refCount = 1;
630 napi_create_reference(env, argv[PARAM0], refCount, &context->callbackRef);
631 } else {
632 IMAGE_ERR("Unsupport arg 0 type: %{public}d", argType);
633 return result;
634 }
635 }
636
637 if (context->callbackRef == nullptr) {
638 napi_create_promise(env, &(context->deferred), &result);
639 } else {
640 napi_get_undefined(env, &result);
641 }
642
643 napi_value resource = nullptr;
644 napi_create_string_utf8(env, "JsRelease", NAPI_AUTO_LENGTH, &resource);
645 status = napi_create_async_work(
646 env, nullptr, resource, [](napi_env env, void* data) {},
647 reinterpret_cast<napi_async_complete_callback>(JSReleaseCallBack),
648 static_cast<void *>(context.get()), &(context->work));
649 if (status != napi_ok) {
650 IMAGE_ERR("fail to create async work %{public}d", status);
651 return result;
652 }
653
654 status = napi_queue_async_work(env, context->work);
655 if (status != napi_ok) {
656 IMAGE_ERR("fail to queue async work %{public}d", status);
657 return result;
658 }
659
660 context.release();
661
662 IMAGE_FUNCTION_OUT();
663 return result;
664 }
665
CreateArrayBuffer(napi_env env,uint8_t * src,size_t srcLen,napi_value * res)666 static bool CreateArrayBuffer(napi_env env, uint8_t* src, size_t srcLen, napi_value *res)
667 {
668 if (src == nullptr || srcLen == 0) {
669 return false;
670 }
671 auto status = napi_create_external_arraybuffer(env, src, srcLen,
672 [](napi_env env, void* data, void* hint) { }, nullptr, res);
673 if (status != napi_ok) {
674 return false;
675 }
676 return true;
677 }
678
IsYUVType(const int32_t & type)679 static bool IsYUVType(const int32_t& type)
680 {
681 if (type == static_cast<int32_t>(ComponentType::YUV_Y) ||
682 type == static_cast<int32_t>(ComponentType::YUV_U) ||
683 type == static_cast<int32_t>(ComponentType::YUV_V)) {
684 return true;
685 }
686 return false;
687 }
IsYCbCr422SP(int32_t format)688 static inline bool IsYCbCr422SP(int32_t format)
689 {
690 if (int32_t(ImageFormat::YCBCR_422_SP) == format) {
691 return true;
692 }
693 if (int32_t(PIXEL_FMT_YCBCR_422_SP) == format) {
694 return true;
695 }
696 return false;
697 }
TestGetComponentCallBack(napi_env env,napi_status status,ImageAsyncContext * context)698 static void TestGetComponentCallBack(napi_env env, napi_status status, ImageAsyncContext* context)
699 {
700 if (context == nullptr) {
701 HiLog::Error(LABEL, "Invalid input context");
702 return;
703 }
704 napi_value result;
705 napi_value array;
706 void *nativePtr = nullptr;
707 if (napi_create_arraybuffer(env, NUM1, &nativePtr, &array) != napi_ok || nativePtr == nullptr) {
708 return;
709 }
710 napi_create_object(env, &result);
711 napi_set_named_property(env, result, "byteBuffer", array);
712 BuildIntProperty(env, "componentType", context->componentType, result);
713 BuildIntProperty(env, "rowStride", NUM0, result);
714 BuildIntProperty(env, "pixelStride", NUM0, result);
715 context->status = SUCCESS;
716 CommonCallbackRoutine(env, context, result);
717 }
JsGetComponentCallBack(napi_env env,napi_status status,ImageAsyncContext * context)718 void ImageNapi::JsGetComponentCallBack(napi_env env, napi_status status,
719 ImageAsyncContext* context)
720 {
721 IMAGE_FUNCTION_IN();
722 napi_value result;
723 napi_get_undefined(env, &result);
724
725 if (receiverTest) {
726 TestGetComponentCallBack(env, status, context);
727 return;
728 }
729
730 if (context == nullptr || context->constructor_ == nullptr ||
731 context->constructor_->sSurfaceBuffer_ == nullptr) {
732 HiLog::Error(LABEL, "Invalid input context");
733 CommonCallbackRoutine(env, context, result);
734 return;
735 }
736
737 auto surfaceBuffer = context->constructor_->sSurfaceBuffer_;
738 uint32_t bufferSize = 0;
739 uint8_t *buffer = nullptr;
740 uint32_t rowStride = 0;
741 uint32_t pixelStride = 0;
742 if (IsYCbCr422SP(surfaceBuffer->GetFormat()) && IsYUVType(context->componentType)) {
743 Component* component = context->constructor_->GetComponentData(
744 ComponentType(context->componentType));
745 if (component != nullptr) {
746 bufferSize = component->raw.size();
747 buffer = component->raw.data();
748 rowStride = component->rowStride;
749 pixelStride = component->pixelStride;
750 } else {
751 context->status = ERROR;
752 HiLog::Error(LABEL, "Failed to GetComponentData");
753 }
754 } else {
755 bufferSize = GetSurfaceDataSize(surfaceBuffer);
756 buffer = static_cast<uint8_t*>(surfaceBuffer->GetVirAddr());
757 rowStride = surfaceBuffer->GetWidth();
758 pixelStride = NUM1;
759 }
760
761 if (buffer != nullptr && bufferSize != NUM0) {
762 napi_value array;
763 if (CreateArrayBuffer(env, buffer, bufferSize, &array)) {
764 napi_create_object(env, &result);
765 napi_set_named_property(env, result, "byteBuffer", array);
766 BuildIntProperty(env, "componentType", context->componentType, result);
767 BuildIntProperty(env, "rowStride", rowStride, result);
768 BuildIntProperty(env, "pixelStride", pixelStride, result);
769 context->status = SUCCESS;
770 } else {
771 HiLog::Error(LABEL, "napi_create_arraybuffer failed!");
772 }
773 } else {
774 HiLog::Error(LABEL, "buffer is nullptr or bufferSize is %{public}" PRIu32, bufferSize);
775 }
776
777 IMAGE_FUNCTION_OUT();
778 CommonCallbackRoutine(env, context, result);
779 }
780
JsGetComponentExec(napi_env env,ImageAsyncContext * context)781 static void JsGetComponentExec(napi_env env, ImageAsyncContext* context)
782 {
783 if (context == nullptr || context->constructor_ == nullptr ||
784 context->constructor_->sSurfaceBuffer_ == nullptr) {
785 HiLog::Error(LABEL, "Invalid input context");
786 return;
787 }
788 auto surfaceBuffer = context->constructor_->sSurfaceBuffer_;
789 HiLog::Info(LABEL,
790 "JsGetComponentExec surface buffer type %{public}" PRId32, surfaceBuffer->GetFormat());
791 context->status = SplitSurfaceToComponent(context->constructor_, surfaceBuffer);
792 }
793
CheckComponentType(const int32_t & type,int32_t format)794 static bool CheckComponentType(const int32_t& type, int32_t format)
795 {
796 if (IsYCbCr422SP(format) && IsYUVType(type)) {
797 return true;
798 }
799 if (!IsYCbCr422SP(format) && type == static_cast<int32_t>(ComponentType::JPEG)) {
800 return true;
801 }
802 return false;
803 }
804
JsGetComponentArgs(napi_env env,size_t argc,napi_value * argv,ImageAsyncContext * context)805 static bool JsGetComponentArgs(napi_env env, size_t argc, napi_value* argv, ImageAsyncContext* context)
806 {
807 if (argv == nullptr || context == nullptr) {
808 IMAGE_ERR("argv is nullptr");
809 return false;
810 }
811
812 if (context->constructor_ == nullptr ||
813 (!receiverTest && context->constructor_->sSurfaceBuffer_ == nullptr)) {
814 IMAGE_ERR("Constructor is nullptr");
815 return false;
816 }
817
818 if (argc == ARGS1 || argc == ARGS2) {
819 auto argType0 = ImageNapiUtils::getType(env, argv[PARAM0]);
820 if (argType0 == napi_number) {
821 napi_get_value_int32(env, argv[PARAM0], &(context->componentType));
822 } else {
823 IMAGE_ERR("Unsupport arg 0 type: %{public}d", argType0);
824 return false;
825 }
826
827 if (!receiverTest) {
828 auto surfaceBuffer = context->constructor_->sSurfaceBuffer_;
829 if (!CheckComponentType(context->componentType, surfaceBuffer->GetFormat())) {
830 IMAGE_ERR("Unsupport component type 0 value: %{public}d", context->componentType);
831 return false;
832 }
833 }
834 }
835 if (argc == ARGS2) {
836 auto argType1 = ImageNapiUtils::getType(env, argv[PARAM1]);
837 if (argType1 == napi_function) {
838 int32_t refCount = 1;
839 napi_create_reference(env, argv[PARAM1], refCount, &(context->callbackRef));
840 } else {
841 IMAGE_ERR("Unsupport arg 1 type: %{public}d", argType1);
842 return false;
843 }
844 }
845 return true;
846 }
847
JsGetComponent(napi_env env,napi_callback_info info)848 napi_value ImageNapi::JsGetComponent(napi_env env, napi_callback_info info)
849 {
850 IMAGE_FUNCTION_IN();
851 napi_status status;
852 napi_value result = nullptr, thisVar = nullptr;
853 size_t argc = ARGS2;
854 napi_value argv[ARGS2] = {0};
855
856 napi_get_undefined(env, &result);
857
858 status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
859 if (status != napi_ok) {
860 IMAGE_ERR("fail to napi_get_cb_info %{public}d", status);
861 return result;
862 }
863
864 unique_ptr<ImageAsyncContext> context = UnwarpContext(env, info);
865 if (context == nullptr) {
866 std::string errMsg = "fail to unwrap constructor_ ";
867 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
868 errMsg.append(std::to_string(status)));
869 }
870
871 if (!JsGetComponentArgs(env, argc, argv, context.get())) {
872 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
873 "Unsupport arg type!");
874 }
875
876 if (context->callbackRef == nullptr) {
877 napi_create_promise(env, &(context->deferred), &result);
878 } else {
879 napi_get_undefined(env, &result);
880 }
881
882 napi_value resource = nullptr;
883 napi_create_string_utf8(env, "JsGetComponent", NAPI_AUTO_LENGTH, &resource);
884 status = napi_create_async_work(
885 env, nullptr, resource,
886 reinterpret_cast<napi_async_execute_callback>(JsGetComponentExec),
887 reinterpret_cast<napi_async_complete_callback>(JsGetComponentCallBack),
888 static_cast<void *>(context.get()), &(context->work));
889 if (status != napi_ok) {
890 IMAGE_ERR("fail to create async work %{public}d", status);
891 return result;
892 }
893
894 status = napi_queue_async_work(env, context->work);
895 if (status != napi_ok) {
896 IMAGE_ERR("fail to queue async work %{public}d", status);
897 return result;
898 }
899 context.release();
900
901 IMAGE_FUNCTION_OUT();
902 return result;
903 }
904
release()905 void ImageNapi::release()
906 {
907 if (!isRelease) {
908 NativeRelease();
909 isRelease = true;
910 }
911 }
912
CreateComponentData(ComponentType type,size_t size,int32_t rowStride,int32_t pixelStride)913 Component* ImageNapi::CreateComponentData(ComponentType type, size_t size,
914 int32_t rowStride, int32_t pixelStride)
915 {
916 Component* result = nullptr;
917 if (size == NUM0) {
918 HiLog::Error(LABEL, "Could't create 0 size component data");
919 return result;
920 }
921 auto iter = componentData_.find(type);
922 if (iter != componentData_.end()) {
923 HiLog::Info(LABEL, "Component %{public}d already exist. No need create", type);
924 return iter->second.get();
925 }
926 std::unique_ptr<Component> component = std::make_unique<Component>();
927 component->pixelStride = pixelStride;
928 component->rowStride = rowStride;
929 component->raw.resize(size);
930 componentData_.insert(std::map<ComponentType, std::unique_ptr<Component>>::value_type(type,
931 std::move(component)));
932 result = GetComponentData(type);
933 return result;
934 }
GetComponentData(ComponentType type)935 Component* ImageNapi::GetComponentData(ComponentType type)
936 {
937 auto iter = componentData_.find(type);
938 if (iter != componentData_.end()) {
939 return iter->second.get();
940 }
941 return nullptr;
942 }
CombineComponentsIntoSurface()943 uint32_t ImageNapi::CombineComponentsIntoSurface()
944 {
945 if (!IsYCbCr422SP(sSurfaceBuffer_->GetFormat())) {
946 HiLog::Info(LABEL, "No need to combine components for NO YUV format now");
947 return SUCCESS;
948 }
949 Component* y = GetComponentData(ComponentType::YUV_Y);
950 Component* u = GetComponentData(ComponentType::YUV_U);
951 Component* v = GetComponentData(ComponentType::YUV_V);
952 if ((y == nullptr) || (u == nullptr) || (v == nullptr)) {
953 HiLog::Error(LABEL, "No component need to combine");
954 return ERR_IMAGE_DATA_ABNORMAL;
955 }
956 uint32_t bufferSize = GetSurfaceDataSize(sSurfaceBuffer_);
957 uint8_t* buffer = static_cast<uint8_t*>(sSurfaceBuffer_->GetVirAddr());
958 struct YUV422SPData data;
959 data.ySize = y->raw.size();
960 data.uvSize = u->raw.size();
961 data.y = y->raw;
962 data.u = u->raw;
963 data.v = v->raw;
964 YUV422SPDataCopy(buffer, bufferSize, data, true);
965 return SUCCESS;
966 }
967 } // namespace Media
968 } // namespace OHOS
969