1 /*
2 * Copyright (C) 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 "avmetadataextractor_napi.h"
17 #include "media_log.h"
18 #include "media_errors.h"
19 #include "common_napi.h"
20 #include "pixel_map_napi.h"
21 #include "string_ex.h"
22 #include "player_xcollie.h"
23 #include "media_dfx.h"
24 #ifdef SUPPORT_JSSTACK
25 #include "xpower_event_js.h"
26 #endif
27 #include "av_common.h"
28 #include "ipc_skeleton.h"
29 #include "tokenid_kit.h"
30
31 using namespace OHOS::AudioStandard;
32
33 namespace {
34 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_METADATA, "AVMetadataExtractorNapi"};
35 constexpr uint8_t ARG_ZERO = 0;
36 constexpr uint8_t ARG_ONE = 1;
37 constexpr uint8_t ARG_TWO = 2;
38 constexpr uint8_t ARG_THREE = 3;
39 constexpr uint8_t ARG_FOUR = 4;
40 }
41
42 namespace OHOS {
43 namespace Media {
44 thread_local napi_ref AVMetadataExtractorNapi::constructor_ = nullptr;
45 const std::string CLASS_NAME = "AVMetadataExtractor";
46
AVMetadataExtractorNapi()47 AVMetadataExtractorNapi::AVMetadataExtractorNapi()
48 {
49 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
50 }
51
~AVMetadataExtractorNapi()52 AVMetadataExtractorNapi::~AVMetadataExtractorNapi()
53 {
54 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
55 }
56
Init(napi_env env,napi_value exports)57 napi_value AVMetadataExtractorNapi::Init(napi_env env, napi_value exports)
58 {
59 napi_property_descriptor staticProperty[] = {
60 DECLARE_NAPI_STATIC_FUNCTION("createAVMetadataExtractor", JsCreateAVMetadataExtractor),
61 };
62
63 napi_property_descriptor properties[] = {
64 DECLARE_NAPI_FUNCTION("setUrlSource", JsSetUrlSource),
65 DECLARE_NAPI_FUNCTION("fetchMetadata", JsResolveMetadata),
66 DECLARE_NAPI_FUNCTION("fetchAlbumCover", JsFetchArtPicture),
67 DECLARE_NAPI_FUNCTION("fetchFrameByTime", JsFetchFrameAtTime),
68 DECLARE_NAPI_FUNCTION("release", JsRelease),
69 DECLARE_NAPI_FUNCTION("getTimeByFrameIndex", JSGetTimeByFrameIndex),
70 DECLARE_NAPI_FUNCTION("getFrameIndexByTime", JSGetFrameIndexByTime),
71 DECLARE_NAPI_GETTER_SETTER("fdSrc", JsGetAVFileDescriptor, JsSetAVFileDescriptor),
72 DECLARE_NAPI_GETTER_SETTER("dataSrc", JsGetDataSrc, JsSetDataSrc),
73 };
74
75 napi_value constructor = nullptr;
76 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
77 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
78 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AVMetadataHelper class");
79
80 status = napi_create_reference(env, constructor, 1, &constructor_);
81 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
82
83 status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
84 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
85
86 status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
87 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
88
89 MEDIA_LOGD("AVMetadataExtractorNapi Init success");
90 return exports;
91 }
92
Constructor(napi_env env,napi_callback_info info)93 napi_value AVMetadataExtractorNapi::Constructor(napi_env env, napi_callback_info info)
94 {
95 napi_value result = nullptr;
96 napi_get_undefined(env, &result);
97
98 size_t argCount = 0;
99 napi_value jsThis = nullptr;
100 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
101 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
102
103 AVMetadataExtractorNapi *extractor = new(std::nothrow) AVMetadataExtractorNapi();
104 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to new AVMetadataExtractorNapi");
105
106 extractor->env_ = env;
107 extractor->helper_ = AVMetadataHelperFactory::CreateAVMetadataHelper();
108 if (extractor->helper_ == nullptr) {
109 delete extractor;
110 MEDIA_LOGE("failed to CreateMetadataHelper");
111 return result;
112 }
113
114 status = napi_wrap(env, jsThis, reinterpret_cast<void *>(extractor),
115 AVMetadataExtractorNapi::Destructor, nullptr, nullptr);
116 if (status != napi_ok) {
117 delete extractor;
118 MEDIA_LOGE("Failed to wrap native instance");
119 return result;
120 }
121
122 MEDIA_LOGI("0x%{public}06" PRIXPTR " Constructor", FAKE_POINTER(extractor));
123 return jsThis;
124 }
125
Destructor(napi_env env,void * nativeObject,void * finalize)126 void AVMetadataExtractorNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
127 {
128 MEDIA_LOGI("0x%{public}06" PRIXPTR " Destructor", FAKE_POINTER(nativeObject));
129 (void)finalize;
130 CHECK_AND_RETURN(nativeObject != nullptr);
131 AVMetadataExtractorNapi *napi = reinterpret_cast<AVMetadataExtractorNapi *>(nativeObject);
132 std::thread([napi]() -> void {
133 MEDIA_LOGD("Destructor Release enter");
134 if (napi != nullptr && napi->helper_ != nullptr) {
135 napi->helper_->Release();
136 }
137 delete napi;
138 }).detach();
139 MEDIA_LOGD("Destructor success");
140 }
141
JsCreateAVMetadataExtractor(napi_env env,napi_callback_info info)142 napi_value AVMetadataExtractorNapi::JsCreateAVMetadataExtractor(napi_env env, napi_callback_info info)
143 {
144 MediaTrace trace("AVMetadataExtractorNapi::JsCreateAVMetadataExtractor");
145 napi_value result = nullptr;
146 napi_get_undefined(env, &result);
147 MEDIA_LOGI("JsCreateAVMetadataExtractor In");
148
149 std::unique_ptr<MediaAsyncContext> asyncContext = std::make_unique<MediaAsyncContext>(env);
150
151 // get args
152 napi_value jsThis = nullptr;
153 napi_value args[1] = { nullptr };
154 size_t argCount = 1;
155 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
156 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
157
158 asyncContext->callbackRef = CommonNapi::CreateReference(env, args[0]);
159 asyncContext->deferred = CommonNapi::CreatePromise(env, asyncContext->callbackRef, result);
160 asyncContext->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
161 asyncContext->ctorFlag = true;
162
163 auto ret = MediaAsyncContext::SendCompleteEvent(env, asyncContext.get(), napi_eprio_high);
164 if (ret != napi_status::napi_ok) {
165 MEDIA_LOGE("failed to SendEvent, ret = %{public}d", ret);
166 } else {
167 asyncContext.release();
168 }
169 MEDIA_LOGI("JsCreateAVMetadataExtractor Out");
170 return result;
171 }
172
JsResolveMetadata(napi_env env,napi_callback_info info)173 napi_value AVMetadataExtractorNapi::JsResolveMetadata(napi_env env, napi_callback_info info)
174 {
175 MediaTrace trace("AVMetadataExtractorNapi::resolveMetadata");
176 napi_value result = nullptr;
177 napi_get_undefined(env, &result);
178 MEDIA_LOGI("JsResolveMetadata In");
179
180 auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
181 napi_value args[1] = { nullptr };
182 size_t argCount = 1;
183
184 AVMetadataExtractorNapi* extractor
185 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
186 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
187 promiseCtx->innerHelper_ = extractor->helper_;
188 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
189 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
190
191 if (extractor->state_ != HelperState::HELPER_STATE_RUNNABLE) {
192 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Can't fetchMetadata, please set source.");
193 }
194
195 // async work
196 napi_value resource = nullptr;
197 napi_create_string_utf8(env, "JsResolveMetadata", NAPI_AUTO_LENGTH, &resource);
198 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
199 auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
200 CHECK_AND_RETURN_LOG(promiseCtx && !promiseCtx->errFlag && promiseCtx->innerHelper_, "Invalid promiseCtx.");
201 promiseCtx->metadata_ = promiseCtx->innerHelper_->GetAVMetadata();
202 CHECK_AND_RETURN(promiseCtx->metadata_ == nullptr);
203 MEDIA_LOGE("ResolveMetadata AVMetadata is nullptr");
204 promiseCtx->SignError(MSERR_EXT_API9_UNSUPPORT_FORMAT, "failed to ResolveMetadata, AVMetadata is nullptr!");
205 }, ResolveMetadataComplete, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
206 NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
207 promiseCtx.release();
208 MEDIA_LOGI("JsResolveMetadata Out");
209 return result;
210 }
211
ResolveMetadataComplete(napi_env env,napi_status status,void * data)212 void AVMetadataExtractorNapi::ResolveMetadataComplete(napi_env env, napi_status status, void *data)
213 {
214 MEDIA_LOGI("ResolveMetadataComplete In");
215 auto promiseCtx = static_cast<AVMetadataExtractorAsyncContext*>(data);
216 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
217
218 napi_value result = nullptr;
219 napi_create_object(env, &result);
220 if (status != napi_ok || promiseCtx->errCode != napi_ok) {
221 promiseCtx->status = promiseCtx->errCode == napi_ok ? MSERR_INVALID_VAL : promiseCtx->errCode;
222 MEDIA_LOGI("Resolve meta data failed");
223 napi_get_undefined(env, &result);
224 CommonCallbackRoutine(env, promiseCtx, result);
225 return;
226 }
227 HandleMetaDataResult(env, promiseCtx, result);
228 promiseCtx->status = ERR_OK;
229 CommonCallbackRoutine(env, promiseCtx, result);
230 }
231
HandleMetaDataResult(napi_env env,AVMetadataExtractorAsyncContext * & promiseCtx,napi_value & result)232 void AVMetadataExtractorNapi::HandleMetaDataResult(napi_env env, AVMetadataExtractorAsyncContext* &promiseCtx,
233 napi_value &result)
234 {
235 bool ret = true;
236 napi_value location = nullptr;
237 napi_value customInfo = nullptr;
238 napi_value tracks = nullptr;
239 napi_create_object(env, &location);
240 napi_create_object(env, &customInfo);
241 napi_get_undefined(env, &tracks);
242 std::shared_ptr<Meta> metadata = promiseCtx->metadata_;
243 for (const auto &key : g_Metadata) {
244 if (metadata->Find(key) == metadata->end()) {
245 MEDIA_LOGE("failed to find key: %{public}s", key.c_str());
246 continue;
247 }
248 MEDIA_LOGE("success to find key: %{public}s", key.c_str());
249 if (key == "latitude" || key == "longitude") {
250 CHECK_AND_CONTINUE_LOG(CommonNapi::SetPropertyByValueType(env, location, metadata, key),
251 "SetProperty failed, key: %{public}s", key.c_str());
252 continue;
253 }
254 if (key == "customInfo") {
255 std::shared_ptr<Meta> customData = std::make_shared<Meta>();
256 ret = metadata->GetData(key, customData);
257 CHECK_AND_CONTINUE_LOG(ret, "GetData failed, key %{public}s", key.c_str());
258 for (auto iter = customData->begin(); iter != customData->end(); ++iter) {
259 AnyValueType type = customData->GetValueType(iter->first);
260 CHECK_AND_CONTINUE_LOG(type == AnyValueType::STRING, "key is not string");
261 CHECK_AND_CONTINUE_LOG(CommonNapi::SetPropertyByValueType(env, customInfo, customData, iter->first),
262 "SetProperty failed, key: %{public}s", key.c_str());
263 }
264 continue;
265 }
266 if (key == "tracks") {
267 std::vector<Format> trackInfoVec;
268 ret = metadata->GetData(key, trackInfoVec);
269 CHECK_AND_CONTINUE_LOG(ret, "GetData failed, key %{public}s", key.c_str());
270 promiseCtx->JsResult = std::make_unique<MediaJsResultArray>(trackInfoVec);
271 CHECK_AND_CONTINUE_LOG(promiseCtx->JsResult, "failed to GetJsResult");
272 promiseCtx->JsResult->GetJsResult(env, tracks);
273 continue;
274 }
275 CHECK_AND_CONTINUE_LOG(CommonNapi::SetPropertyByValueType(env, result, metadata, key),
276 "SetProperty failed, key: %{public}s", key.c_str());
277 }
278 napi_set_named_property(env, result, "location", location);
279 napi_set_named_property(env, result, "customInfo", customInfo);
280 napi_set_named_property(env, result, "tracks", tracks);
281 }
282
ConvertMemToPixelMap(std::shared_ptr<AVSharedMemory> sharedMemory)283 static std::unique_ptr<PixelMap> ConvertMemToPixelMap(std::shared_ptr<AVSharedMemory> sharedMemory)
284 {
285 CHECK_AND_RETURN_RET_LOG(sharedMemory != nullptr, nullptr, "SharedMem is nullptr");
286 MEDIA_LOGI("FetchArtPicture size: %{public}d", sharedMemory->GetSize());
287 SourceOptions sourceOptions;
288 uint32_t errorCode = 0;
289 std::unique_ptr<ImageSource> imageSource =
290 ImageSource::CreateImageSource(sharedMemory->GetBase(), sharedMemory->GetSize(), sourceOptions, errorCode);
291 CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, nullptr, "Failed to create imageSource.");
292 DecodeOptions decodeOptions;
293 std::unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOptions, errorCode);
294 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "Failed to decode imageSource");
295 return pixelMap;
296 }
297
JsFetchArtPicture(napi_env env,napi_callback_info info)298 napi_value AVMetadataExtractorNapi::JsFetchArtPicture(napi_env env, napi_callback_info info)
299 {
300 MediaTrace trace("AVMetadataExtractorNapi::fetchArtPicture");
301 napi_value result = nullptr;
302 napi_get_undefined(env, &result);
303 MEDIA_LOGI("JsFetchArtPicture In");
304
305 auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
306 napi_value args[1] = { nullptr };
307 size_t argCount = 1;
308
309 AVMetadataExtractorNapi* extractor
310 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
311 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
312 promiseCtx->innerHelper_ = extractor->helper_;
313 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
314 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
315
316 if (extractor->state_ != HelperState::HELPER_STATE_RUNNABLE) {
317 promiseCtx->SignError(
318 MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Can't fetchAlbumCover, please set fdSrc or dataSrc.");
319 }
320
321 // async work
322 napi_value resource = nullptr;
323 napi_create_string_utf8(env, "JsFetchArtPicture", NAPI_AUTO_LENGTH, &resource);
324 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
325 MEDIA_LOGI("JsFetchArtPicture task start");
326 auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
327 CHECK_AND_RETURN_LOG(promiseCtx && !promiseCtx->errFlag && promiseCtx->innerHelper_, "Invalid context.");
328 auto sharedMemory = promiseCtx->innerHelper_->FetchArtPicture();
329 promiseCtx->artPicture_ = ConvertMemToPixelMap(sharedMemory);
330 if (promiseCtx->artPicture_ == nullptr) {
331 promiseCtx->SignError(MSERR_EXT_API9_UNSUPPORT_FORMAT, "Failed to fetchAlbumCover");
332 }
333 }, FetchArtPictureComplete, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
334 NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
335 promiseCtx.release();
336 MEDIA_LOGI("JsFetchArtPicture Out");
337 return result;
338 }
339
FetchArtPictureComplete(napi_env env,napi_status status,void * data)340 void AVMetadataExtractorNapi::FetchArtPictureComplete(napi_env env, napi_status status, void *data)
341 {
342 napi_value result = nullptr;
343
344 MEDIA_LOGI("FetchArtPictureComplete In");
345 auto context = static_cast<AVMetadataExtractorAsyncContext*>(data);
346
347 if (status == napi_ok && context->errCode == napi_ok) {
348 result = Media::PixelMapNapi::CreatePixelMap(env, context->artPicture_);
349 context->status = ERR_OK;
350 } else {
351 context->status = context->errCode == napi_ok ? MSERR_INVALID_VAL : context->errCode;
352 napi_get_undefined(env, &result);
353 }
354
355 CommonCallbackRoutine(env, context, result);
356 }
357
CommonCallbackRoutine(napi_env env,AVMetadataExtractorAsyncContext * & asyncContext,const napi_value & valueParam)358 void AVMetadataExtractorNapi::CommonCallbackRoutine(napi_env env, AVMetadataExtractorAsyncContext* &asyncContext,
359 const napi_value &valueParam)
360 {
361 napi_value result[ARG_TWO] = {0};
362 napi_value retVal;
363 napi_value callback = nullptr;
364
365 napi_get_undefined(env, &result[0]);
366 napi_get_undefined(env, &result[1]);
367
368 napi_handle_scope scope = nullptr;
369 napi_open_handle_scope(env, &scope);
370 CHECK_AND_RETURN(scope != nullptr && asyncContext != nullptr);
371 if (asyncContext->status == ERR_OK) {
372 result[1] = valueParam;
373 }
374 napi_create_uint32(env, asyncContext->status, &result[0]);
375
376 if (asyncContext->errFlag) {
377 (void)CommonNapi::CreateError(env, asyncContext->errCode, asyncContext->errMessage, callback);
378 result[0] = callback;
379 }
380 if (asyncContext->deferred) {
381 if (asyncContext->status == ERR_OK) {
382 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
383 } else {
384 napi_reject_deferred(env, asyncContext->deferred, result[0]);
385 }
386 } else {
387 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
388 napi_call_function(env, nullptr, callback, ARG_TWO, result, &retVal); // 2
389 napi_delete_reference(env, asyncContext->callbackRef);
390 }
391
392 napi_delete_async_work(env, asyncContext->work);
393 napi_close_handle_scope(env, scope);
394
395 delete asyncContext;
396 asyncContext = nullptr;
397 }
398
JsFetchFrameAtTime(napi_env env,napi_callback_info info)399 napi_value AVMetadataExtractorNapi::JsFetchFrameAtTime(napi_env env, napi_callback_info info)
400 {
401 MediaTrace trace("AVMetadataExtractorNapi::JsFetchFrameAtTime");
402 MEDIA_LOGI("JsFetchFrameAtTime in");
403 const int32_t maxArgs = ARG_FOUR; // args + callback
404 const int32_t argCallback = ARG_THREE; // index three, the 4th param if exist
405 const int32_t argPixelParam = ARG_TWO; // index 2, the 3rd param
406 size_t argCount = maxArgs;
407 napi_value args[maxArgs] = { nullptr };
408 napi_value result = nullptr;
409 napi_get_undefined(env, &result);
410
411 AVMetadataExtractorNapi* extractor
412 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
413 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
414
415 auto asyncCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
416 CHECK_AND_RETURN_RET_LOG(asyncCtx, result, "failed to GetAsyncContext");
417 asyncCtx->innerHelper_ = extractor->helper_;
418 asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[argCallback]);
419 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
420 napi_valuetype valueType = napi_undefined;
421 bool notParamValid = argCount < argCallback || napi_typeof(env, args[argPixelParam], &valueType) != napi_ok ||
422 valueType != napi_object ||
423 extractor->GetFetchFrameArgs(asyncCtx, env, args[ARG_ZERO], args[ARG_ONE], args[ARG_TWO]) != MSERR_OK;
424 if (notParamValid) {
425 asyncCtx->SignError(MSERR_EXT_API20_PARAM_ERROR_OUT_OF_RANGE, "Parameter check failed");
426 }
427
428 if (extractor->state_ != HelperState::HELPER_STATE_RUNNABLE && !asyncCtx->errFlag) {
429 asyncCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Current state is not runnable, can't fetchFrame.");
430 }
431
432 napi_value resource = nullptr;
433 napi_create_string_utf8(env, "JsFetchFrameAtTime", NAPI_AUTO_LENGTH, &resource);
434 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
435 auto asyncCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
436 CHECK_AND_RETURN_LOG(asyncCtx && !asyncCtx->errFlag && asyncCtx->innerHelper_, "Invalid context.");
437 auto pixelMap = asyncCtx->innerHelper_->
438 FetchScaledFrameYuv(asyncCtx->timeUs, asyncCtx->option, asyncCtx->param_);
439 asyncCtx->pixel_ = pixelMap;
440 if (asyncCtx->pixel_ == nullptr) {
441 asyncCtx->SignError(MSERR_EXT_API9_UNSUPPORT_FORMAT, "FetchFrameByTime failed.");
442 }
443 }, CreatePixelMapComplete, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
444 NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
445 asyncCtx.release();
446 MEDIA_LOGI("JsFetchFrameAtTime Out");
447 return result;
448 }
449
CreatePixelMapComplete(napi_env env,napi_status status,void * data)450 void AVMetadataExtractorNapi::CreatePixelMapComplete(napi_env env, napi_status status, void *data)
451 {
452 napi_value result = nullptr;
453
454 MEDIA_LOGI("CreatePixelMapComplete In");
455 auto context = static_cast<AVMetadataExtractorAsyncContext*>(data);
456 CHECK_AND_RETURN_LOG(context != nullptr, "Invalid context.");
457
458 if (status == napi_ok && context->errCode == napi_ok) {
459 MEDIA_LOGI("set pixel map success");
460 context->status = ERR_OK;
461 result = Media::PixelMapNapi::CreatePixelMap(env, context->pixel_);
462 } else {
463 context->status = context->errCode == napi_ok ? MSERR_INVALID_VAL : context->errCode;
464 MEDIA_LOGW("set pixel map failed");
465 napi_get_undefined(env, &result);
466 }
467
468 CommonCallbackRoutine(env, context, result);
469 }
470
JsRelease(napi_env env,napi_callback_info info)471 napi_value AVMetadataExtractorNapi::JsRelease(napi_env env, napi_callback_info info)
472 {
473 MediaTrace trace("AVMetadataExtractorNapi::release");
474 napi_value result = nullptr;
475 napi_get_undefined(env, &result);
476 MEDIA_LOGI("JsRelease In");
477
478 auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
479 napi_value args[1] = { nullptr };
480 size_t argCount = 1;
481 AVMetadataExtractorNapi *extractor
482 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
483 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
484 promiseCtx->innerHelper_ = extractor->helper_;
485 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
486 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
487
488 if (extractor->dataSrcCb_ != nullptr) {
489 extractor->dataSrcCb_->ClearCallbackReference();
490 extractor->dataSrcCb_ = nullptr;
491 }
492
493 if (extractor->state_ == HelperState::HELPER_STATE_RELEASED) {
494 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Has released once, can't release again.");
495 }
496
497 napi_value resource = nullptr;
498 napi_create_string_utf8(env, "JsRelease", NAPI_AUTO_LENGTH, &resource);
499 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
500 auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
501 CHECK_AND_RETURN_LOG(promiseCtx && !promiseCtx->errFlag && promiseCtx->innerHelper_, "Invalid promiseCtx.");
502 promiseCtx->innerHelper_->Release();
503 }, MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
504 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
505 promiseCtx.release();
506 MEDIA_LOGI("JsRelease Out");
507 return result;
508 }
509
JsSetUrlSource(napi_env env,napi_callback_info info)510 napi_value AVMetadataExtractorNapi::JsSetUrlSource(napi_env env, napi_callback_info info)
511 {
512 MediaTrace trace("AVMetadataExtractorNapi::setUrlSource");
513 napi_value result = nullptr;
514 napi_get_undefined(env, &result);
515 MEDIA_LOGI("JsSetUrlSource In");
516
517 const int32_t maxArgs = ARG_TWO;
518 size_t argCount = ARG_TWO;
519 napi_value args[maxArgs] = { nullptr };
520 AVMetadataExtractorNapi *extractor
521 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
522 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstanceWithParameter");
523
524 CHECK_AND_RETURN_RET_LOG(
525 extractor->state_ == HelperState::HELPER_STATE_IDLE, result, "Has set source once, unsupport set again");
526
527 napi_valuetype valueType = napi_undefined;
528 if (argCount < ARG_ONE || napi_typeof(env, args[ARG_ZERO], &valueType) != napi_ok || valueType != napi_string) {
529 return result;
530 }
531
532 extractor->url_ = CommonNapi::GetStringArgument(env, args[ARG_ZERO]);
533 (void)CommonNapi::GetPropertyMap(env, args[1], extractor->header_);
534 auto res = extractor->helper_->SetUrlSource(extractor->url_, extractor->header_);
535 extractor->state_ = res == MSERR_OK ? HelperState::HELPER_STATE_RUNNABLE : HelperState::HELPER_ERROR;
536 extractor->helper_->SetAVMetadataCaller(AVMetadataCaller::AV_METADATA_EXTRACTOR);
537 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetUrlSource Out", FAKE_POINTER(extractor));
538 return result;
539 }
540
JsSetAVFileDescriptor(napi_env env,napi_callback_info info)541 napi_value AVMetadataExtractorNapi::JsSetAVFileDescriptor(napi_env env, napi_callback_info info)
542 {
543 MediaTrace trace("AVMetadataExtractorNapi::set fd");
544 napi_value result = nullptr;
545 napi_get_undefined(env, &result);
546 MEDIA_LOGI("JsSetAVFileDescriptor In");
547
548 napi_value args[1] = { nullptr };
549 size_t argCount = 1;
550 AVMetadataExtractorNapi *extractor = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
551 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstanceWithParameter");
552 CHECK_AND_RETURN_RET_LOG(
553 extractor->state_ == HelperState::HELPER_STATE_IDLE, result, "Has set source once, unsupport set again");
554 napi_valuetype valueType = napi_undefined;
555 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
556 return result;
557 }
558
559 bool notValidParam = argCount < ARG_ONE || napi_typeof(env, args[0], &valueType) != napi_ok
560 || valueType != napi_object || !CommonNapi::GetFdArgument(env, args[0], extractor->fileDescriptor_);
561 CHECK_AND_RETURN_RET_LOG(!notValidParam, result, "Invalid file descriptor, return");
562 CHECK_AND_RETURN_RET_LOG(extractor->helper_, result, "Invalid AVMetadataExtractorNapi.");
563
564 auto fileDescriptor = extractor->fileDescriptor_;
565 auto res = extractor->helper_->SetSource(fileDescriptor.fd, fileDescriptor.offset, fileDescriptor.length);
566 extractor->state_ = res == MSERR_OK ? HelperState::HELPER_STATE_RUNNABLE : HelperState::HELPER_ERROR;
567 extractor->helper_->SetAVMetadataCaller(AVMetadataCaller::AV_METADATA_EXTRACTOR);
568 return result;
569 }
570
JsGetAVFileDescriptor(napi_env env,napi_callback_info info)571 napi_value AVMetadataExtractorNapi::JsGetAVFileDescriptor(napi_env env, napi_callback_info info)
572 {
573 MediaTrace trace("AVMetadataExtractorNapi::get fd");
574 napi_value result = nullptr;
575 napi_get_undefined(env, &result);
576 MEDIA_LOGI("JsGetAVFileDescriptor In");
577
578 AVMetadataExtractorNapi *extractor = AVMetadataExtractorNapi::GetJsInstance(env, info);
579 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
580
581 napi_value value = nullptr;
582 (void)napi_create_object(env, &value);
583 (void)CommonNapi::AddNumberPropInt32(env, value, "fd", extractor->fileDescriptor_.fd);
584 (void)CommonNapi::AddNumberPropInt64(env, value, "offset", extractor->fileDescriptor_.offset);
585 (void)CommonNapi::AddNumberPropInt64(env, value, "length", extractor->fileDescriptor_.length);
586
587 MEDIA_LOGI("JsGetAVFileDescriptor Out");
588 return value;
589 }
590
JsSetDataSrc(napi_env env,napi_callback_info info)591 napi_value AVMetadataExtractorNapi::JsSetDataSrc(napi_env env, napi_callback_info info)
592 {
593 MediaTrace trace("AVMetadataExtractorNapi::set dataSrc");
594 napi_value result = nullptr;
595 napi_get_undefined(env, &result);
596 MEDIA_LOGI("JsSetDataSrc In");
597
598 napi_value args[1] = { nullptr };
599 size_t argCount = ARG_ONE;
600 AVMetadataExtractorNapi *jsMetaHelper
601 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
602 CHECK_AND_RETURN_RET_LOG(jsMetaHelper != nullptr, result, "failed to GetJsInstanceWithParameter");
603
604 CHECK_AND_RETURN_RET_LOG(
605 jsMetaHelper->state_ == HelperState::HELPER_STATE_IDLE, result, "Has set source once, unsupport set again");
606
607 napi_valuetype valueType = napi_undefined;
608 bool notValidParam = argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object;
609 CHECK_AND_RETURN_RET_LOG(!notValidParam, result, "Invalid dataSrc param, return");
610 CHECK_AND_RETURN_RET_LOG(jsMetaHelper->helper_, result, "Invalid AVMetadataExtractorNapi.");
611 (void)CommonNapi::GetPropertyInt64(env, args[0], "fileSize", jsMetaHelper->dataSrcDescriptor_.fileSize);
612 CHECK_AND_RETURN_RET(
613 jsMetaHelper->dataSrcDescriptor_.fileSize >= -1 && jsMetaHelper->dataSrcDescriptor_.fileSize != 0, result);
614 MEDIA_LOGI("Recvive filesize is %{public}" PRId64 "", jsMetaHelper->dataSrcDescriptor_.fileSize);
615 jsMetaHelper->dataSrcCb_
616 = std::make_shared<HelperDataSourceCallback>(env, jsMetaHelper->dataSrcDescriptor_.fileSize);
617
618 napi_value callback = nullptr;
619 napi_ref ref = nullptr;
620 napi_get_named_property(env, args[0], "callback", &callback);
621 jsMetaHelper->dataSrcDescriptor_.callback = callback;
622 napi_status status = napi_create_reference(env, callback, 1, &ref);
623 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
624 std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
625 const std::string callbackName = "readAt";
626 jsMetaHelper->dataSrcCb_->SaveCallbackReference(callbackName, autoRef);
627 auto res = jsMetaHelper->helper_->SetSource(jsMetaHelper->dataSrcCb_);
628 jsMetaHelper->state_ = res == MSERR_OK ? HelperState::HELPER_STATE_RUNNABLE : HelperState::HELPER_ERROR;
629 MEDIA_LOGI("JsSetDataSrc Out");
630 return result;
631 }
632
JsGetDataSrc(napi_env env,napi_callback_info info)633 napi_value AVMetadataExtractorNapi::JsGetDataSrc(napi_env env, napi_callback_info info)
634 {
635 MediaTrace trace("AVMetadataExtractorNapi::get dataSrc");
636 napi_value result = nullptr;
637 napi_get_undefined(env, &result);
638 MEDIA_LOGI("JsGetDataSrc In");
639
640 AVMetadataExtractorNapi *jsMetaHelper = AVMetadataExtractorNapi::GetJsInstance(env, info);
641 CHECK_AND_RETURN_RET_LOG(jsMetaHelper != nullptr, result, "failed to GetJsInstance");
642 CHECK_AND_RETURN_RET_LOG(jsMetaHelper->dataSrcCb_ != nullptr, result, "failed to check dataSrcCb_");
643
644 napi_value value = nullptr;
645 int64_t fileSize;
646 napi_value callback = nullptr;
647 (void)napi_create_object(env, &value);
648 (void)jsMetaHelper->dataSrcCb_->GetSize(fileSize);
649 (void)CommonNapi::AddNumberPropInt64(env, value, "fileSize", fileSize);
650 const std::string callbackName = "readAt";
651 int32_t ret = jsMetaHelper->dataSrcCb_->GetCallback(callbackName, &callback);
652 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, result, "failed to GetCallback");
653 (void)HelperDataSourceCallback::AddNapiValueProp(env, value, "callback", callback);
654
655 MEDIA_LOGI("JsGetDataSrc Out");
656 return value;
657 }
658
GetFetchFrameArgs(std::unique_ptr<AVMetadataExtractorAsyncContext> & asyncCtx,napi_env env,napi_value timeUs,napi_value option,napi_value params)659 int32_t AVMetadataExtractorNapi::GetFetchFrameArgs(std::unique_ptr<AVMetadataExtractorAsyncContext> &asyncCtx,
660 napi_env env, napi_value timeUs, napi_value option, napi_value params)
661 {
662 napi_status ret = napi_get_value_int64(env, timeUs, &asyncCtx->timeUs);
663 CHECK_AND_RETURN_RET_LOG(ret == napi_ok, MSERR_INVALID_VAL, "failed to get timeUs");
664
665 ret = napi_get_value_int32(env, option, &asyncCtx->option);
666 CHECK_AND_RETURN_RET_LOG(ret == napi_ok, MSERR_INVALID_VAL, "failed to get option");
667
668 int32_t width = 0;
669 if (!CommonNapi::GetPropertyInt32(env, params, "width", width)) {
670 MEDIA_LOGW("failed to get width");
671 }
672
673 int32_t height = 0;
674 if (!CommonNapi::GetPropertyInt32(env, params, "height", height)) {
675 MEDIA_LOGW("failed to get height");
676 }
677
678 PixelFormat colorFormat = PixelFormat::RGBA_8888;
679 int32_t formatVal = 3;
680 CommonNapi::GetPropertyInt32(env, params, "colorFormat", formatVal);
681 colorFormat = static_cast<PixelFormat>(formatVal);
682 if (colorFormat != PixelFormat::RGB_565 && colorFormat != PixelFormat::RGB_888 &&
683 colorFormat != PixelFormat::RGBA_8888) {
684 MEDIA_LOGE("formatVal is invalid");
685 return MSERR_INVALID_VAL;
686 }
687
688 asyncCtx->param_.dstWidth = width;
689 asyncCtx->param_.dstHeight = height;
690 asyncCtx->param_.colorFormat = colorFormat;
691 return MSERR_OK;
692 }
693
GetJsInstance(napi_env env,napi_callback_info info)694 AVMetadataExtractorNapi* AVMetadataExtractorNapi::GetJsInstance(napi_env env, napi_callback_info info)
695 {
696 size_t argCount = 0;
697 napi_value jsThis = nullptr;
698 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
699 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
700
701 AVMetadataExtractorNapi *extractor = nullptr;
702 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&extractor));
703 CHECK_AND_RETURN_RET_LOG(status == napi_ok && extractor != nullptr, nullptr, "failed to napi_unwrap");
704
705 return extractor;
706 }
707
GetJsInstanceWithParameter(napi_env env,napi_callback_info info,size_t & argc,napi_value * argv)708 AVMetadataExtractorNapi* AVMetadataExtractorNapi::GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
709 size_t &argc, napi_value *argv)
710 {
711 napi_value jsThis = nullptr;
712 napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
713 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
714
715 AVMetadataExtractorNapi *extractor = nullptr;
716 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&extractor));
717 CHECK_AND_RETURN_RET_LOG(status == napi_ok && extractor != nullptr, nullptr, "failed to napi_unwrap");
718
719 return extractor;
720 }
721
JSGetTimeByFrameIndex(napi_env env,napi_callback_info info)722 napi_value AVMetadataExtractorNapi::JSGetTimeByFrameIndex(napi_env env, napi_callback_info info)
723 {
724 MediaTrace trace("AVMetadataExtractorNapi::JSGetTimeByFrameIndex");
725 napi_value result = nullptr;
726 napi_get_undefined(env, &result);
727 MEDIA_LOGI("frame to time");
728
729 napi_value args[ARG_TWO] = { nullptr };
730 size_t argCount = ARG_TWO;
731 AVMetadataExtractorNapi* extractor
732 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
733 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
734
735 auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
736
737 if (CommonNapi::CheckValueType(env, args[0], napi_number)) {
738 auto res = napi_get_value_uint32(env, args[0], &promiseCtx->index_);
739 if (res != napi_ok || static_cast<int32_t>(promiseCtx->index_) < 0) {
740 promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "frame index is not valid");
741 }
742 }
743
744 promiseCtx->innerHelper_ = extractor->helper_;
745 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[1]);
746 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
747
748 if (extractor->state_ != HelperState::HELPER_STATE_RUNNABLE) {
749 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Invalid state, please set source");
750 }
751
752 // async work
753 napi_value resource = nullptr;
754 napi_create_string_utf8(env, "JSGetTimeByFrameIndex", NAPI_AUTO_LENGTH, &resource);
755 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
756 auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
757 CHECK_AND_RETURN_LOG(promiseCtx && !promiseCtx->errFlag && promiseCtx->innerHelper_, "Invalid promiseCtx.");
758 auto res = promiseCtx->innerHelper_->GetTimeByFrameIndex(promiseCtx->index_, promiseCtx->timeStamp_);
759 if (res != MSERR_EXT_API9_OK) {
760 MEDIA_LOGE("JSGetTimeByFrameIndex get result SignError");
761 promiseCtx->SignError(MSERR_EXT_API9_UNSUPPORT_FORMAT, "Demuxer getTimeByFrameIndex failed.");
762 }
763 }, GetTimeByFrameIndexComplete, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
764 NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
765 promiseCtx.release();
766 return result;
767 }
768
GetTimeByFrameIndexComplete(napi_env env,napi_status status,void * data)769 void AVMetadataExtractorNapi::GetTimeByFrameIndexComplete(napi_env env, napi_status status, void *data)
770 {
771 napi_value result = nullptr;
772 auto context = static_cast<AVMetadataExtractorAsyncContext*>(data);
773
774 if (status == napi_ok && context->errCode == napi_ok) {
775 napi_create_int64(env, context->timeStamp_, &result);
776 context->status = ERR_OK;
777 } else {
778 context->status = context->errCode == napi_ok ? MSERR_INVALID_VAL : context->errCode;
779 napi_get_undefined(env, &result);
780 }
781 CommonCallbackRoutine(env, context, result);
782 }
783
JSGetFrameIndexByTime(napi_env env,napi_callback_info info)784 napi_value AVMetadataExtractorNapi::JSGetFrameIndexByTime(napi_env env, napi_callback_info info)
785 {
786 MediaTrace trace("AVMetadataExtractorNapi::JSGetFrameIndexByTime");
787 napi_value result = nullptr;
788 napi_get_undefined(env, &result);
789 MEDIA_LOGI("time to frame");
790
791 napi_value args[ARG_TWO] = { nullptr };
792 size_t argCount = ARG_TWO;
793 AVMetadataExtractorNapi* extractor
794 = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
795 CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
796
797 auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
798
799 if (CommonNapi::CheckValueType(env, args[0], napi_number)) {
800 int64_t timeStamp = 0;
801 auto res = napi_get_value_int64(env, args[0], &timeStamp);
802 if (res != napi_ok) {
803 promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "time stamp is not valid");
804 }
805 promiseCtx->timeStamp_ = static_cast<uint64_t>(timeStamp);
806 }
807
808 promiseCtx->innerHelper_ = extractor->helper_;
809 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[1]);
810 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
811
812 if (extractor->state_ != HelperState::HELPER_STATE_RUNNABLE) {
813 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Invalid state, please set source");
814 }
815
816 // async work
817 napi_value resource = nullptr;
818 napi_create_string_utf8(env, "JSGetFrameIndexByTime", NAPI_AUTO_LENGTH, &resource);
819 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
820 auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
821 CHECK_AND_RETURN_LOG(promiseCtx && !promiseCtx->errFlag && promiseCtx->innerHelper_, "Invalid promiseCtx.");
822 auto res = promiseCtx->innerHelper_->GetFrameIndexByTime(promiseCtx->timeStamp_, promiseCtx->index_);
823 if (res != MSERR_EXT_API9_OK) {
824 MEDIA_LOGE("JSGetFrameIndexByTime get result SignError");
825 promiseCtx->SignError(MSERR_EXT_API9_UNSUPPORT_FORMAT, "Demuxer getFrameIndexByTime failed.");
826 }
827 }, GetFrameIndexByTimeComplete, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
828 NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
829 promiseCtx.release();
830 return result;
831 }
832
GetFrameIndexByTimeComplete(napi_env env,napi_status status,void * data)833 void AVMetadataExtractorNapi::GetFrameIndexByTimeComplete(napi_env env, napi_status status, void *data)
834 {
835 napi_value result = nullptr;
836 auto context = static_cast<AVMetadataExtractorAsyncContext*>(data);
837
838 if (status == napi_ok && context->errCode == napi_ok) {
839 napi_create_uint32(env, context->index_, &result);
840 context->status = ERR_OK;
841 } else {
842 context->status = context->errCode == napi_ok ? MSERR_INVALID_VAL : context->errCode;
843 napi_get_undefined(env, &result);
844 }
845 CommonCallbackRoutine(env, context, result);
846 }
847 } // namespace Media
848 } // namespace OHOS