• 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, "AVMetadataExtractorNapi"};
35 }
36 
37 namespace OHOS {
38 namespace Media {
39 static const std::map<HelperStates, std::string> stateMap = {
40     {HELPER_IDLE, AVMetadataHelperState::STATE_IDLE},
41     {HELPER_PREPARED, AVMetadataHelperState::STATE_PREPARED},
42     {HELPER_RELEASED, AVMetadataHelperState::STATE_RELEASED},
43     {HELPER_CALL_DONE, AVMetadataHelperState::STATE_CALL_DONE},
44 };
45 
46 thread_local napi_ref AVMetadataExtractorNapi::constructor_ = nullptr;
47 const std::string CLASS_NAME = "AVMetadataExtractor";
48 
AVMetadataExtractorNapi()49 AVMetadataExtractorNapi::AVMetadataExtractorNapi()
50 {
51     MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
52 }
53 
~AVMetadataExtractorNapi()54 AVMetadataExtractorNapi::~AVMetadataExtractorNapi()
55 {
56     MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
57 }
58 
Init(napi_env env,napi_value exports)59 napi_value AVMetadataExtractorNapi::Init(napi_env env, napi_value exports)
60 {
61     napi_property_descriptor staticProperty[] = {
62         DECLARE_NAPI_STATIC_FUNCTION("createAVMetadataExtractor", JsCreateAVMetadataExtractor),
63     };
64 
65     napi_property_descriptor properties[] = {
66         DECLARE_NAPI_FUNCTION("fetchMetadata", JsResolveMetadata),
67         DECLARE_NAPI_FUNCTION("fetchAlbumCover", JsFetchArtPicture),
68         DECLARE_NAPI_FUNCTION("release", JsRelease),
69 
70         DECLARE_NAPI_GETTER_SETTER("url", JsGetUrl, JsSetUrl),
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("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     CHECK_AND_RETURN_RET_LOG(extractor->helper_ != nullptr, result, "failed to CreateMetadataHelper");
109 
110     extractor->taskQue_ = std::make_unique<TaskQueue>("AVMetadataExtractorNapi");
111     (void)extractor->taskQue_->Start();
112 
113     extractor->extractorCb_ = std::make_shared<AVMetadataHelperCallback>(env, extractor);
114     (void)extractor->helper_->SetHelperCallback(extractor->extractorCb_);
115 
116     status = napi_wrap(env, jsThis, reinterpret_cast<void *>(extractor),
117         AVMetadataExtractorNapi::Destructor, nullptr, nullptr);
118     if (status != napi_ok) {
119         delete extractor;
120         MEDIA_LOGE("Failed to wrap native instance");
121         return result;
122     }
123 
124     MEDIA_LOGI("Constructor success");
125     return jsThis;
126 }
127 
Destructor(napi_env env,void * nativeObject,void * finalize)128 void AVMetadataExtractorNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
129 {
130     (void)finalize;
131     if (nativeObject != nullptr) {
132         AVMetadataExtractorNapi *extractor = reinterpret_cast<AVMetadataExtractorNapi *>(nativeObject);
133         auto task = extractor->ReleaseTask();
134         if (task != nullptr) {
135             MEDIA_LOGI("Destructor Wait Release Task Start");
136             task->GetResult(); // sync release
137             MEDIA_LOGI("Destructor Wait Release Task End");
138         }
139         extractor->WaitTaskQueStop();
140         delete extractor;
141     }
142     MEDIA_LOGI("Destructor success");
143 }
144 
JsCreateAVMetadataExtractor(napi_env env,napi_callback_info info)145 napi_value AVMetadataExtractorNapi::JsCreateAVMetadataExtractor(napi_env env, napi_callback_info info)
146 {
147     MediaTrace trace("AVMetadataExtractorNapi::JsCreateAVMetadataExtractor");
148     napi_value result = nullptr;
149     napi_get_undefined(env, &result);
150     MEDIA_LOGI("JsCreateAVMetadataExtractor In");
151 
152     std::unique_ptr<MediaAsyncContext> asyncContext = std::make_unique<MediaAsyncContext>(env);
153 
154     // get args
155     napi_value jsThis = nullptr;
156     napi_value args[1] = { nullptr };
157     size_t argCount = 1;
158     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
159     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
160 
161     asyncContext->callbackRef = CommonNapi::CreateReference(env, args[0]);
162     asyncContext->deferred = CommonNapi::CreatePromise(env, asyncContext->callbackRef, result);
163     asyncContext->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
164     asyncContext->ctorFlag = true;
165 
166     napi_value resource = nullptr;
167     napi_create_string_utf8(env, "JsCreateAVMetadataExtractor", NAPI_AUTO_LENGTH, &resource);
168     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {},
169         MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncContext.get()), &asyncContext->work));
170     NAPI_CALL(env, napi_queue_async_work(env, asyncContext->work));
171     asyncContext.release();
172     MEDIA_LOGI("JsCreateAVMetadataExtractor Out");
173     return result;
174 }
175 
ResolveMetadataTask(std::unique_ptr<AVMetadataExtractorAsyncContext> & promiseCtx)176 std::shared_ptr<TaskHandler<TaskRet>> AVMetadataExtractorNapi::ResolveMetadataTask(
177     std::unique_ptr<AVMetadataExtractorAsyncContext> &promiseCtx)
178 {
179     auto task = std::make_shared<TaskHandler<TaskRet>>([this, &metadata = promiseCtx->metadata_]() {
180         MEDIA_LOGI("ResolveMetadata Task In");
181         std::unique_lock<std::mutex> lock(taskMutex_);
182         auto state = GetCurrentState();
183         if (state == AVMetadataHelperState::STATE_PREPARED || state == AVMetadataHelperState::STATE_CALL_DONE) {
184             std::unordered_map<int32_t, std::string> res = helper_->ResolveMetadata();
185             MEDIA_LOGD("ResolveMetadata Task end resolve: %{public}zu", res.size());
186             metadata = std::make_shared<std::unordered_map<int32_t, std::string>>(res);
187 
188             stopWait_ = false;
189             LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "ResolveMetadataTask", false)
190 
191             if (GetCurrentState() == AVMetadataHelperState::STATE_ERROR) {
192                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
193                     "failed to resolve metadata, metadata helper enter error status!");
194             }
195         } else {
196             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
197                 "current state is not initialized, unsupport resolve metadata operation");
198         }
199 
200         MEDIA_LOGI("ResolveMetadata Task Out");
201         return TaskRet(MSERR_EXT_API9_OK, "Success");
202     });
203 
204     (void)taskQue_->EnqueueTask(task);
205     return task;
206 }
207 
JsResolveMetadata(napi_env env,napi_callback_info info)208 napi_value AVMetadataExtractorNapi::JsResolveMetadata(napi_env env, napi_callback_info info)
209 {
210     MediaTrace trace("AVMetadataExtractorNapi::resolveMetadata");
211     napi_value result = nullptr;
212     napi_get_undefined(env, &result);
213     MEDIA_LOGI("JsResolveMetadata In");
214 
215     auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
216     napi_value args[1] = { nullptr };
217     size_t argCount = 1;
218 
219     AVMetadataExtractorNapi* extractor
220         = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
221     CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
222     promiseCtx->napi = extractor;
223     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
224     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
225 
226     promiseCtx->task_ = extractor->ResolveMetadataTask(promiseCtx);
227 
228     // async work
229     napi_value resource = nullptr;
230     napi_create_string_utf8(env, "JsResolveMetadata", NAPI_AUTO_LENGTH, &resource);
231     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
232         [](napi_env env, void *data) {
233             auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
234             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
235 
236             if (promiseCtx->task_) {
237                 auto result = promiseCtx->task_->GetResult();
238                 MEDIA_LOGD("JsResolveMetadata get result end");
239                 if (result.Value().first != MSERR_EXT_API9_OK) {
240                     MEDIA_LOGE("JsResolveMetadata get result SignError");
241                     promiseCtx->SignError(result.Value().first, result.Value().second);
242                 }
243             }
244             MEDIA_LOGI("The js thread of resolving meta data finishes execution and returns");
245         },
246         ResolveMetadataComplete, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
247     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
248     promiseCtx.release();
249     MEDIA_LOGI("JsResolveMetadata Out");
250     return result;
251 }
252 
ResolveMetadataComplete(napi_env env,napi_status status,void * data)253 void AVMetadataExtractorNapi::ResolveMetadataComplete(napi_env env, napi_status status, void *data)
254 {
255     MEDIA_LOGI("ResolveMetadataComplete In");
256     auto promiseCtx = static_cast<AVMetadataExtractorAsyncContext*>(data);
257     CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
258 
259     napi_value result = nullptr;
260     napi_create_object(env, &result);
261 
262     if (status == napi_ok && promiseCtx->errCode == napi_ok) {
263         for (auto iter = promiseCtx->metadata_->begin(); iter != promiseCtx->metadata_->end(); ++iter) {
264             MEDIA_LOGI("Resolve metadata completed, key: %{public}d, val: %{public}s",
265                 iter->first, iter->second.c_str());
266 
267             napi_value keyNapi = nullptr;
268             auto it = g_MetadataCodeMap.find(iter->first);
269             const char* key = nullptr;
270             if (it != g_MetadataCodeMap.end()) {
271                 key = it->second;
272             }
273             if (key == nullptr) {
274                 MEDIA_LOGW("failed to get key: %{public}d", iter->first);
275                 continue;
276             }
277             napi_status st = napi_create_string_utf8(env, key, NAPI_AUTO_LENGTH, &keyNapi);
278 
279             napi_value valueNapi = nullptr;
280             st = napi_create_string_utf8(env, iter->second.c_str(), NAPI_AUTO_LENGTH, &valueNapi);
281             napi_set_property(env, result, keyNapi, valueNapi);
282             if (st != napi_ok) {
283                 MEDIA_LOGW("failed to set property: %{public}d", iter->first);
284                 continue;
285             }
286         }
287         promiseCtx->status = ERR_OK;
288     } else {
289         promiseCtx->status = promiseCtx->errCode == napi_ok ? MSERR_INVALID_VAL : promiseCtx->errCode;
290         MEDIA_LOGI("Resolve meta data failed");
291         napi_get_undefined(env, &result);
292     }
293 
294     CommonCallbackRoutine(env, promiseCtx, result);
295 }
296 
FetchArtPictureTask(std::unique_ptr<AVMetadataExtractorAsyncContext> & promiseCtx)297 std::shared_ptr<TaskHandler<TaskRet>> AVMetadataExtractorNapi::FetchArtPictureTask(
298     std::unique_ptr<AVMetadataExtractorAsyncContext> &promiseCtx)
299 {
300     auto task = std::make_shared<TaskHandler<TaskRet>>(
301         [this, &napi = promiseCtx->napi, &picture = promiseCtx->artPicture_]() {
302         MEDIA_LOGI("FetchArtPicture Task In");
303         std::unique_lock<std::mutex> lock(taskMutex_);
304         auto state = GetCurrentState();
305         if (state == AVMetadataHelperState::STATE_PREPARED || state == AVMetadataHelperState::STATE_CALL_DONE) {
306             auto mem = helper_->FetchArtPicture();
307             if (mem == nullptr) {
308                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
309                     "FetchArtPicture result is nullptr.");
310             }
311             MEDIA_LOGD("FetchArtPicture Task end size: %{public}d", mem->GetSize());
312             SourceOptions options;
313             uint32_t errCode;
314             std::unique_ptr<ImageSource> imageSource
315                 = ImageSource::CreateImageSource(mem->GetBase(), mem->GetSize(), options, errCode);
316             if (imageSource == nullptr) {
317                 return TaskRet(MSERR_EXT_API9_INVALID_PARAMETER,
318                     "Create image source failed.");
319             }
320 
321             DecodeOptions decodeParam;
322             std::unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(0, decodeParam, errCode);
323             if (pixelMap == nullptr) {
324                 return TaskRet(MSERR_EXT_API9_INVALID_PARAMETER,
325                     "Create pixel map failed.");
326             }
327             picture = std::move(pixelMap);
328 
329             stopWait_ = false;
330             LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "FetchArtPictureTask", false)
331 
332             if (GetCurrentState() == AVMetadataHelperState::STATE_ERROR) {
333                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
334                     "failed to FetchArtPicture, metadata helper enter error status!");
335             }
336         } else {
337             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
338                 "current state is not initialized, unsupport FetchArtPicture operation");
339         }
340 
341         MEDIA_LOGI("FetchArtPicture Task Out");
342         return TaskRet(MSERR_EXT_API9_OK, "Success");
343     });
344 
345     (void)taskQue_->EnqueueTask(task);
346     return task;
347 }
348 
JsFetchArtPicture(napi_env env,napi_callback_info info)349 napi_value AVMetadataExtractorNapi::JsFetchArtPicture(napi_env env, napi_callback_info info)
350 {
351     MediaTrace trace("AVMetadataExtractorNapi::fetchArtPicture");
352     napi_value result = nullptr;
353     napi_get_undefined(env, &result);
354     MEDIA_LOGI("JsFetchArtPicture In");
355 
356     auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
357     napi_value args[1] = { nullptr };
358     size_t argCount = 1;
359 
360     AVMetadataExtractorNapi* extractor
361         = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
362     CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
363     promiseCtx->napi = extractor;
364     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
365     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
366 
367     promiseCtx->task_ = extractor->FetchArtPictureTask(promiseCtx);
368 
369     // async work
370     napi_value resource = nullptr;
371     napi_create_string_utf8(env, "JsFetchArtPicture", NAPI_AUTO_LENGTH, &resource);
372     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
373         [](napi_env env, void *data) {
374             MEDIA_LOGI("JsFetchArtPicture task start");
375             auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
376             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
377 
378             if (promiseCtx->task_) {
379                 auto result = promiseCtx->task_->GetResult();
380                 MEDIA_LOGD("JsFetchArtPicture get result end");
381                 if (result.Value().first != MSERR_EXT_API9_OK) {
382                     MEDIA_LOGI("JsFetchArtPicture get result SignError");
383                     promiseCtx->SignError(result.Value().first, result.Value().second);
384                 }
385             }
386             MEDIA_LOGI("The js thread of resolving meta data finishes execution and returns");
387         },
388         FetchArtPictureComplete, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
389     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
390     promiseCtx.release();
391     MEDIA_LOGI("JsFetchArtPicture Out");
392     return result;
393 }
394 
FetchArtPictureComplete(napi_env env,napi_status status,void * data)395 void AVMetadataExtractorNapi::FetchArtPictureComplete(napi_env env, napi_status status, void *data)
396 {
397     napi_value result = nullptr;
398 
399     MEDIA_LOGI("FetchArtPictureComplete In");
400     auto context = static_cast<AVMetadataExtractorAsyncContext*>(data);
401 
402     if (status == napi_ok && context->errCode == napi_ok) {
403         result = Media::PixelMapNapi::CreatePixelMap(env, context->artPicture_);
404         context->status = ERR_OK;
405     } else {
406         context->status = context->errCode == napi_ok ? MSERR_INVALID_VAL : context->errCode;
407         napi_get_undefined(env, &result);
408     }
409 
410     CommonCallbackRoutine(env, context, result);
411 }
412 
CommonCallbackRoutine(napi_env env,AVMetadataExtractorAsyncContext * & asyncContext,const napi_value & valueParam)413 void AVMetadataExtractorNapi::CommonCallbackRoutine(napi_env env, AVMetadataExtractorAsyncContext* &asyncContext,
414     const napi_value &valueParam)
415 {
416     napi_value result[2] = {0};
417     napi_value retVal;
418     napi_value callback = nullptr;
419 
420     napi_get_undefined(env, &result[0]);
421     napi_get_undefined(env, &result[1]);
422 
423     napi_handle_scope scope = nullptr;
424     napi_open_handle_scope(env, &scope);
425     if (scope == nullptr) {
426         MEDIA_LOGW("scope is null");
427         return;
428     }
429 
430     if (asyncContext == nullptr) {
431         MEDIA_LOGW("asyncContext is null");
432         return;
433     }
434 
435     if (asyncContext->status == ERR_OK) {
436         result[1] = valueParam;
437         napi_create_uint32(env, asyncContext->status, &result[0]);
438     } else {
439         napi_create_uint32(env, asyncContext->status, &result[0]);
440     }
441 
442     if (asyncContext->deferred) {
443         MEDIA_LOGD("deferred in");
444         if (asyncContext->status == ERR_OK) {
445             napi_resolve_deferred(env, asyncContext->deferred, result[1]);
446         } else {
447             napi_reject_deferred(env, asyncContext->deferred, result[0]);
448         }
449     } else {
450         MEDIA_LOGD("callback in");
451         napi_get_reference_value(env, asyncContext->callbackRef, &callback);
452         napi_call_function(env, nullptr, callback, 2, result, &retVal); // 2
453         napi_delete_reference(env, asyncContext->callbackRef);
454     }
455 
456     napi_delete_async_work(env, asyncContext->work);
457     napi_close_handle_scope(env, scope);
458 
459     delete asyncContext;
460     asyncContext = nullptr;
461 }
462 
WaitTaskQueStop()463 void AVMetadataExtractorNapi::WaitTaskQueStop()
464 {
465     MEDIA_LOGI("WaitTaskQueStop In");
466     std::unique_lock<std::mutex> lock(taskMutex_);
467     LISTENER(stopTaskQueCond_.wait(lock, [this]() { return taskQueStoped_; }), "StopTaskQue", false)
468     MEDIA_LOGI("WaitTaskQueStop Out");
469 }
470 
StopTaskQue()471 void AVMetadataExtractorNapi::StopTaskQue()
472 {
473     MEDIA_LOGI("StopTaskQue In");
474     taskQue_->Stop();
475     taskQueStoped_ = true;
476     stopTaskQueCond_.notify_all();
477     MEDIA_LOGI("StopTaskQue Out");
478 }
479 
ReleaseTask()480 std::shared_ptr<TaskHandler<TaskRet>> AVMetadataExtractorNapi::ReleaseTask()
481 {
482     std::shared_ptr<TaskHandler<TaskRet>> task = nullptr;
483     if (isReleased_.load()) {
484         MEDIA_LOGE("Instance is released.");
485         return task;
486     }
487 
488     task = std::make_shared<TaskHandler<TaskRet>>([this]() {
489         MEDIA_LOGI("Release Task In");
490         PauseListenCurrentResource(); // Pause event listening for the current resource
491         ResetUserParameters();
492 
493         if (helper_ != nullptr) {
494             (void)helper_->Release();
495             helper_ = nullptr;
496         }
497 
498         if (extractorCb_ != nullptr) {
499             extractorCb_->Release();
500         }
501 
502         std::thread(&AVMetadataExtractorNapi::StopTaskQue, this).detach();
503 
504         MEDIA_LOGI("Release Task Out");
505         return TaskRet(MSERR_EXT_API9_OK, "Success");
506     });
507 
508     std::unique_lock<std::mutex> lock(taskMutex_);
509     isReleased_.store(true);
510     (void)taskQue_->EnqueueTask(task, true); // CancelNotExecutedTask
511     stopWait_ = true;
512     stateChangeCond_.notify_all();
513     return task;
514 }
515 
JsRelease(napi_env env,napi_callback_info info)516 napi_value AVMetadataExtractorNapi::JsRelease(napi_env env, napi_callback_info info)
517 {
518     MediaTrace trace("AVMetadataExtractorNapi::release");
519     napi_value result = nullptr;
520     napi_get_undefined(env, &result);
521     MEDIA_LOGI("JsRelease In");
522 
523     auto promiseCtx = std::make_unique<AVMetadataExtractorAsyncContext>(env);
524     napi_value args[1] = { nullptr };
525     size_t argCount = 1;
526     AVMetadataExtractorNapi *extractor
527         = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
528     CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
529     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
530     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
531 
532     promiseCtx->task_ = extractor->ReleaseTask();
533     if (extractor->dataSrcCb_ != nullptr) {
534         extractor->dataSrcCb_->ClearCallbackReference();
535         extractor->dataSrcCb_ = nullptr;
536     }
537 
538     napi_value resource = nullptr;
539     napi_create_string_utf8(env, "JsRelease", NAPI_AUTO_LENGTH, &resource);
540     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
541         [](napi_env env, void *data) {
542             auto promiseCtx = reinterpret_cast<AVMetadataExtractorAsyncContext *>(data);
543             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
544             if (promiseCtx->task_ == nullptr) {
545                 promiseCtx->SignError(MSERR_INVALID_VAL, "Async release task is invalid.");
546                 return;
547             }
548 
549             auto result = promiseCtx->task_->GetResult();
550             MEDIA_LOGD("Release task GetResult end.");
551             if (result.HasResult() && result.Value().first != MSERR_EXT_API9_OK) {
552                 promiseCtx->SignError(result.Value().first, result.Value().second);
553                 return;
554             }
555             MEDIA_LOGI("Release task completed.");
556         },
557         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
558     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
559     promiseCtx.release();
560     MEDIA_LOGI("JsRelease Out");
561     return result;
562 }
563 
SetSource(std::string url)564 void AVMetadataExtractorNapi::SetSource(std::string url)
565 {
566     MEDIA_LOGI("input url is %{public}s!", url.c_str());
567     bool isFd = (url.find("fd://") != std::string::npos) ? true : false;
568     bool isNetwork = (url.find("http") != std::string::npos) ? true : false;
569     if (isNetwork) {
570         auto task = std::make_shared<TaskHandler<void>>([this, url]() {
571             std::unique_lock<std::mutex> lock(taskMutex_);
572             auto state = GetCurrentState();
573             if (state != AVMetadataHelperState::STATE_IDLE) {
574                 OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set url");
575                 return;
576             }
577             if (helper_ != nullptr) {
578                 if (helper_->SetSource(url, AVMetadataUsage::AV_META_USAGE_META_ONLY) != MSERR_OK) {
579                     OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to SetSourceNetWork");
580                 }
581                 stopWait_ = false;
582                 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }),
583                     "SetSourceNetWork", false)
584             }
585         });
586         (void)taskQue_->EnqueueTask(task);
587     } else if (isFd) {
588         std::string inputFd = url.substr(sizeof("fd://") - 1);
589         int32_t fd = -1;
590         if (!StrToInt(inputFd, fd) || fd < 0) {
591             OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "The input parameter is not a fd://+numeric string");
592             return;
593         }
594         auto task = std::make_shared<TaskHandler<void>>([this, fd]() {
595             std::unique_lock<std::mutex> lock(taskMutex_);
596             auto state = GetCurrentState();
597             if (state != AVMetadataHelperState::STATE_IDLE) {
598                 OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set source fd");
599                 return;
600             }
601             if (helper_ != nullptr) {
602                 if (helper_->SetSource(fd, 0, -1, AVMetadataUsage::AV_META_USAGE_META_ONLY) != MSERR_OK) {
603                     OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "failed to SetSourceFd");
604                 }
605                 stopWait_ = false;
606                 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "SetSourceFd", false)
607             }
608         });
609         (void)taskQue_->EnqueueTask(task);
610     } else {
611         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "The input parameter is not fd:// or network address");
612     }
613 }
614 
JsSetUrl(napi_env env,napi_callback_info info)615 napi_value AVMetadataExtractorNapi::JsSetUrl(napi_env env, napi_callback_info info)
616 {
617     MediaTrace trace("AVMetadataExtractorNapi::set url");
618     napi_value result = nullptr;
619     napi_get_undefined(env, &result);
620     MEDIA_LOGI("JsSetUrl In");
621 
622     napi_value args[1] = { nullptr };
623     size_t argCount = 1; // url: string
624     AVMetadataExtractorNapi *extractor
625         = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
626     CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstanceWithParameter");
627 
628     if (extractor->GetCurrentState() != AVMetadataHelperState::STATE_IDLE) {
629         extractor->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set url");
630         return result;
631     }
632 
633     napi_valuetype valueType = napi_undefined;
634     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
635         extractor->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "url is not string");
636         return result;
637     }
638 
639     // get url from js
640     extractor->url_ = CommonNapi::GetStringArgument(env, args[0]);
641     extractor->SetSource(extractor->url_);
642 
643     MEDIA_LOGI("JsSetUrl Out");
644     return result;
645 }
646 
JsGetUrl(napi_env env,napi_callback_info info)647 napi_value AVMetadataExtractorNapi::JsGetUrl(napi_env env, napi_callback_info info)
648 {
649     MediaTrace trace("AVMetadataExtractorNapi::get url");
650     napi_value result = nullptr;
651     napi_get_undefined(env, &result);
652     MEDIA_LOGI("JsGetUrl In");
653 
654     AVMetadataExtractorNapi *extractor = AVMetadataExtractorNapi::GetJsInstance(env, info);
655     CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
656 
657     napi_value value = nullptr;
658     (void)napi_create_string_utf8(env, extractor->url_.c_str(), NAPI_AUTO_LENGTH, &value);
659 
660     MEDIA_LOGI("JsGetUrl Out Current Url: %{public}s", extractor->url_.c_str());
661     return value;
662 }
663 
SetAVFileDescriptorTask(std::shared_ptr<AVMetadataHelper> & avHelper,AVFileDescriptor & fileDescriptor)664 void AVMetadataExtractorNapi::SetAVFileDescriptorTask(std::shared_ptr<AVMetadataHelper>& avHelper,
665     AVFileDescriptor& fileDescriptor)
666 {
667     auto task = std::make_shared<TaskHandler<void>>([this, &helper_ = avHelper, &fileDescriptor_ = fileDescriptor]() {
668         MEDIA_LOGI("SetAVFileDescriptor Task");
669         std::unique_lock<std::mutex> lock(taskMutex_);
670         auto state = GetCurrentState();
671         if (state != AVMetadataHelperState::STATE_IDLE) {
672             OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set source fd");
673             return;
674         }
675 
676         if (helper_ != nullptr) {
677             if (helper_->SetSource(fileDescriptor_.fd, fileDescriptor_.offset, fileDescriptor_.length,
678                 AVMetadataUsage::AV_META_USAGE_META_ONLY) != MSERR_OK) {
679                 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "Helper SetSource FileDescriptor failed");
680             }
681             stopWait_ = false;
682             LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }),
683                 "SetSource FileDescriptor", false)
684         }
685         MEDIA_LOGI("SetSource FileDescriptor end");
686     });
687     (void)taskQue_->EnqueueTask(task);
688 }
689 
JsSetAVFileDescriptor(napi_env env,napi_callback_info info)690 napi_value AVMetadataExtractorNapi::JsSetAVFileDescriptor(napi_env env, napi_callback_info info)
691 {
692     MediaTrace trace("AVMetadataExtractorNapi::set fd");
693     napi_value result = nullptr;
694     napi_get_undefined(env, &result);
695     MEDIA_LOGI("JsSetAVFileDescriptor In");
696 
697     napi_value args[1] = { nullptr };
698     size_t argCount = 1; // url: string
699     AVMetadataExtractorNapi *extractor
700         = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
701     CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstanceWithParameter");
702 
703     if (extractor->GetCurrentState() != AVMetadataHelperState::STATE_IDLE) {
704         extractor->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set fd");
705         return result;
706     }
707 
708     extractor->StartListenCurrentResource(); // Listen to the events of the current resource
709     napi_valuetype valueType = napi_undefined;
710     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
711         extractor->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAVFileDescriptor is not napi_object");
712         return result;
713     }
714 
715     if (!CommonNapi::GetFdArgument(env, args[0], extractor->fileDescriptor_)) {
716         MEDIA_LOGE("get fileDescriptor argument failed!");
717         extractor->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
718             "invalid parameters, please check the input parameters(fileDescriptor)");
719         return result;
720     }
721     extractor->SetAVFileDescriptorTask(extractor->helper_, extractor->fileDescriptor_);
722     MEDIA_LOGI("JsSetAVFileDescriptor Out");
723     return result;
724 }
725 
JsGetAVFileDescriptor(napi_env env,napi_callback_info info)726 napi_value AVMetadataExtractorNapi::JsGetAVFileDescriptor(napi_env env, napi_callback_info info)
727 {
728     MediaTrace trace("AVMetadataExtractorNapi::get fd");
729     napi_value result = nullptr;
730     napi_get_undefined(env, &result);
731     MEDIA_LOGI("JsGetAVFileDescriptor In");
732 
733     AVMetadataExtractorNapi *extractor = AVMetadataExtractorNapi::GetJsInstance(env, info);
734     CHECK_AND_RETURN_RET_LOG(extractor != nullptr, result, "failed to GetJsInstance");
735 
736     napi_value value = nullptr;
737     (void)napi_create_object(env, &value);
738     (void)CommonNapi::AddNumberPropInt32(env, value, "fd", extractor->fileDescriptor_.fd);
739     (void)CommonNapi::AddNumberPropInt64(env, value, "offset", extractor->fileDescriptor_.offset);
740     (void)CommonNapi::AddNumberPropInt64(env, value, "length", extractor->fileDescriptor_.length);
741 
742     MEDIA_LOGI("JsGetAVFileDescriptor Out");
743     return value;
744 }
745 
SetDataSrcTask(std::shared_ptr<AVMetadataHelper> & avHelper,std::shared_ptr<HelperDataSourceCallback> & dataSrcCb)746 void AVMetadataExtractorNapi::SetDataSrcTask(std::shared_ptr<AVMetadataHelper>& avHelper,
747     std::shared_ptr<HelperDataSourceCallback>& dataSrcCb)
748 {
749     auto task = std::make_shared<TaskHandler<void>>([this, &helper_ = avHelper, &dataSrcCb_ = dataSrcCb]() {
750         MEDIA_LOGI("SetDataSrc Task");
751         std::unique_lock<std::mutex> lock(taskMutex_);
752         auto state = GetCurrentState();
753         if (state != AVMetadataHelperState::STATE_IDLE) {
754             OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set data source");
755             return;
756         }
757 
758         if (helper_ != nullptr) {
759             MEDIA_LOGI("SetDataSrc Task SetSource");
760             if (helper_->SetSource(dataSrcCb_) != MSERR_OK) {
761                 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "Meta helper SetSource DataSrc failed");
762             }
763 
764             stopWait_ = false;
765             LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "Set data source", false)
766         }
767         MEDIA_LOGI("SetDataSrc Task SetSource end");
768     });
769     (void)taskQue_->EnqueueTask(task);
770 }
771 
JsSetDataSrc(napi_env env,napi_callback_info info)772 napi_value AVMetadataExtractorNapi::JsSetDataSrc(napi_env env, napi_callback_info info)
773 {
774     MediaTrace trace("AVMetadataExtractorNapi::set dataSrc");
775     napi_value result = nullptr;
776     napi_get_undefined(env, &result);
777     MEDIA_LOGI("JsSetDataSrc In");
778 
779     napi_value args[1] = { nullptr };
780     size_t argCount = 1;
781     AVMetadataExtractorNapi *jsMetaHelper
782         = AVMetadataExtractorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
783     CHECK_AND_RETURN_RET_LOG(jsMetaHelper != nullptr, result, "failed to GetJsInstanceWithParameter");
784 
785     if (jsMetaHelper->GetCurrentState() != AVMetadataHelperState::STATE_IDLE) {
786         jsMetaHelper->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set dataSrc");
787         return result;
788     }
789     jsMetaHelper->StartListenCurrentResource(); // Listen to the events of the current resource
790 
791     napi_valuetype valueType = napi_undefined;
792     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
793         jsMetaHelper->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "args[0] is not napi_object");
794         return result;
795     }
796     (void)CommonNapi::GetPropertyInt64(env, args[0], "fileSize", jsMetaHelper->dataSrcDescriptor_.fileSize);
797     if (jsMetaHelper->dataSrcDescriptor_.fileSize < -1 || jsMetaHelper->dataSrcDescriptor_.fileSize == 0) {
798         jsMetaHelper->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
799             "invalid parameters, please check parameter fileSize");
800         return result;
801     }
802     MEDIA_LOGI("Recvive filesize is %{public}" PRId64 "", jsMetaHelper->dataSrcDescriptor_.fileSize);
803     jsMetaHelper->dataSrcCb_
804         = std::make_shared<HelperDataSourceCallback>(env, jsMetaHelper->dataSrcDescriptor_.fileSize);
805 
806     napi_value callback = nullptr;
807     napi_ref ref = nullptr;
808     napi_get_named_property(env, args[0], "callback", &callback);
809     jsMetaHelper->dataSrcDescriptor_.callback = callback;
810     napi_status status = napi_create_reference(env, callback, 1, &ref);
811     CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
812     std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
813     jsMetaHelper->dataSrcCb_->SaveCallbackReference(HELPER_READAT_CALLBACK_NAME, autoRef);
814 
815     jsMetaHelper->SetDataSrcTask(jsMetaHelper->helper_, jsMetaHelper->dataSrcCb_);
816 
817     MEDIA_LOGI("JsSetDataSrc Out");
818     return result;
819 }
820 
JsGetDataSrc(napi_env env,napi_callback_info info)821 napi_value AVMetadataExtractorNapi::JsGetDataSrc(napi_env env, napi_callback_info info)
822 {
823     MediaTrace trace("AVMetadataExtractorNapi::get dataSrc");
824     napi_value result = nullptr;
825     napi_get_undefined(env, &result);
826     MEDIA_LOGI("JsGetDataSrc In");
827 
828     AVMetadataExtractorNapi *jsMetaHelper = AVMetadataExtractorNapi::GetJsInstance(env, info);
829     CHECK_AND_RETURN_RET_LOG(jsMetaHelper != nullptr, result, "failed to GetJsInstance");
830     CHECK_AND_RETURN_RET_LOG(jsMetaHelper->dataSrcCb_ != nullptr, result, "failed to check dataSrcCb_");
831 
832     napi_value value = nullptr;
833     int64_t fileSize;
834     napi_value callback = nullptr;
835     (void)napi_create_object(env, &value);
836     (void)jsMetaHelper->dataSrcCb_->GetSize(fileSize);
837     (void)CommonNapi::AddNumberPropInt64(env, value, "fileSize", fileSize);
838     int32_t ret = jsMetaHelper->dataSrcCb_->GetCallback(HELPER_READAT_CALLBACK_NAME, &callback);
839     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, result, "failed to GetCallback");
840     (void)HelperDataSourceCallback::AddNapiValueProp(env, value, "callback", callback);
841 
842     MEDIA_LOGI("JsGetDataSrc Out");
843     return value;
844 }
845 
GetCurrentState()846 std::string AVMetadataExtractorNapi::GetCurrentState()
847 {
848     if (isReleased_.load()) {
849         return AVMetadataHelperState::STATE_RELEASED;
850     } else {
851         std::string curState = AVMetadataHelperState::STATE_ERROR;
852 
853         if (stateMap.find(state_) != stateMap.end()) {
854             curState = stateMap.at(state_);
855         }
856         return curState;
857     }
858 }
859 
SaveCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)860 void AVMetadataExtractorNapi::SaveCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
861 {
862     std::lock_guard<std::mutex> lock(mutex_);
863     refMap_[callbackName] = ref;
864     if (extractorCb_ != nullptr) {
865         extractorCb_->SaveCallbackReference(callbackName, ref);
866     }
867 }
868 
ClearCallbackReference()869 void AVMetadataExtractorNapi::ClearCallbackReference()
870 {
871     std::lock_guard<std::mutex> lock(mutex_);
872     if (extractorCb_ != nullptr) {
873         extractorCb_->ClearCallbackReference();
874     }
875     refMap_.clear();
876 }
877 
ClearCallbackReference(const std::string & callbackName)878 void AVMetadataExtractorNapi::ClearCallbackReference(const std::string &callbackName)
879 {
880     std::lock_guard<std::mutex> lock(mutex_);
881     if (extractorCb_ != nullptr) {
882         extractorCb_->ClearCallbackReference(callbackName);
883     }
884     refMap_.erase(callbackName);
885 }
886 
NotifyState(HelperStates state)887 void AVMetadataExtractorNapi::NotifyState(HelperStates state)
888 {
889     std::lock_guard<std::mutex> lock(taskMutex_);
890     state_ = state;
891     MEDIA_LOGI("notify completed, current state: %{public}s", GetCurrentState().c_str());
892     stopWait_ = true;
893     stateChangeCond_.notify_all();
894 }
895 
ResetUserParameters()896 void AVMetadataExtractorNapi::ResetUserParameters()
897 {
898     url_.clear();
899     fileDescriptor_.fd = 0;
900     fileDescriptor_.offset = 0;
901     fileDescriptor_.length = -1;
902     fileDescriptor_.length = -1;
903 }
904 
StartListenCurrentResource()905 void AVMetadataExtractorNapi::StartListenCurrentResource()
906 {
907     std::lock_guard<std::mutex> lock(mutex_);
908     if (extractorCb_ != nullptr) {
909         extractorCb_->Start();
910     }
911 }
912 
PauseListenCurrentResource()913 void AVMetadataExtractorNapi::PauseListenCurrentResource()
914 {
915     std::lock_guard<std::mutex> lock(mutex_);
916     if (extractorCb_ != nullptr) {
917         extractorCb_->Pause();
918     }
919 }
920 
OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)921 void AVMetadataExtractorNapi::OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
922 {
923     std::lock_guard<std::mutex> lock(mutex_);
924     if (extractorCb_ != nullptr) {
925         extractorCb_->OnErrorCb(errorCode, errorMsg);
926     }
927 }
928 
GetJsInstance(napi_env env,napi_callback_info info)929 AVMetadataExtractorNapi* AVMetadataExtractorNapi::GetJsInstance(napi_env env, napi_callback_info info)
930 {
931     size_t argCount = 0;
932     napi_value jsThis = nullptr;
933     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
934     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
935 
936     AVMetadataExtractorNapi *extractor = nullptr;
937     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&extractor));
938     CHECK_AND_RETURN_RET_LOG(status == napi_ok && extractor != nullptr, nullptr, "failed to napi_unwrap");
939 
940     return extractor;
941 }
942 
GetJsInstanceWithParameter(napi_env env,napi_callback_info info,size_t & argc,napi_value * argv)943 AVMetadataExtractorNapi* AVMetadataExtractorNapi::GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
944     size_t &argc, napi_value *argv)
945 {
946     napi_value jsThis = nullptr;
947     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
948     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
949 
950     AVMetadataExtractorNapi *extractor = nullptr;
951     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&extractor));
952     CHECK_AND_RETURN_RET_LOG(status == napi_ok && extractor != nullptr, nullptr, "failed to napi_unwrap");
953 
954     return extractor;
955 }
956 } // namespace Media
957 } // namespace OHOS