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