1 /*
2 * Copyright (c) 2021-2024 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 "frameworks/bridge/declarative_frontend/jsview/js_video.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/common/utils/engine_helper.h"
20 #include "bridge/declarative_frontend/jsview/js_utils.h"
21 #include "bridge/declarative_frontend/jsview/js_video_controller.h"
22 #include "bridge/declarative_frontend/jsview/models/video_model_impl.h"
23 #include "core/components_ng/base/view_stack_processor.h"
24 #include "core/components_ng/pattern/video/video_model_ng.h"
25 #ifdef SUPPORT_JSSTACK
26 #include "xpower_event_jsvm.h"
27 #endif
28
29 namespace OHOS::Ace {
30
31 std::unique_ptr<VideoModel> VideoModel::instance_ = nullptr;
32 std::mutex VideoModel::mutex_;
33
GetInstance()34 VideoModel* VideoModel::GetInstance()
35 {
36 if (!instance_) {
37 std::lock_guard<std::mutex> lock(mutex_);
38 if (!instance_) {
39 #ifdef NG_BUILD
40 instance_.reset(new NG::VideoModelNG());
41 #else
42 if (Container::IsCurrentUseNewPipeline()) {
43 instance_.reset(new NG::VideoModelNG());
44 } else {
45 instance_.reset(new Framework::VideoModelImpl());
46 }
47 #endif
48 }
49 }
50 return instance_.get();
51 }
52
53 } // namespace OHOS::Ace
54
55 namespace OHOS::Ace::Framework {
56
Create(const JSCallbackInfo & info)57 void JSVideo::Create(const JSCallbackInfo& info)
58 {
59 if (!info[0]->IsObject()) {
60 return;
61 }
62 JSRef<JSObject> videoObj = JSRef<JSObject>::Cast(info[0]);
63 JSRef<JSVal> srcValue = videoObj->GetProperty("src");
64 JSRef<JSVal> previewUriValue = videoObj->GetProperty("previewUri");
65 JSRef<JSVal> currentProgressRateValue = videoObj->GetProperty("currentProgressRate");
66
67 auto controllerObj = videoObj->GetProperty("controller");
68 RefPtr<VideoControllerV2> videoController = nullptr;
69 if (controllerObj->IsObject()) {
70 auto* jsVideoController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSVideoController>();
71 if (jsVideoController) {
72 jsVideoController->SetInstanceId(Container::CurrentId());
73 videoController = jsVideoController->GetController();
74 }
75 }
76 VideoModel::GetInstance()->Create(videoController);
77
78 // Parse the src, if it is invalid, use the empty string.
79 std::string bundleNameSrc;
80 std::string moduleNameSrc;
81 std::string src;
82 int32_t resId = 0;
83 ParseJsMediaWithBundleName(srcValue, src, bundleNameSrc, moduleNameSrc, resId);
84 VideoModel::GetInstance()->SetSrc(src, bundleNameSrc, moduleNameSrc);
85
86 // Parse the rate, if it is invalid, set it as 1.0.
87 double currentProgressRate = 1.0;
88 ParseJsDouble(currentProgressRateValue, currentProgressRate);
89 VideoModel::GetInstance()->SetProgressRate(currentProgressRate);
90
91 auto aiOptions = videoObj->GetProperty("imageAIOptions");
92 if (aiOptions->IsObject()) {
93 ParseImageAIOptions(aiOptions);
94 }
95
96 std::string previewUri;
97 std::string bundleName;
98 std::string moduleName;
99 GetJsMediaBundleInfo(previewUriValue, bundleName, moduleName);
100 if (previewUriValue->IsUndefined() || previewUriValue->IsNull()) {
101 // When it is undefined, just set the empty image.
102 VideoModel::GetInstance()->SetPosterSourceInfo(previewUri, "", "");
103 return;
104 }
105 auto noPixMap = ParseJsMedia(previewUriValue, previewUri);
106 if (noPixMap) {
107 // Src is a string or resource
108 VideoModel::GetInstance()->SetPosterSourceInfo(previewUri, bundleName, moduleName);
109 } else {
110 // Src is a pixelmap.
111 #if defined(PIXEL_MAP_SUPPORTED)
112 RefPtr<PixelMap> pixMap = CreatePixelMapFromNapiValue(previewUriValue);
113 VideoModel::GetInstance()->SetPosterSourceByPixelMap(pixMap);
114 #endif
115 }
116 }
117
ParseImageAIOptions(const JSRef<JSVal> & jsValue)118 void JSVideo::ParseImageAIOptions(const JSRef<JSVal>& jsValue)
119 {
120 auto engine = EngineHelper::GetCurrentEngine();
121 CHECK_NULL_VOID(engine);
122 NativeEngine* nativeEngine = engine->GetNativeEngine();
123 CHECK_NULL_VOID(nativeEngine);
124 panda::Local<JsiValue> value = jsValue.Get().GetLocalHandle();
125 JSValueWrapper valueWrapper = value;
126 ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
127 napi_value optionsValue = nativeEngine->ValueToNapiValue(valueWrapper);
128 VideoModel::GetInstance()->SetImageAIOptions(optionsValue);
129 }
130
JsMuted(const JSCallbackInfo & info)131 void JSVideo::JsMuted(const JSCallbackInfo& info)
132 {
133 bool muted = false;
134 if (info[0]->IsBoolean()) {
135 muted = info[0]->ToBoolean();
136 #ifdef SUPPORT_JSSTACK
137 HiviewDFX::ReportXPowerJsStackSysEvent(info.GetVm(), "VOLUME_CHANGE", "SRC=Video");
138 #endif
139 }
140 VideoModel::GetInstance()->SetMuted(muted);
141 }
142
JsAutoPlay(const JSCallbackInfo & info)143 void JSVideo::JsAutoPlay(const JSCallbackInfo& info)
144 {
145 bool autoPlay = false;
146 if (info[0]->IsBoolean()) {
147 autoPlay = info[0]->ToBoolean();
148 #ifdef SUPPORT_JSSTACK
149 HiviewDFX::ReportXPowerJsStackSysEvent(info.GetVm(), "STREAM_CHANGE", "SRC=Video");
150 #endif
151 }
152 VideoModel::GetInstance()->SetAutoPlay(autoPlay);
153 }
154
JsControls(const JSCallbackInfo & info)155 void JSVideo::JsControls(const JSCallbackInfo& info)
156 {
157 bool controls = true;
158 if (info[0]->IsBoolean()) {
159 controls = info[0]->ToBoolean();
160 }
161 VideoModel::GetInstance()->SetControls(controls);
162 }
163
JsLoop(const JSCallbackInfo & info)164 void JSVideo::JsLoop(const JSCallbackInfo& info)
165 {
166 bool loop = false;
167 if (info[0]->IsBoolean()) {
168 loop = info[0]->ToBoolean();
169 }
170 VideoModel::GetInstance()->SetLoop(loop);
171 }
172
JsObjectFit(const JSCallbackInfo & info)173 void JSVideo::JsObjectFit(const JSCallbackInfo& info)
174 {
175 ImageFit imageFit = ImageFit::COVER;
176 // The default value of Imagefit is FILL, but in the video the default value is COVER.
177 // So the default value need to be converted.
178 if (info[0]->IsUndefined()) {
179 VideoModel::GetInstance()->SetObjectFit(imageFit);
180 return;
181 }
182 if (info[0]->IsNumber()) {
183 imageFit = static_cast<ImageFit>(info[0]->ToNumber<int>());
184 }
185 VideoModel::GetInstance()->SetObjectFit(imageFit);
186 }
187
JsOnStart(const JSCallbackInfo & info)188 void JSVideo::JsOnStart(const JSCallbackInfo& info)
189 {
190 if (!info[0]->IsFunction()) {
191 return;
192 }
193 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
194 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
195 auto onStart = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
196 const std::string& param) {
197 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
198 ACE_SCORING_EVENT("Video.onStart");
199 PipelineContext::SetCallBackNode(node);
200 std::vector<std::string> keys = { "start" };
201 func->Execute(keys, param);
202 };
203 VideoModel::GetInstance()->SetOnStart(std::move(onStart));
204 }
205
JsOnPause(const JSCallbackInfo & info)206 void JSVideo::JsOnPause(const JSCallbackInfo& info)
207 {
208 if (!info[0]->IsFunction()) {
209 return;
210 }
211 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
212 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
213 auto onPause = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
214 const std::string& param) {
215 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
216 ACE_SCORING_EVENT("Video.onPause");
217 PipelineContext::SetCallBackNode(node);
218 std::vector<std::string> keys = { "pause" };
219 func->Execute(keys, param);
220 };
221 VideoModel::GetInstance()->SetOnPause(std::move(onPause));
222 }
223
JsOnFinish(const JSCallbackInfo & info)224 void JSVideo::JsOnFinish(const JSCallbackInfo& info)
225 {
226 if (!info[0]->IsFunction()) {
227 return;
228 }
229 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
230 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
231 auto onFinish = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
232 const std::string& param) {
233 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
234 ACE_SCORING_EVENT("Video.onFinish");
235 PipelineContext::SetCallBackNode(node);
236 std::vector<std::string> keys = { "finish" };
237 func->Execute(keys, param);
238 };
239 VideoModel::GetInstance()->SetOnFinish(std::move(onFinish));
240 }
241
JsOnStop(const JSCallbackInfo & info)242 void JSVideo::JsOnStop(const JSCallbackInfo& info)
243 {
244 if (!info[0]->IsFunction()) {
245 return;
246 }
247 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
248 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
249 auto onStop = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
250 const std::string& param) {
251 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
252 ACE_SCORING_EVENT("Video.onStop");
253 PipelineContext::SetCallBackNode(node);
254 std::vector<std::string> keys = { "stop" };
255 func->Execute(keys, param);
256 };
257 VideoModel::GetInstance()->SetOnStop(std::move(onStop));
258 }
259
JsOnFullscreenChange(const JSCallbackInfo & info)260 void JSVideo::JsOnFullscreenChange(const JSCallbackInfo& info)
261 {
262 if (!info[0]->IsFunction()) {
263 return;
264 }
265 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
266 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
267 auto OnFullScreenChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
268 const std::string& param) {
269 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
270 ACE_SCORING_EVENT("Video.OnFullScreenChange");
271 PipelineContext::SetCallBackNode(node);
272 std::vector<std::string> keys = { "fullscreen" };
273 func->Execute(keys, param);
274 };
275 VideoModel::GetInstance()->SetOnFullScreenChange(std::move(OnFullScreenChange));
276 }
277
JsOnPrepared(const JSCallbackInfo & info)278 void JSVideo::JsOnPrepared(const JSCallbackInfo& info)
279 {
280 if (!info[0]->IsFunction()) {
281 return;
282 }
283 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
284 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
285 auto onPrepared = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
286 const std::string& param) {
287 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
288 ACE_SCORING_EVENT("Video.onPrepared");
289 PipelineContext::SetCallBackNode(node);
290 std::vector<std::string> keys = { "duration" };
291 func->Execute(keys, param);
292 };
293 VideoModel::GetInstance()->SetOnPrepared(std::move(onPrepared));
294 }
295
JsOnSeeking(const JSCallbackInfo & info)296 void JSVideo::JsOnSeeking(const JSCallbackInfo& info)
297 {
298 if (!info[0]->IsFunction()) {
299 return;
300 }
301 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
302 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
303 auto onSeeking = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
304 const std::string& param) {
305 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
306 ACE_SCORING_EVENT("Video.onSeeking");
307 PipelineContext::SetCallBackNode(node);
308 std::vector<std::string> keys = { "time" };
309 func->Execute(keys, param);
310 };
311 VideoModel::GetInstance()->SetOnSeeking(std::move(onSeeking));
312 }
313
JsOnSeeked(const JSCallbackInfo & info)314 void JSVideo::JsOnSeeked(const JSCallbackInfo& info)
315 {
316 if (!info[0]->IsFunction()) {
317 return;
318 }
319 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
320 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
321 auto onSeeked = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
322 const std::string& param) {
323 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
324 ACE_SCORING_EVENT("Video.onSeeked");
325 PipelineContext::SetCallBackNode(node);
326 std::vector<std::string> keys = { "time" };
327 func->Execute(keys, param);
328 };
329 VideoModel::GetInstance()->SetOnSeeked(std::move(onSeeked));
330 }
331
JsOnUpdate(const JSCallbackInfo & info)332 void JSVideo::JsOnUpdate(const JSCallbackInfo& info)
333 {
334 if (!info[0]->IsFunction()) {
335 return;
336 }
337 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
338 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
339 auto onUpdate = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
340 const std::string& param) {
341 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
342 ACE_SCORING_EVENT("Video.onUpdate");
343 PipelineContext::SetCallBackNode(node);
344 std::vector<std::string> keys = { "time" };
345 func->Execute(keys, param);
346 };
347 VideoModel::GetInstance()->SetOnUpdate(std::move(onUpdate));
348 }
349
JsOnError(const JSCallbackInfo & info)350 void JSVideo::JsOnError(const JSCallbackInfo& info)
351 {
352 if (!info[0]->IsFunction()) {
353 return;
354 }
355 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
356 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
357 auto onError = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
358 const std::string& param) {
359 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
360 ACE_SCORING_EVENT("Video.onError");
361 PipelineContext::SetCallBackNode(node);
362 std::vector<std::string> keys = { "error" };
363 func->Execute(keys, param);
364 };
365 VideoModel::GetInstance()->SetOnError(std::move(onError));
366 }
367
GetEventMarker(const JSCallbackInfo & info,const std::vector<std::string> & keys)368 EventMarker JSVideo::GetEventMarker(const JSCallbackInfo& info, const std::vector<std::string>& keys)
369 {
370 if (!info[0]->IsFunction()) {
371 return EventMarker();
372 }
373
374 RefPtr<JsFunction> jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
375 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
376 auto eventMarker = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc), keys,
377 node = targetNode](const std::string& param) {
378 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
379 PipelineContext::SetCallBackNode(node);
380 func->Execute(keys, param);
381 });
382 return eventMarker;
383 }
384
EnableAnalyzer(bool enable)385 void JSVideo::EnableAnalyzer(bool enable)
386 {
387 VideoModel::GetInstance()->EnableAnalyzer(enable);
388 }
389
AnalyzerConfig(const JSCallbackInfo & info)390 void JSVideo::AnalyzerConfig(const JSCallbackInfo& info)
391 {
392 auto configParams = info[0];
393 if (configParams->IsNull() || !configParams->IsObject()) {
394 return;
395 }
396 auto engine = EngineHelper::GetCurrentEngine();
397 CHECK_NULL_VOID(engine);
398 NativeEngine* nativeEngine = engine->GetNativeEngine();
399 panda::Local<JsiValue> value = configParams.Get().GetLocalHandle();
400 JSValueWrapper valueWrapper = value;
401 ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
402 napi_value nativeValue = nativeEngine->ValueToNapiValue(valueWrapper);
403 VideoModel::GetInstance()->SetImageAnalyzerConfig(nativeValue);
404 }
405
JSBind(BindingTarget globalObj)406 void JSVideo::JSBind(BindingTarget globalObj)
407 {
408 JSClass<JSVideo>::Declare("Video");
409 MethodOptions opt = MethodOptions::NONE;
410 JSClass<JSVideo>::StaticMethod("create", &JSVideo::Create, opt);
411 JSClass<JSVideo>::StaticMethod("muted", &JSVideo::JsMuted, opt);
412 JSClass<JSVideo>::StaticMethod("autoPlay", &JSVideo::JsAutoPlay, opt);
413 JSClass<JSVideo>::StaticMethod("controls", &JSVideo::JsControls, opt);
414 JSClass<JSVideo>::StaticMethod("loop", &JSVideo::JsLoop, opt);
415 JSClass<JSVideo>::StaticMethod("objectFit", &JSVideo::JsObjectFit, opt);
416
417 JSClass<JSVideo>::StaticMethod("onStart", &JSVideo::JsOnStart);
418 JSClass<JSVideo>::StaticMethod("onPause", &JSVideo::JsOnPause);
419 JSClass<JSVideo>::StaticMethod("onFinish", &JSVideo::JsOnFinish);
420 JSClass<JSVideo>::StaticMethod("onFullscreenChange", &JSVideo::JsOnFullscreenChange);
421 JSClass<JSVideo>::StaticMethod("onPrepared", &JSVideo::JsOnPrepared);
422 JSClass<JSVideo>::StaticMethod("onSeeking", &JSVideo::JsOnSeeking);
423 JSClass<JSVideo>::StaticMethod("onSeeked", &JSVideo::JsOnSeeked);
424 JSClass<JSVideo>::StaticMethod("onUpdate", &JSVideo::JsOnUpdate);
425 JSClass<JSVideo>::StaticMethod("onError", &JSVideo::JsOnError);
426 JSClass<JSVideo>::StaticMethod("onStop", &JSVideo::JsOnStop);
427 JSClass<JSVideo>::StaticMethod("enableAnalyzer", &JSVideo::EnableAnalyzer);
428 JSClass<JSVideo>::StaticMethod("analyzerConfig", &JSVideo::AnalyzerConfig);
429
430 JSClass<JSVideo>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
431 JSClass<JSVideo>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
432 JSClass<JSVideo>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
433 JSClass<JSVideo>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
434 JSClass<JSVideo>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
435 JSClass<JSVideo>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
436 JSClass<JSVideo>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
437 JSClass<JSVideo>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
438 JSClass<JSVideo>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
439 JSClass<JSVideo>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
440 // override method
441 JSClass<JSVideo>::StaticMethod("opacity", &JSViewAbstract::JsOpacityPassThrough);
442 JSClass<JSVideo>::StaticMethod("transition", &JSViewAbstract::JsTransitionPassThrough);
443 JSClass<JSVideo>::InheritAndBind<JSViewAbstract>(globalObj);
444 }
445
446 } // namespace OHOS::Ace::Framework
447