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