• 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 "avimagegenerator_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 #if !defined(CROSS_PLATFORM)
29 #include "ipc_skeleton.h"
30 #include "tokenid_kit.h"
31 #endif
32 
33 using namespace OHOS::AudioStandard;
34 
35 namespace {
36 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_METADATA, "AVImageGeneratorNapi" };
37 constexpr uint8_t ARG_ZERO = 0;
38 constexpr uint8_t ARG_ONE = 1;
39 constexpr uint8_t ARG_TWO = 2;
40 constexpr uint8_t ARG_THREE = 3;
41 constexpr uint8_t ARG_FOUR = 4;
42 }
43 
44 namespace OHOS {
45 namespace Media {
46 thread_local napi_ref AVImageGeneratorNapi::constructor_ = nullptr;
47 const std::string CLASS_NAME = "AVImageGenerator";
48 
AVImageGeneratorNapi()49 AVImageGeneratorNapi::AVImageGeneratorNapi()
50 {
51     MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
52 }
53 
~AVImageGeneratorNapi()54 AVImageGeneratorNapi::~AVImageGeneratorNapi()
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 AVImageGeneratorNapi::Init(napi_env env, napi_value exports)
60 {
61     napi_property_descriptor staticProperty[] = {
62         DECLARE_NAPI_STATIC_FUNCTION("createAVImageGenerator", JsCreateAVImageGenerator),
63     };
64 
65     napi_property_descriptor properties[] = {
66         DECLARE_NAPI_FUNCTION("fetchFrameByTime", JsFetchFrameAtTime),
67         DECLARE_NAPI_FUNCTION("release", JsRelease),
68 
69         DECLARE_NAPI_GETTER_SETTER("fdSrc", JsGetAVFileDescriptor, JsSetAVFileDescriptor),
70     };
71 
72     napi_value constructor = nullptr;
73     CHECK_AND_RETURN_RET_LOG(sizeof(properties[0]) != 0, nullptr, "Failed to define calss");
74 
75     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
76         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
77     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AVImageGenerator class");
78 
79     status = napi_create_reference(env, constructor, 1, &constructor_);
80     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
81 
82     status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
83     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
84 
85     status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
86     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
87 
88     MEDIA_LOGD("AVImageGeneratorNapi Init success");
89     return exports;
90 }
91 
Constructor(napi_env env,napi_callback_info info)92 napi_value AVImageGeneratorNapi::Constructor(napi_env env, napi_callback_info info)
93 {
94     napi_value result = nullptr;
95     napi_get_undefined(env, &result);
96 
97     size_t argCount = 0;
98     napi_value jsThis = nullptr;
99     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
100     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
101 
102     AVImageGeneratorNapi *generator = new(std::nothrow) AVImageGeneratorNapi();
103     CHECK_AND_RETURN_RET_LOG(generator != nullptr, result, "failed to new AVImageGeneratorNapi");
104 
105     generator->env_ = env;
106     generator->helper_ = AVMetadataHelperFactory::CreateAVMetadataHelper();
107     if (generator->helper_ == nullptr) {
108         delete generator;
109         MEDIA_LOGE("failed to CreateMetadataHelper");
110         return result;
111     }
112 
113     status = napi_wrap(env, jsThis, reinterpret_cast<void *>(generator),
114         AVImageGeneratorNapi::Destructor, nullptr, nullptr);
115     if (status != napi_ok) {
116         delete generator;
117         MEDIA_LOGE("Failed to wrap native instance");
118         return result;
119     }
120 
121     MEDIA_LOGI("Constructor success");
122     return jsThis;
123 }
124 
Destructor(napi_env env,void * nativeObject,void * finalize)125 void AVImageGeneratorNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
126 {
127     MEDIA_LOGI("0x%{public}06" PRIXPTR " Destructor", FAKE_POINTER(nativeObject));
128     (void)finalize;
129     CHECK_AND_RETURN(nativeObject != nullptr);
130     AVImageGeneratorNapi *napi = reinterpret_cast<AVImageGeneratorNapi *>(nativeObject);
131     std::thread([napi]() -> void {
132         MEDIA_LOGD("Destructor Release enter");
133         if (napi != nullptr && napi->helper_ != nullptr) {
134             napi->helper_->Release();
135         }
136         delete napi;
137     }).detach();
138     MEDIA_LOGD("Destructor success");
139 }
140 
JsCreateAVImageGenerator(napi_env env,napi_callback_info info)141 napi_value AVImageGeneratorNapi::JsCreateAVImageGenerator(napi_env env, napi_callback_info info)
142 {
143     MediaTrace trace("AVImageGeneratorNapi::JsCreateAVImageGenerator");
144     napi_value result = nullptr;
145     napi_get_undefined(env, &result);
146     MEDIA_LOGI("JsCreateAVImageGenerator In");
147 
148     std::unique_ptr<MediaAsyncContext> asyncContext = std::make_unique<MediaAsyncContext>(env);
149 
150     // get args
151     napi_value jsThis = nullptr;
152     napi_value args[1] = { nullptr };
153     size_t argCount = 1;
154     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
155     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
156 
157     asyncContext->callbackRef = CommonNapi::CreateReference(env, args[0]);
158     asyncContext->deferred = CommonNapi::CreatePromise(env, asyncContext->callbackRef, result);
159     asyncContext->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
160     asyncContext->ctorFlag = true;
161 
162     auto ret = MediaAsyncContext::SendCompleteEvent(env, asyncContext.get(), napi_eprio_high);
163     if (ret != napi_status::napi_ok) {
164         MEDIA_LOGE("failed to SendEvent, ret = %{public}d", ret);
165     } else {
166         asyncContext.release();
167     }
168     MEDIA_LOGI("JsCreateAVImageGenerator Out");
169     return result;
170 }
171 
GetFetchFrameArgs(std::unique_ptr<AVImageGeneratorAsyncContext> & asyncCtx,napi_env env,napi_value timeUs,napi_value option,napi_value params)172 int32_t AVImageGeneratorNapi::GetFetchFrameArgs(std::unique_ptr<AVImageGeneratorAsyncContext> &asyncCtx, napi_env env,
173     napi_value timeUs, napi_value option, napi_value params)
174 {
175     napi_status ret = napi_get_value_int64(env, timeUs, &asyncCtx->timeUs_);
176     if (ret != napi_ok) {
177         asyncCtx->SignError(MSERR_INVALID_VAL, "failed to get timeUs");
178         return MSERR_INVALID_VAL;
179     }
180     ret = napi_get_value_int32(env, option, &asyncCtx->option_);
181     if (ret != napi_ok) {
182         asyncCtx->SignError(MSERR_INVALID_VAL, "failed to get option");
183         return MSERR_INVALID_VAL;
184     }
185 
186     int32_t width = -1;
187     if (!CommonNapi::GetPropertyInt32(env, params, "width", width)) {
188         MEDIA_LOGW("failed to get width");
189     }
190 
191     int32_t height = -1;
192     if (!CommonNapi::GetPropertyInt32(env, params, "height", height)) {
193         MEDIA_LOGW("failed to get height");
194     }
195 
196     PixelFormat colorFormat = PixelFormat::RGBA_8888;
197     int32_t formatVal = 3;
198     CommonNapi::GetPropertyInt32(env, params, "colorFormat", formatVal);
199     colorFormat = static_cast<PixelFormat>(formatVal);
200     if (colorFormat != PixelFormat::RGB_565 && colorFormat != PixelFormat::RGB_888 &&
201         colorFormat != PixelFormat::RGBA_8888) {
202         asyncCtx->SignError(MSERR_INVALID_VAL, "formatVal is invalid");
203         return MSERR_INVALID_VAL;
204     }
205 
206     asyncCtx->param_.dstWidth = width;
207     asyncCtx->param_.dstHeight = height;
208     asyncCtx->param_.colorFormat = colorFormat;
209     return MSERR_OK;
210 }
211 
JsFetchFrameAtTime(napi_env env,napi_callback_info info)212 napi_value AVImageGeneratorNapi::JsFetchFrameAtTime(napi_env env, napi_callback_info info)
213 {
214     MediaTrace trace("AVImageGeneratorNapi::JsFetchFrameAtTime");
215     MEDIA_LOGI("JsFetchFrameAtTime  in");
216     const int32_t maxArgs = ARG_FOUR;  // args + callback
217     const int32_t argCallback = ARG_THREE;  // index three, the 4th param if exist
218     const int32_t argPixelParam = ARG_TWO;  // index 2, the 3rd param
219     size_t argCount = maxArgs;
220     napi_value args[maxArgs] = { nullptr };
221     napi_value result = nullptr;
222     napi_get_undefined(env, &result);
223 
224     AVImageGeneratorNapi *napi = AVImageGeneratorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
225     CHECK_AND_RETURN_RET_LOG(napi != nullptr, result, "failed to GetJsInstance");
226 
227     auto asyncCtx = std::make_unique<AVImageGeneratorAsyncContext>(env);
228     asyncCtx->innerHelper_ = napi->helper_;
229     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[argCallback]);
230     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
231     napi_valuetype valueType = napi_undefined;
232     bool notParamValid = argCount < argCallback || napi_typeof(env, args[argPixelParam], &valueType) != napi_ok ||
233         valueType != napi_object ||
234         napi->GetFetchFrameArgs(asyncCtx, env, args[ARG_ZERO], args[ARG_ONE], args[ARG_TWO]) != MSERR_OK;
235     if (notParamValid) {
236         asyncCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "JsFetchFrameAtTime");
237     }
238 
239     if (napi->state_ != HelperState::HELPER_STATE_RUNNABLE && !asyncCtx->errFlag) {
240         asyncCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Current state is not runnable, can't fetchFrame.");
241     }
242 
243     napi_value resource = nullptr;
244     napi_create_string_utf8(env, "JsFetchFrameAtTime", NAPI_AUTO_LENGTH, &resource);
245     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
246         auto asyncCtx = reinterpret_cast<AVImageGeneratorAsyncContext *>(data);
247         CHECK_AND_RETURN_LOG(asyncCtx && !asyncCtx->errFlag && asyncCtx->innerHelper_, "Invalid context.");
248         auto pixelMap = asyncCtx->innerHelper_->
249             FetchFrameYuv(asyncCtx->timeUs_, asyncCtx->option_, asyncCtx->param_);
250         asyncCtx->pixel_ = pixelMap;
251         CHECK_AND_RETURN(asyncCtx->pixel_ == nullptr);
252         asyncCtx->SignError(MSERR_EXT_API9_UNSUPPORT_FORMAT, "FetchFrameByTime failed.");
253     }, CreatePixelMapComplete, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
254     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
255     asyncCtx.release();
256     MEDIA_LOGI("JsFetchFrameAtTime Out");
257     return result;
258 }
259 
CreatePixelMapComplete(napi_env env,napi_status status,void * data)260 void AVImageGeneratorNapi::CreatePixelMapComplete(napi_env env, napi_status status, void *data)
261 {
262     napi_value result = nullptr;
263 
264     MEDIA_LOGI("CreatePixelMapComplete In");
265     auto context = static_cast<AVImageGeneratorAsyncContext*>(data);
266 
267     if (status == napi_ok && context->errCode == napi_ok) {
268         MEDIA_LOGI("set pixel map success");
269         context->status = MSERR_OK;
270         result = Media::PixelMapNapi::CreatePixelMap(env, context->pixel_);
271     } else {
272         context->status = context->errCode == napi_ok ? MSERR_INVALID_VAL : context->errCode;
273         MEDIA_LOGW("set pixel map failed");
274         napi_get_undefined(env, &result);
275     }
276 
277     CommonCallbackRoutine(env, context, result);
278 }
279 
CommonCallbackRoutine(napi_env env,AVImageGeneratorAsyncContext * & asyncContext,const napi_value & valueParam)280 void AVImageGeneratorNapi::CommonCallbackRoutine(napi_env env, AVImageGeneratorAsyncContext* &asyncContext,
281     const napi_value &valueParam)
282 {
283     napi_value result[2] = {0};
284     napi_value retVal;
285     napi_value callback = nullptr;
286 
287     napi_get_undefined(env, &result[0]);
288     napi_get_undefined(env, &result[1]);
289 
290     napi_handle_scope scope = nullptr;
291     napi_open_handle_scope(env, &scope);
292     CHECK_AND_RETURN(scope != nullptr && asyncContext != nullptr);
293     if (asyncContext->status == ERR_OK) {
294         result[1] = valueParam;
295     }
296     napi_create_uint32(env, asyncContext->status, &result[0]);
297 
298     if (asyncContext->errFlag) {
299         (void)CommonNapi::CreateError(env, asyncContext->errCode, asyncContext->errMessage, callback);
300         result[0] = callback;
301     }
302     if (asyncContext->deferred && asyncContext->status == ERR_OK) {
303         napi_resolve_deferred(env, asyncContext->deferred, result[1]);
304     } else if (asyncContext->deferred) {
305         napi_reject_deferred(env, asyncContext->deferred, result[0]);
306     } else {
307         napi_get_reference_value(env, asyncContext->callbackRef, &callback);
308         napi_call_function(env, nullptr, callback, ARG_TWO, result, &retVal);
309         napi_delete_reference(env, asyncContext->callbackRef);
310     }
311 
312     napi_delete_async_work(env, asyncContext->work);
313     napi_close_handle_scope(env, scope);
314 
315     delete asyncContext;
316     asyncContext = nullptr;
317 }
318 
JsRelease(napi_env env,napi_callback_info info)319 napi_value AVImageGeneratorNapi::JsRelease(napi_env env, napi_callback_info info)
320 {
321     MediaTrace trace("AVImageGeneratorNapi::release");
322     napi_value result = nullptr;
323     napi_get_undefined(env, &result);
324     MEDIA_LOGI("JsRelease In");
325 
326     auto promiseCtx = std::make_unique<AVImageGeneratorAsyncContext>(env);
327     napi_value args[1] = { nullptr };
328     size_t argCount = 1;
329     AVImageGeneratorNapi *generator = AVImageGeneratorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
330     CHECK_AND_RETURN_RET_LOG(generator != nullptr, result, "failed to GetJsInstance");
331     promiseCtx->innerHelper_ = generator->helper_;
332     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
333     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
334 
335     if (generator->state_ == HelperState::HELPER_STATE_RELEASED) {
336         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Has released once, can't release again.");
337     }
338 
339     napi_value resource = nullptr;
340     napi_create_string_utf8(env, "JsRelease", NAPI_AUTO_LENGTH, &resource);
341     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
342         auto promiseCtx = reinterpret_cast<AVImageGeneratorAsyncContext *>(data);
343         CHECK_AND_RETURN_LOG(promiseCtx && promiseCtx->innerHelper_, "Invalid promiseCtx.");
344         promiseCtx->innerHelper_->Release();
345     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
346     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
347     promiseCtx.release();
348     MEDIA_LOGI("JsRelease Out");
349     return result;
350 }
351 
JsSetAVFileDescriptor(napi_env env,napi_callback_info info)352 napi_value AVImageGeneratorNapi::JsSetAVFileDescriptor(napi_env env, napi_callback_info info)
353 {
354     MediaTrace trace("AVImageGeneratorNapi::set fd");
355     napi_value result = nullptr;
356     napi_get_undefined(env, &result);
357     MEDIA_LOGI("JsSetAVFileDescriptor In");
358 
359     napi_value args[1] = { nullptr };
360     size_t argCount = 1; // url: string
361     AVImageGeneratorNapi *generator = AVImageGeneratorNapi::GetJsInstanceWithParameter(env, info, argCount, args);
362     CHECK_AND_RETURN_RET_LOG(generator != nullptr, result, "failed to GetJsInstanceWithParameter");
363 
364     CHECK_AND_RETURN_RET_LOG(
365         generator->state_ == HelperState::HELPER_STATE_IDLE, result, "Has set source once, unsupport set again");
366 
367     napi_valuetype valueType = napi_undefined;
368     bool notValidParam = argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object ||
369         !CommonNapi::GetFdArgument(env, args[0], generator->fileDescriptor_);
370     CHECK_AND_RETURN_RET_LOG(!notValidParam, result, "Invalid file descriptor, return");
371     CHECK_AND_RETURN_RET_LOG(generator->helper_, result, "Invalid AVImageGeneratorNapi.");
372 
373     auto fileDescriptor = generator->fileDescriptor_;
374     auto res = generator->helper_->SetSource(fileDescriptor.fd, fileDescriptor.offset, fileDescriptor.length);
375     generator->state_ = res == MSERR_OK ? HelperState::HELPER_STATE_RUNNABLE : HelperState::HELPER_ERROR;
376     return result;
377 }
378 
JsGetAVFileDescriptor(napi_env env,napi_callback_info info)379 napi_value AVImageGeneratorNapi::JsGetAVFileDescriptor(napi_env env, napi_callback_info info)
380 {
381     MediaTrace trace("AVImageGeneratorNapi::get fd");
382     napi_value result = nullptr;
383     napi_get_undefined(env, &result);
384     MEDIA_LOGI("JsGetAVFileDescriptor In");
385 
386     AVImageGeneratorNapi *generator = AVImageGeneratorNapi::GetJsInstance(env, info);
387     CHECK_AND_RETURN_RET_LOG(generator != nullptr, result, "failed to GetJsInstance");
388 
389     napi_value value = nullptr;
390     (void)napi_create_object(env, &value);
391     (void)CommonNapi::AddNumberPropInt32(env, value, "fd", generator->fileDescriptor_.fd);
392     (void)CommonNapi::AddNumberPropInt64(env, value, "offset", generator->fileDescriptor_.offset);
393     (void)CommonNapi::AddNumberPropInt64(env, value, "length", generator->fileDescriptor_.length);
394 
395     MEDIA_LOGI("JsGetAVFileDescriptor Out");
396     return value;
397 }
398 
GetJsInstance(napi_env env,napi_callback_info info)399 AVImageGeneratorNapi* AVImageGeneratorNapi::GetJsInstance(napi_env env, napi_callback_info info)
400 {
401     size_t argCount = 0;
402     napi_value jsThis = nullptr;
403     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
404     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
405 
406     AVImageGeneratorNapi *generator = nullptr;
407     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&generator));
408     CHECK_AND_RETURN_RET_LOG(status == napi_ok && generator != nullptr, nullptr, "failed to napi_unwrap");
409 
410     return generator;
411 }
412 
GetJsInstanceWithParameter(napi_env env,napi_callback_info info,size_t & argc,napi_value * argv)413 AVImageGeneratorNapi* AVImageGeneratorNapi::GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
414     size_t &argc, napi_value *argv)
415 {
416     napi_value jsThis = nullptr;
417     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
418     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
419 
420     AVImageGeneratorNapi *generator = nullptr;
421     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&generator));
422     CHECK_AND_RETURN_RET_LOG(status == napi_ok && generator != nullptr, nullptr, "failed to napi_unwrap");
423 
424     return generator;
425 }
426 } // namespace Media
427 } // namespace OHOS