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