• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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