1 /*
2 * Copyright (c) 2021-2023 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 "output/photo_napi.h"
17
18 #include "camera_log.h"
19 #include "hilog/log.h"
20 #include "image_napi.h"
21 #include "napi/native_common.h"
22 #include "napi_ref_manager.h"
23
24 namespace OHOS {
25 namespace CameraStandard {
26 thread_local napi_ref PhotoNapi::sConstructor_ = nullptr;
27 thread_local napi_value PhotoNapi::sMainImage_ = nullptr;
28 thread_local napi_value PhotoNapi::sRawImage_ = nullptr;
29 sptr<SurfaceBuffer> PhotoNapi::imageBuffer_ = nullptr;
30 thread_local uint32_t PhotoNapi::photoTaskId = PHOTO_TASKID;
31
PhotoNapi()32 PhotoNapi::PhotoNapi() : env_(nullptr), mainImage_(nullptr), rawImage_(nullptr) {}
33
~PhotoNapi()34 PhotoNapi::~PhotoNapi()
35 {
36 MEDIA_DEBUG_LOG("~PhotoNapi is called");
37 }
38
39 // Constructor callback
PhotoNapiConstructor(napi_env env,napi_callback_info info)40 napi_value PhotoNapi::PhotoNapiConstructor(napi_env env, napi_callback_info info)
41 {
42 MEDIA_DEBUG_LOG("PhotoNapiConstructor is called");
43 napi_status status;
44 napi_value result = nullptr;
45 napi_value thisVar = nullptr;
46
47 napi_get_undefined(env, &result);
48 CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
49
50 if (status == napi_ok && thisVar != nullptr) {
51 std::unique_ptr<PhotoNapi> obj = std::make_unique<PhotoNapi>();
52 obj->env_ = env;
53 obj->mainImage_ = sMainImage_;
54 obj->rawImage_ = sRawImage_;
55 status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
56 PhotoNapi::PhotoNapiDestructor, nullptr, nullptr);
57 if (status == napi_ok) {
58 obj.release();
59 return thisVar;
60 } else {
61 MEDIA_ERR_LOG("Failure wrapping js to native napi");
62 }
63 }
64 MEDIA_ERR_LOG("PhotoNapiConstructor call Failed!");
65 return result;
66 }
67
PhotoNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)68 void PhotoNapi::PhotoNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
69 {
70 MEDIA_DEBUG_LOG("PhotoNapiDestructor is called");
71 PhotoNapi* photo = reinterpret_cast<PhotoNapi*>(nativeObject);
72 if (photo != nullptr) {
73 delete photo;
74 }
75 }
76
Init(napi_env env,napi_value exports)77 napi_value PhotoNapi::Init(napi_env env, napi_value exports)
78 {
79 MEDIA_DEBUG_LOG("Init is called");
80 napi_status status;
81 napi_value ctorObj;
82
83 napi_property_descriptor photo_properties[] = {
84 // Photo
85 DECLARE_NAPI_GETTER("main", GetMain),
86 DECLARE_NAPI_GETTER("rawImage", GetRaw),
87 DECLARE_NAPI_FUNCTION("release", Release),
88 };
89
90 status = napi_define_class(env, PHOTO_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
91 PhotoNapiConstructor, nullptr,
92 sizeof(photo_properties) / sizeof(photo_properties[PARAM0]),
93 photo_properties, &ctorObj);
94 if (status == napi_ok) {
95 if (NapiRefManager::CreateMemSafetyRef(env, ctorObj, &sConstructor_) == napi_ok) {
96 status = napi_set_named_property(env, exports, PHOTO_NAPI_CLASS_NAME, ctorObj);
97 CHECK_RETURN_RET(status == napi_ok, exports);
98 }
99 }
100 MEDIA_ERR_LOG("Init call Failed!");
101 return nullptr;
102 }
103
CreatePhoto(napi_env env,napi_value mainImage,bool isRaw,sptr<SurfaceBuffer> imageBuffer)104 napi_value PhotoNapi::CreatePhoto(napi_env env, napi_value mainImage, bool isRaw, sptr<SurfaceBuffer> imageBuffer)
105 {
106 MEDIA_DEBUG_LOG("CreatePhoto is called");
107 CAMERA_SYNC_TRACE;
108 napi_status status;
109 napi_value result = nullptr;
110 napi_value constructor;
111 napi_get_undefined(env, &result);
112
113 imageBuffer_ = imageBuffer;
114 status = napi_get_reference_value(env, sConstructor_, &constructor);
115 if (status == napi_ok) {
116 if (isRaw) {
117 sRawImage_ = mainImage;
118 MEDIA_DEBUG_LOG("raw image");
119 } else {
120 sMainImage_ = mainImage;
121 }
122 status = napi_new_instance(env, constructor, 0, nullptr, &result);
123 sRawImage_ = nullptr;
124 sMainImage_ = nullptr;
125 if (status == napi_ok && result != nullptr) {
126 return result;
127 } else {
128 MEDIA_ERR_LOG("Failed to create photo obj instance");
129 }
130 }
131 napi_get_undefined(env, &result);
132 MEDIA_ERR_LOG("CreatePhoto call Failed");
133 return result;
134 }
135
GetMain(napi_env env,napi_callback_info info)136 napi_value PhotoNapi::GetMain(napi_env env, napi_callback_info info)
137 {
138 MEDIA_INFO_LOG("GetMain is called");
139 napi_status status;
140 napi_value result = nullptr;
141 size_t argc = ARGS_ZERO;
142 napi_value argv[ARGS_ZERO];
143 napi_value thisVar = nullptr;
144
145 MEDIA_DEBUG_LOG("PhotoNapi::GetMain get js args");
146 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
147
148 napi_get_undefined(env, &result);
149 PhotoNapi* photoNapi = nullptr;
150 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoNapi));
151 if (status == napi_ok && photoNapi != nullptr) {
152 result = photoNapi->mainImage_;
153 MEDIA_ERR_LOG("PhotoNapi::GetMain Success");
154 return result;
155 }
156 napi_get_undefined(env, &result);
157 MEDIA_ERR_LOG("PhotoNapi::GetMain call Failed");
158 return result;
159 }
160
CreateRawPhoto(napi_env env,napi_value rawImage)161 napi_value PhotoNapi::CreateRawPhoto(napi_env env, napi_value rawImage)
162 {
163 MEDIA_DEBUG_LOG("CreateRawPhoto is called");
164 CAMERA_SYNC_TRACE;
165 napi_status status;
166 napi_value result = nullptr;
167 napi_value constructor;
168 napi_get_undefined(env, &result);
169
170 status = napi_get_reference_value(env, sConstructor_, &constructor);
171 if (status == napi_ok) {
172 sRawImage_ = rawImage;
173 status = napi_new_instance(env, constructor, 0, nullptr, &result);
174 sRawImage_ = nullptr;
175 if (status == napi_ok && result != nullptr) {
176 return result;
177 } else {
178 MEDIA_ERR_LOG("Failed to create photo obj instance");
179 }
180 }
181 napi_get_undefined(env, &result);
182 MEDIA_ERR_LOG("CreateRawPhoto call Failed");
183 return result;
184 }
185
GetRaw(napi_env env,napi_callback_info info)186 napi_value PhotoNapi::GetRaw(napi_env env, napi_callback_info info)
187 {
188 MEDIA_INFO_LOG("GetRaw is called");
189 napi_status status;
190 napi_value result = nullptr;
191 size_t argc = ARGS_ZERO;
192 napi_value argv[ARGS_ZERO];
193 napi_value thisVar = nullptr;
194
195 MEDIA_DEBUG_LOG("PhotoNapi::GetRaw get js args");
196 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
197
198 napi_get_undefined(env, &result);
199 PhotoNapi* photoNapi = nullptr;
200 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoNapi));
201 if (status == napi_ok && photoNapi != nullptr) {
202 result = photoNapi->rawImage_;
203 MEDIA_DEBUG_LOG("PhotoNapi::GetRaw Success");
204 return result;
205 }
206 napi_get_undefined(env, &result);
207 MEDIA_ERR_LOG("PhotoNapi::GetRaw call Failed");
208 return result;
209 }
210
Release(napi_env env,napi_callback_info info)211 napi_value PhotoNapi::Release(napi_env env, napi_callback_info info)
212 {
213 MEDIA_INFO_LOG("Release is called");
214 napi_status status;
215 napi_value result = nullptr;
216 napi_value resource = nullptr;
217 size_t argc = ARGS_ZERO;
218 napi_value argv[ARGS_ZERO];
219 napi_value thisVar = nullptr;
220
221 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
222 imageBuffer_ = nullptr;
223 napi_get_undefined(env, &result);
224 std::unique_ptr<PhotoAsyncContext> asyncContext = std::make_unique<PhotoAsyncContext>();
225 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
226 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
227 CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
228 CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
229
230 status = napi_create_async_work(
231 env, nullptr, resource,
232 [](napi_env env, void* data) {
233 auto context = static_cast<PhotoAsyncContext*>(data);
234 context->status = false;
235 // Start async trace
236 context->funcName = "PhotoNapi::Release";
237 context->taskId = CameraNapiUtils::IncrementAndGet(photoTaskId);
238 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
239 if (context->objectInfo != nullptr) {
240 context->status = true;
241 context->objectInfo->mainImage_ = nullptr;
242 context->objectInfo->rawImage_ = nullptr;
243 }
244 },
245 [](napi_env env, napi_status status, void* data) {
246 auto context = static_cast<PhotoAsyncContext*>(data);
247 CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
248 napi_value result = nullptr;
249 napi_get_undefined(env, &result);
250 napi_resolve_deferred(env, context->deferred, result);
251 napi_delete_async_work(env, context->work);
252 delete context;
253 }, static_cast<void*>(asyncContext.get()), &asyncContext->work);
254 if (status != napi_ok) {
255 MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoNapi::Release");
256 napi_get_undefined(env, &result);
257 } else {
258 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
259 asyncContext.release();
260 }
261 } else {
262 MEDIA_ERR_LOG("PhotoNapi::Release call Failed!");
263 }
264 return result;
265 }
266 } // namespace CameraStandard
267 } // namespace OHOS