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