1 /*
2 * Copyright (c) 2021-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 "output/camera_output_napi.h"
17 #include <uv.h>
18
19 namespace OHOS {
20 namespace CameraStandard {
21 using namespace std;
22 using OHOS::HiviewDFX::HiLog;
23 using OHOS::HiviewDFX::HiLogLabel;
24
25 thread_local napi_ref CameraOutputCapabilityNapi::sCapabilityConstructor_ = nullptr;
26 thread_local sptr<CameraOutputCapability> CameraOutputCapabilityNapi::sCameraOutputCapability_ = nullptr;
27
CameraOutputCapabilityNapi()28 CameraOutputCapabilityNapi::CameraOutputCapabilityNapi() : env_(nullptr), wrapper_(nullptr)
29 {
30 cameraOutputCapability_ = nullptr;
31 }
32
~CameraOutputCapabilityNapi()33 CameraOutputCapabilityNapi::~CameraOutputCapabilityNapi()
34 {
35 if (wrapper_ != nullptr) {
36 napi_delete_reference(env_, wrapper_);
37 }
38 if (cameraOutputCapability_) {
39 cameraOutputCapability_ = nullptr;
40 }
41 }
42
CameraOutputCapabilityNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)43 void CameraOutputCapabilityNapi::CameraOutputCapabilityNapiDestructor(
44 napi_env env, void* nativeObject, void* finalize_hint)
45 {
46 MEDIA_DEBUG_LOG("CameraOutputCapabilityNapiDestructor enter");
47 CameraOutputCapabilityNapi* cameraOutputCapabilityNapi =
48 reinterpret_cast<CameraOutputCapabilityNapi*>(nativeObject);
49 if (cameraOutputCapabilityNapi != nullptr) {
50 cameraOutputCapabilityNapi->~CameraOutputCapabilityNapi();
51 }
52 }
53
Init(napi_env env,napi_value exports)54 napi_value CameraOutputCapabilityNapi::Init(napi_env env, napi_value exports)
55 {
56 napi_status status;
57 napi_value ctorObj;
58
59 napi_property_descriptor camera_output_capability_props[] = {
60 DECLARE_NAPI_GETTER("previewProfiles", GetPreviewProfiles),
61 DECLARE_NAPI_GETTER("photoProfiles", GetPhotoProfiles),
62 DECLARE_NAPI_GETTER("videoProfiles", GetVideoProfiles),
63 DECLARE_NAPI_GETTER("supportedMetadataObjectTypes", GetSupportedMetadataObjectTypes)
64 };
65
66 status = napi_define_class(env, CAMERA_OUTPUT_CAPABILITY_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
67 CameraOutputCapabilityNapiConstructor, nullptr,
68 sizeof(camera_output_capability_props) / sizeof(camera_output_capability_props[PARAM0]),
69 camera_output_capability_props, &ctorObj);
70 if (status == napi_ok) {
71 int32_t refCount = 1;
72 status = napi_create_reference(env, ctorObj, refCount, &sCapabilityConstructor_);
73 if (status == napi_ok) {
74 status = napi_set_named_property(env, exports, CAMERA_OUTPUT_CAPABILITY_NAPI_CLASS_NAME, ctorObj);
75 if (status == napi_ok) {
76 return exports;
77 }
78 }
79 }
80
81 return nullptr;
82 }
83
WrapSizeJs(napi_env env,Size & size,napi_value & result)84 void WrapSizeJs(napi_env env, Size &size, napi_value &result)
85 {
86 napi_value value = nullptr;
87 napi_create_int32(env, size.width, &value);
88 napi_set_named_property(env, result, "width", value);
89 napi_create_int32(env, size.height, &value);
90 napi_set_named_property(env, result, "height", value);
91 }
92
WrapProfileJs(napi_env env,Profile & profile,napi_value & result)93 void WrapProfileJs(napi_env env, Profile &profile, napi_value &result)
94 {
95 napi_value sizeNapi = nullptr;
96 napi_create_object(env, &result);
97 napi_create_object(env, &sizeNapi);
98 WrapSizeJs(env, profile.size_, sizeNapi);
99 napi_value value = nullptr;
100 napi_create_int32(env, profile.format_, &value);
101 napi_set_named_property(env, result, "format", value);
102 napi_set_named_property(env, result, "size", sizeNapi);
103 }
104
CreateProfileJsArray(napi_env env,napi_status status,std::vector<Profile> profileList)105 static napi_value CreateProfileJsArray(napi_env env, napi_status status, std::vector<Profile> profileList)
106 {
107 napi_value profileArray = nullptr;
108
109 napi_get_undefined(env, &profileArray);
110 if (profileList.empty()) {
111 MEDIA_ERR_LOG("profileList is empty");
112 return profileArray;
113 }
114
115 status = napi_create_array(env, &profileArray);
116 if (status == napi_ok) {
117 for (uint32_t i = 0; i < profileList.size(); i++) {
118 napi_value profile = nullptr;
119 WrapProfileJs(env, profileList[i], profile);
120 if (profile == nullptr || napi_set_element(env, profileArray, i, profile) != napi_ok) {
121 MEDIA_ERR_LOG("Failed to create profile napi wrapper object");
122 napi_get_undefined(env, &profileArray);
123 return profileArray;
124 }
125 }
126 }
127 MEDIA_INFO_LOG("profileList is %{public}zu", profileList.size());
128 return profileArray;
129 }
130
WrapJsVideoProfile(napi_env env,VideoProfile & profile,napi_value & result)131 void WrapJsVideoProfile(napi_env env, VideoProfile &profile, napi_value &result)
132 {
133 napi_value sizeNapi = nullptr;
134 napi_create_object(env, &result);
135 napi_create_object(env, &sizeNapi);
136 WrapSizeJs(env, profile.size_, sizeNapi);
137 napi_set_named_property(env, result, "size", sizeNapi);
138
139 napi_value value = nullptr;
140 napi_create_int32(env, profile.format_, &value);
141 napi_set_named_property(env, result, "format", value);
142
143 napi_value frameRateRange;
144 napi_create_object(env, &frameRateRange);
145 std::vector<int32_t> ranges = profile.framerates_;
146 napi_create_int32(env, ranges[0], &value);
147 napi_set_named_property(env, frameRateRange, "min", value);
148 napi_create_int32(env, ranges[1], &value);
149 napi_set_named_property(env, frameRateRange, "max", value);
150 napi_set_named_property(env, result, "frameRateRange", frameRateRange);
151 }
152
CreateVideoProfileJsArray(napi_env env,napi_status status,std::vector<VideoProfile> profileList)153 static napi_value CreateVideoProfileJsArray(napi_env env, napi_status status, std::vector<VideoProfile> profileList)
154 {
155 napi_value profileArray = nullptr;
156 napi_value profile = nullptr;
157
158 napi_get_undefined(env, &profileArray);
159 if (profileList.empty()) {
160 MEDIA_ERR_LOG("profileList is empty");
161 return profileArray;
162 }
163
164 status = napi_create_array(env, &profileArray);
165 if (status == napi_ok) {
166 for (size_t i = 0; i < profileList.size(); i++) {
167 WrapJsVideoProfile(env, profileList[i], profile);
168 if (profile == nullptr || napi_set_element(env, profileArray, i, profile) != napi_ok) {
169 MEDIA_ERR_LOG("Failed to create profile napi wrapper object");
170 napi_get_undefined(env, &profileArray);
171 return profileArray;
172 }
173 }
174 }
175 MEDIA_INFO_LOG("VideoProfileList is %{public}zu", profileList.size());
176 return profileArray;
177 }
178
CreateMetadataObjectTypeJsArray(napi_env env,napi_status status,std::vector<MetadataObjectType> metadataTypeList)179 static napi_value CreateMetadataObjectTypeJsArray(napi_env env, napi_status status,
180 std::vector<MetadataObjectType> metadataTypeList)
181 {
182 napi_value metadataTypeArray = nullptr;
183 napi_value metadataType = nullptr;
184
185 napi_get_undefined(env, &metadataTypeArray);
186 if (metadataTypeList.empty()) {
187 MEDIA_ERR_LOG("metadataTypeList is empty");
188 return metadataTypeArray;
189 }
190
191 status = napi_create_array(env, &metadataTypeArray);
192 if (status == napi_ok) {
193 for (size_t i = 0; i < metadataTypeList.size(); i++) {
194 napi_create_int32(env, static_cast<int32_t>(metadataTypeList[i]), &metadataType);
195 MEDIA_INFO_LOG("WrapJsVideoProfile success");
196 if (metadataType == nullptr || napi_set_element(env, metadataTypeArray, i, metadataType) != napi_ok) {
197 MEDIA_ERR_LOG("Failed to create metadataType napi wrapper object");
198 napi_get_undefined(env, &metadataTypeArray);
199 return metadataTypeArray;
200 }
201 }
202 }
203 return metadataTypeArray;
204 }
205
206 // Constructor callback
CameraOutputCapabilityNapiConstructor(napi_env env,napi_callback_info info)207 napi_value CameraOutputCapabilityNapi::CameraOutputCapabilityNapiConstructor(napi_env env, napi_callback_info info)
208 {
209 napi_status status;
210 napi_value result = nullptr;
211 napi_value thisVar = nullptr;
212
213 napi_get_undefined(env, &result);
214 CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
215
216 if (status == napi_ok && thisVar != nullptr) {
217 std::unique_ptr<CameraOutputCapabilityNapi> obj = std::make_unique<CameraOutputCapabilityNapi>();
218 obj->env_ = env;
219 obj->cameraOutputCapability_ = sCameraOutputCapability_;
220 status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
221 CameraOutputCapabilityNapi::CameraOutputCapabilityNapiDestructor,
222 nullptr,
223 nullptr);
224 if (status == napi_ok) {
225 obj.release();
226 MEDIA_ERR_LOG("CameraOutputCapabilityNapiConstructor Success wrapping js to native napi");
227 return thisVar;
228 } else {
229 MEDIA_ERR_LOG("Failure wrapping js to native napi");
230 }
231 }
232
233 return result;
234 }
235
CreateCameraOutputCapability(napi_env env,sptr<CameraDevice> camera)236 napi_value CameraOutputCapabilityNapi::CreateCameraOutputCapability(napi_env env, sptr<CameraDevice> camera)
237 {
238 CAMERA_SYNC_TRACE;
239 napi_status status;
240 napi_value result = nullptr;
241 napi_value constructor;
242 if (camera == nullptr) {
243 return result;
244 }
245 status = napi_get_reference_value(env, sCapabilityConstructor_, &constructor);
246 if (status == napi_ok) {
247 sCameraOutputCapability_ = CameraManager::GetInstance()->GetSupportedOutputCapability(camera);
248 if (sCameraOutputCapability_ == nullptr) {
249 MEDIA_ERR_LOG("failed to create CreateCameraOutputCapability");
250 return result;
251 }
252 status = napi_new_instance(env, constructor, 0, nullptr, &result);
253 sCameraOutputCapability_ = nullptr;
254 if (status == napi_ok && result != nullptr) {
255 MEDIA_ERR_LOG("success to create CreateCameraOutputCapabilityNapi");
256 return result;
257 } else {
258 MEDIA_ERR_LOG("Failed to create photo output instance");
259 }
260 }
261 MEDIA_ERR_LOG("CreateCameraOutputCapability napi_get_reference_value failed");
262 napi_get_undefined(env, &result);
263 return result;
264 }
265
GetPreviewProfiles(napi_env env,napi_callback_info info)266 napi_value CameraOutputCapabilityNapi::GetPreviewProfiles(napi_env env, napi_callback_info info)
267 {
268 napi_status status;
269 napi_value jsResult = nullptr;
270 napi_value undefinedResult = nullptr;
271 CameraOutputCapabilityNapi* obj = nullptr;
272 napi_value thisVar = nullptr;
273 MEDIA_INFO_LOG("GetPreviewProfiles start!");
274 napi_get_undefined(env, &undefinedResult);
275 CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
276 MEDIA_INFO_LOG("GetPreviewProfiles 1!");
277 if (status != napi_ok || thisVar == nullptr) {
278 MEDIA_INFO_LOG("Invalid arguments!");
279 return undefinedResult;
280 }
281 MEDIA_INFO_LOG("GetPreviewProfiles 2!");
282 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
283 MEDIA_INFO_LOG("GetPreviewProfiles 3!");
284 if ((status == napi_ok) && (obj != nullptr)) {
285 std::vector<Profile> profileList = obj->cameraOutputCapability_->GetPreviewProfiles();
286 MEDIA_INFO_LOG("GetPreviewProfiles 4!");
287 jsResult = CreateProfileJsArray(env, status, profileList);
288 MEDIA_INFO_LOG("GetPreviewProfiles 5!");
289 return jsResult;
290 }
291 MEDIA_INFO_LOG("GetPreviewProfiles 6!");
292 return undefinedResult;
293 }
294
GetPhotoProfiles(napi_env env,napi_callback_info info)295 napi_value CameraOutputCapabilityNapi::GetPhotoProfiles(napi_env env, napi_callback_info info)
296 {
297 napi_status status;
298 napi_value jsResult = nullptr;
299 napi_value undefinedResult = nullptr;
300 CameraOutputCapabilityNapi* obj = nullptr;
301 napi_value thisVar = nullptr;
302
303 napi_get_undefined(env, &undefinedResult);
304 CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
305
306 if (status != napi_ok || thisVar == nullptr) {
307 MEDIA_ERR_LOG("Invalid arguments!");
308 return undefinedResult;
309 }
310
311 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
312 if ((status == napi_ok) && (obj != nullptr)) {
313 std::vector<Profile> profileList = obj->cameraOutputCapability_->GetPhotoProfiles();
314 jsResult = CreateProfileJsArray(env, status, profileList);
315 return jsResult;
316 }
317
318 return undefinedResult;
319 }
320
321 // todo : should return VideoProfile
GetVideoProfiles(napi_env env,napi_callback_info info)322 napi_value CameraOutputCapabilityNapi::GetVideoProfiles(napi_env env, napi_callback_info info)
323 {
324 napi_status status;
325 napi_value jsResult = nullptr;
326 napi_value undefinedResult = nullptr;
327 CameraOutputCapabilityNapi* obj = nullptr;
328 napi_value thisVar = nullptr;
329
330 napi_get_undefined(env, &undefinedResult);
331 CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
332
333 if (status != napi_ok || thisVar == nullptr) {
334 MEDIA_ERR_LOG("Invalid arguments!");
335 return undefinedResult;
336 }
337
338 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
339 if ((status == napi_ok) && (obj != nullptr)) {
340 std::vector<VideoProfile> profileList = obj->cameraOutputCapability_->GetVideoProfiles();
341 jsResult = CreateVideoProfileJsArray(env, status, profileList);
342 return jsResult;
343 }
344
345 return undefinedResult;
346 }
347
GetSupportedMetadataObjectTypes(napi_env env,napi_callback_info info)348 napi_value CameraOutputCapabilityNapi::GetSupportedMetadataObjectTypes(napi_env env, napi_callback_info info)
349 {
350 napi_status status;
351 napi_value jsResult = nullptr;
352 napi_value undefinedResult = nullptr;
353 CameraOutputCapabilityNapi* obj = nullptr;
354 napi_value thisVar = nullptr;
355
356 napi_get_undefined(env, &undefinedResult);
357 CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
358
359 if (status != napi_ok || thisVar == nullptr) {
360 MEDIA_ERR_LOG("Invalid arguments!");
361 return undefinedResult;
362 }
363
364 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
365 if ((status == napi_ok) && (obj != nullptr)) {
366 std::vector<MetadataObjectType> metadataTypeList;
367 metadataTypeList = obj->cameraOutputCapability_->GetSupportedMetadataObjectType();
368 jsResult = CreateMetadataObjectTypeJsArray(env, status, metadataTypeList);
369 return jsResult;
370 }
371
372 return undefinedResult;
373 }
374 } // namespace CameraStandard
375 } // namespace OHOS
376