1 /*
2 * Copyright (c) 2022-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 "core/components_ng/pattern/video/video_pattern.h"
17
18 #include "video_node.h"
19
20 #include "base/background_task_helper/background_task_helper.h"
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/i18n/localization.h"
24 #include "base/json/json_util.h"
25 #include "base/thread/task_executor.h"
26 #include "base/utils/string_utils.h"
27 #include "base/utils/system_properties.h"
28 #include "base/utils/utils.h"
29 #include "core/common/ace_engine.h"
30 #include "core/common/ace_view.h"
31 #include "core/common/ai/image_analyzer_manager.h"
32 #include "core/common/container.h"
33 #include "core/common/udmf/udmf_client.h"
34 #include "core/components/common/layout/constants.h"
35 #include "core/components/common/properties/color.h"
36 #include "core/components/declaration/button/button_declaration.h"
37 #include "core/components/video/video_theme.h"
38 #include "core/components/video/video_utils.h"
39 #include "core/components_ng/pattern/button/button_event_hub.h"
40 #include "core/components_ng/pattern/button/button_layout_property.h"
41 #include "core/components_ng/pattern/button/button_pattern.h"
42 #include "core/components_ng/pattern/image/image_layout_property.h"
43 #include "core/components_ng/pattern/image/image_pattern.h"
44 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
45 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
46 #include "core/components_ng/pattern/slider/slider_event_hub.h"
47 #include "core/components_ng/pattern/slider/slider_layout_property.h"
48 #include "core/components_ng/pattern/slider/slider_paint_property.h"
49 #include "core/components_ng/pattern/slider/slider_pattern.h"
50 #include "core/components_ng/pattern/text/text_layout_property.h"
51 #include "core/components_ng/pattern/text/text_pattern.h"
52 #include "core/components_ng/pattern/video/video_event_hub.h"
53 #include "core/components_ng/pattern/video/video_full_screen_node.h"
54 #include "core/components_ng/pattern/video/video_full_screen_pattern.h"
55 #include "core/components_ng/pattern/video/video_layout_property.h"
56 #include "core/components_ng/pattern/video/video_node.h"
57 #include "core/components_ng/property/gradient_property.h"
58 #include "core/components_ng/property/property.h"
59 #include "core/components_v2/inspector/inspector_constants.h"
60 #include "core/pipeline_ng/pipeline_context.h"
61 namespace OHOS::Ace::NG {
62 namespace {
63 using HiddenChangeEvent = std::function<void(bool)>;
64 constexpr uint32_t SECONDS_PER_HOUR = 3600;
65 constexpr uint32_t SECONDS_PER_MINUTE = 60;
66 const std::string FORMAT_HH_MM_SS = "%02d:%02d:%02d";
67 const std::string FORMAT_MM_SS = "%02d:%02d";
68 constexpr int32_t MILLISECONDS_TO_SECONDS = 1000;
69 constexpr uint32_t CURRENT_POS = 1;
70 constexpr uint32_t SLIDER_POS = 2;
71 constexpr uint32_t DURATION_POS = 3;
72 constexpr uint32_t FULL_SCREEN_POS = 4;
73 constexpr int32_t AVERAGE_VALUE = 2;
74 constexpr int32_t ANALYZER_DELAY_TIME = 100;
75 constexpr int32_t ANALYZER_CAPTURE_DELAY_TIME = 1000;
76 const Dimension LIFT_HEIGHT = 28.0_vp;
77 const std::string PNG_FILE_EXTENSION = "png";
78 constexpr int32_t MEDIA_TYPE_AUD = 0;
79
80 // Default error, empty string.
81 const std::string ERROR = "";
82
83 enum SliderChangeMode {
84 BEGIN = 0,
85 MOVING,
86 END,
87 };
88
IntTimeToText(uint32_t time)89 std::string IntTimeToText(uint32_t time)
90 {
91 auto minutes = (time % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE;
92 auto seconds = time % SECONDS_PER_MINUTE;
93 if (time >= SECONDS_PER_HOUR) {
94 auto hours = time / SECONDS_PER_HOUR;
95 return StringUtils::FormatString(FORMAT_HH_MM_SS.c_str(), hours, minutes, seconds);
96 }
97 return StringUtils::FormatString(FORMAT_MM_SS.c_str(), minutes, seconds);
98 }
99
CalculateFitContain(const SizeF & videoSize,const SizeF & layoutSize)100 SizeF CalculateFitContain(const SizeF& videoSize, const SizeF& layoutSize)
101 {
102 double layoutRatio = NearZero(layoutSize.Height()) ? 0.0 : layoutSize.Width() / layoutSize.Height();
103 double sourceRatio = NearZero(videoSize.Height()) ? layoutRatio : videoSize.Width() / videoSize.Height();
104
105 if (NearZero(layoutRatio) || NearZero(sourceRatio)) {
106 return layoutSize;
107 }
108 if (sourceRatio < layoutRatio) {
109 return { static_cast<float>(sourceRatio) * layoutSize.Height(), layoutSize.Height() };
110 }
111 return { layoutSize.Width(), static_cast<float>(layoutSize.Width() / sourceRatio) };
112 }
113
CalculateFitFill(const SizeF & layoutSize)114 SizeF CalculateFitFill(const SizeF& layoutSize)
115 {
116 return layoutSize;
117 }
118
CalculateFitCover(const SizeF & videoSize,const SizeF & layoutSize)119 SizeF CalculateFitCover(const SizeF& videoSize, const SizeF& layoutSize)
120 {
121 double layoutRatio = NearZero(layoutSize.Height()) ? 0.0 : layoutSize.Width() / layoutSize.Height();
122 double sourceRatio = NearZero(videoSize.Height()) ? layoutRatio : videoSize.Width() / videoSize.Height();
123
124 if (NearZero(layoutRatio) || NearZero(sourceRatio)) {
125 return layoutSize;
126 }
127 if (sourceRatio < layoutRatio) {
128 return { layoutSize.Width(), static_cast<float>(layoutSize.Width() / sourceRatio) };
129 }
130 return { static_cast<float>(layoutSize.Height() * sourceRatio), layoutSize.Height() };
131 }
132
CalculateFitNone(const SizeF & videoSize)133 SizeF CalculateFitNone(const SizeF& videoSize)
134 {
135 return videoSize;
136 }
137
CalculateFitScaleDown(const SizeF & videoSize,const SizeF & layoutSize)138 SizeF CalculateFitScaleDown(const SizeF& videoSize, const SizeF& layoutSize)
139 {
140 if (layoutSize.Width() > videoSize.Width()) {
141 return CalculateFitNone(videoSize);
142 }
143 return CalculateFitContain(videoSize, layoutSize);
144 }
145
MeasureVideoContentLayout(const SizeF & layoutSize,const RefPtr<VideoLayoutProperty> & layoutProperty)146 SizeF MeasureVideoContentLayout(const SizeF& layoutSize, const RefPtr<VideoLayoutProperty>& layoutProperty)
147 {
148 if (!layoutProperty || !layoutProperty->HasVideoSize()) {
149 return layoutSize;
150 }
151
152 auto videoSize = layoutProperty->GetVideoSizeValue(SizeF(0, 0));
153 auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
154 SizeF contentSize = { 0.0, 0.0 };
155 switch (imageFit) {
156 case ImageFit::CONTAIN:
157 contentSize = CalculateFitContain(videoSize, layoutSize);
158 break;
159 case ImageFit::FILL:
160 contentSize = CalculateFitFill(layoutSize);
161 break;
162 case ImageFit::COVER:
163 contentSize = CalculateFitCover(videoSize, layoutSize);
164 break;
165 case ImageFit::NONE:
166 contentSize = CalculateFitNone(videoSize);
167 break;
168 case ImageFit::SCALE_DOWN:
169 contentSize = CalculateFitScaleDown(videoSize, layoutSize);
170 break;
171 default:
172 contentSize = CalculateFitContain(videoSize, layoutSize);
173 }
174
175 // Just return contentSize as the video frame area.
176 return contentSize;
177 }
178
RoundValueToPixelGrid(float value,bool isRound,bool forceCeil,bool forceFloor)179 float RoundValueToPixelGrid(float value, bool isRound, bool forceCeil, bool forceFloor)
180 {
181 float fractials = fmod(value, 1.0f);
182 if (fractials < 0.0f) {
183 ++fractials;
184 }
185 if (forceCeil) {
186 return (value - fractials + 1.0f);
187 } else if (forceFloor) {
188 return (value - fractials);
189 } else if (isRound) {
190 if (NearEqual(fractials, 1.0f) || GreatOrEqual(fractials, 0.50f)) {
191 return (value - fractials + 1.0f);
192 } else {
193 return (value - fractials);
194 }
195 }
196 return value;
197 }
198
AdjustPaintRect(float positionX,float positionY,float width,float height,bool isRound)199 RectF AdjustPaintRect(float positionX, float positionY, float width, float height, bool isRound)
200 {
201 RectF rect;
202 float relativeLeft = positionX;
203 float relativeTop = positionY;
204 float nodeWidth = width;
205 float nodeHeight = height;
206 float absoluteRight = relativeLeft + nodeWidth;
207 float absoluteBottom = relativeTop + nodeHeight;
208 float roundToPixelErrorX = 0.0f;
209 float roundToPixelErrorY = 0.0f;
210
211 float nodeLeftI = RoundValueToPixelGrid(relativeLeft, isRound, false, false);
212 float nodeTopI = RoundValueToPixelGrid(relativeTop, isRound, false, false);
213 roundToPixelErrorX += nodeLeftI - relativeLeft;
214 roundToPixelErrorY += nodeTopI - relativeTop;
215 rect.SetLeft(nodeLeftI);
216 rect.SetTop(nodeTopI);
217
218 float nodeWidthI = RoundValueToPixelGrid(absoluteRight, isRound, false, false) - nodeLeftI;
219 float nodeWidthTemp = RoundValueToPixelGrid(nodeWidth, isRound, false, false);
220 roundToPixelErrorX += nodeWidthI - nodeWidth;
221 if (roundToPixelErrorX > 0.5f) {
222 nodeWidthI -= 1.0f;
223 roundToPixelErrorX -= 1.0f;
224 }
225 if (roundToPixelErrorX < -0.5f) {
226 nodeWidthI += 1.0f;
227 roundToPixelErrorX += 1.0f;
228 }
229 if (nodeWidthI < nodeWidthTemp) {
230 roundToPixelErrorX += nodeWidthTemp - nodeWidthI;
231 nodeWidthI = nodeWidthTemp;
232 }
233
234 float nodeHeightI = RoundValueToPixelGrid(absoluteBottom, isRound, false, false) - nodeTopI;
235 float nodeHeightTemp = RoundValueToPixelGrid(nodeHeight, isRound, false, false);
236 roundToPixelErrorY += nodeHeightI - nodeHeight;
237 if (roundToPixelErrorY > 0.5f) {
238 nodeHeightI -= 1.0f;
239 roundToPixelErrorY -= 1.0f;
240 }
241 if (roundToPixelErrorY < -0.5f) {
242 nodeHeightI += 1.0f;
243 roundToPixelErrorY += 1.0f;
244 }
245 if (nodeHeightI < nodeHeightTemp) {
246 roundToPixelErrorY += nodeHeightTemp - nodeHeightI;
247 nodeHeightI = nodeHeightTemp;
248 }
249
250 rect.SetWidth(nodeWidthI);
251 rect.SetHeight(nodeHeightI);
252 return rect;
253 }
ConvertToGradient(Color color)254 Gradient ConvertToGradient(Color color)
255 {
256 Gradient gradient;
257 GradientColor gradientColorBegin;
258 gradientColorBegin.SetLinearColor(LinearColor(color));
259 gradientColorBegin.SetDimension(Dimension(0.0f));
260 gradient.AddColor(gradientColorBegin);
261 OHOS::Ace::NG::GradientColor gradientColorEnd;
262 gradientColorEnd.SetLinearColor(LinearColor(color));
263 gradientColorEnd.SetDimension(Dimension(1.0f));
264 gradient.AddColor(gradientColorEnd);
265
266 return gradient;
267 }
268 } // namespace
269
VideoPattern(const RefPtr<VideoControllerV2> & videoController)270 VideoPattern::VideoPattern(const RefPtr<VideoControllerV2>& videoController)
271 : instanceId_(Container::CurrentId()), videoControllerV2_(videoController)
272 {}
273
ResetStatus()274 void VideoPattern::ResetStatus()
275 {
276 isInitialState_ = true;
277 isPlaying_ = false;
278 #ifndef OHOS_PLATFORM
279 isStop_ = false;
280 #endif
281 }
282
ResetMediaPlayer()283 void VideoPattern::ResetMediaPlayer()
284 {
285 CHECK_NULL_VOID(mediaPlayer_);
286 mediaPlayer_->ResetMediaPlayer();
287 if (!SetSourceForMediaPlayer()) {
288 TAG_LOGW(AceLogTag::ACE_VIDEO, "Video set source for mediaPlayer failed.");
289
290 // It need post on ui thread.
291 FireError();
292 return;
293 }
294
295 RegisterMediaPlayerEvent();
296 PrepareSurface();
297 if (mediaPlayer_ && mediaPlayer_->PrepareAsync() != 0) {
298 TAG_LOGE(AceLogTag::ACE_VIDEO, "Player prepare failed");
299 }
300 }
301
UpdateMediaPlayerOnBg()302 void VideoPattern::UpdateMediaPlayerOnBg()
303 {
304 PrepareMediaPlayer();
305 UpdateSpeed();
306 UpdateLooping();
307 UpdateMuted();
308 if (isInitialState_ && autoPlay_) {
309 // When video is autoPlay, start playing the video when it is initial state.
310 Start();
311 }
312 }
313
PrepareMediaPlayer()314 void VideoPattern::PrepareMediaPlayer()
315 {
316 auto videoLayoutProperty = GetLayoutProperty<VideoLayoutProperty>();
317 CHECK_NULL_VOID(videoLayoutProperty);
318 // src has not set/changed
319 if (!videoLayoutProperty->HasVideoSource() || videoLayoutProperty->GetVideoSource() == videoSrcInfo_) {
320 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video source is null or the source has not changed.");
321 return;
322 }
323 auto videoSrcInfo = videoLayoutProperty->GetVideoSourceValue(VideoSourceInfo());
324 videoSrcInfo_.src = videoSrcInfo.GetSrc();
325 videoSrcInfo_.bundleName = videoSrcInfo.GetBundleName();
326 videoSrcInfo_.moduleName = videoSrcInfo.GetModuleName();
327 if (mediaPlayer_ && !mediaPlayer_->IsMediaPlayerValid()) {
328 mediaPlayer_->CreateMediaPlayer();
329 }
330
331 if (mediaPlayer_ && !mediaPlayer_->IsMediaPlayerValid()) {
332 // It need post on ui thread.
333 FireError();
334 return;
335 }
336
337 ResetStatus();
338 ContainerScope scope(instanceId_);
339 auto host = GetHost();
340 CHECK_NULL_VOID(host);
341 auto context = host->GetContext();
342 CHECK_NULL_VOID(context);
343 auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
344 platformTask.PostTask([weak = WeakClaim(this)] {
345 auto video = weak.Upgrade();
346 CHECK_NULL_VOID(video);
347 auto targetPattern = video->GetTargetVideoPattern();
348 CHECK_NULL_VOID(targetPattern);
349 targetPattern->ResetMediaPlayer();
350 }, "ArkUIVideoMediaPlayerReset");
351 }
352
SetSourceForMediaPlayer()353 bool VideoPattern::SetSourceForMediaPlayer()
354 {
355 CHECK_NULL_RETURN(mediaPlayer_, false);
356 return mediaPlayer_->SetSource(videoSrcInfo_.GetSrc(), videoSrcInfo_.GetBundleName(),
357 videoSrcInfo_.GetModuleName());
358 }
359
RegisterMediaPlayerEvent()360 void VideoPattern::RegisterMediaPlayerEvent()
361 {
362 if (videoSrcInfo_.GetSrc().empty() || !mediaPlayer_) {
363 TAG_LOGW(AceLogTag::ACE_VIDEO, "Video src is empty or mediaPlayer is null, register mediaPlayerEvent fail");
364 return;
365 }
366 ContainerScope scope(instanceId_);
367 auto context = PipelineContext::GetCurrentContext();
368 CHECK_NULL_VOID(context);
369
370 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
371 auto videoPattern = WeakClaim(this);
372
373 auto&& positionUpdatedEvent = [videoPattern, uiTaskExecutor](uint32_t currentPos) {
374 uiTaskExecutor.PostSyncTask([&videoPattern, currentPos] {
375 auto video = videoPattern.Upgrade();
376 CHECK_NULL_VOID(video);
377 ContainerScope scope(video->instanceId_);
378 video->OnCurrentTimeChange(currentPos);
379 video->StartUpdateImageAnalyzer();
380 }, "ArkUIVideoCurrentTimeChange");
381 };
382
383 auto&& stateChangedEvent = [videoPattern, uiTaskExecutor](PlaybackStatus status) {
384 uiTaskExecutor.PostTask([videoPattern, status] {
385 auto video = videoPattern.Upgrade();
386 CHECK_NULL_VOID(video);
387 ContainerScope scope(video->instanceId_);
388 video->OnPlayerStatus(status);
389 }, "ArkUIVideoPlayerStatusChange");
390 };
391
392 auto&& errorEvent = [videoPattern, uiTaskExecutor]() {
393 uiTaskExecutor.PostTask([videoPattern] {
394 auto video = videoPattern.Upgrade();
395 CHECK_NULL_VOID(video);
396 ContainerScope scope(video->instanceId_);
397 video->OnError("");
398 }, "ArkUIVideoError");
399 };
400
401 auto&& resolutionChangeEvent = [videoPattern, uiTaskExecutor]() {
402 uiTaskExecutor.PostSyncTask([&videoPattern] {
403 auto video = videoPattern.Upgrade();
404 CHECK_NULL_VOID(video);
405 ContainerScope scope(video->instanceId_);
406 video->OnResolutionChange();
407 }, "ArkUIVideoResolutionChange");
408 };
409
410 auto&& startRenderFrameEvent = [videoPattern, uiTaskExecutor]() {
411 uiTaskExecutor.PostSyncTask([&videoPattern] {
412 auto video = videoPattern.Upgrade();
413 CHECK_NULL_VOID(video);
414 ContainerScope scope(video->instanceId_);
415 video->OnStartRenderFrameCb();
416 }, "ArkUIVideoStartRenderFrame");
417 };
418
419 mediaPlayer_->RegisterMediaPlayerEvent(
420 positionUpdatedEvent, stateChangedEvent, errorEvent, resolutionChangeEvent, startRenderFrameEvent);
421
422 auto&& seekDoneEvent = [videoPattern, uiTaskExecutor](uint32_t currentPos) {
423 uiTaskExecutor.PostSyncTask(
424 [&videoPattern, currentPos] {
425 auto video = videoPattern.Upgrade();
426 CHECK_NULL_VOID(video);
427 ContainerScope scope(video->instanceId_);
428 video->SetIsSeeking(false);
429 video->OnCurrentTimeChange(currentPos);
430 }, "ArkUIVideoSeekDone");
431 };
432 mediaPlayer_->RegisterMediaPlayerSeekDoneEvent(std::move(seekDoneEvent));
433
434 #ifdef RENDER_EXTRACT_SUPPORTED
435 auto&& textureRefreshEvent = [videoPattern, uiTaskExecutor](int32_t instanceId, int64_t textureId) {
436 uiTaskExecutor.PostSyncTask([&videoPattern, instanceId, textureId] {
437 auto video = videoPattern.Upgrade();
438 CHECK_NULL_VOID(video);
439 void* nativeWindow = video->GetNativeWindow(instanceId, textureId);
440 if (!nativeWindow) {
441 LOGE("the native window is nullptr.");
442 return;
443 }
444 video->OnTextureRefresh(nativeWindow);
445 }, "ArkUIVideoTextureRefresh");
446 };
447 mediaPlayer_->RegisterTextureEvent(textureRefreshEvent);
448 #endif
449 }
450
451 #ifdef RENDER_EXTRACT_SUPPORTED
GetNativeWindow(int32_t instanceId,int64_t textureId)452 void* VideoPattern::GetNativeWindow(int32_t instanceId, int64_t textureId)
453 {
454 auto container = AceEngine::Get().GetContainer(instanceId);
455 CHECK_NULL_RETURN(container, nullptr);
456 auto nativeView = container->GetAceView();
457 CHECK_NULL_RETURN(nativeView, nullptr);
458 return const_cast<void*>(nativeView->GetNativeWindowById(textureId));
459 }
460
OnTextureRefresh(void * surface)461 void VideoPattern::OnTextureRefresh(void* surface)
462 {
463 CHECK_NULL_VOID(surface);
464 auto renderContextForMediaPlayer = renderContextForMediaPlayerWeakPtr_.Upgrade();
465 CHECK_NULL_VOID(renderContextForMediaPlayer);
466 renderContextForMediaPlayer->MarkNewFrameAvailable(surface);
467 }
468 #endif
469
PrintPlayerStatus(PlaybackStatus status)470 void VideoPattern::PrintPlayerStatus(PlaybackStatus status)
471 {
472 switch (status) {
473 case PlaybackStatus::ERROR:
474 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is ERROR.");
475 break;
476 case PlaybackStatus::IDLE:
477 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is IDLE.");
478 break;
479 case PlaybackStatus::PREPARED:
480 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is PREPARED.");
481 break;
482 case PlaybackStatus::STARTED:
483 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is STARTED.");
484 break;
485 case PlaybackStatus::PAUSED:
486 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is PAUSED.");
487 break;
488 case PlaybackStatus::STOPPED:
489 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is STOPPED.");
490 break;
491 case PlaybackStatus::PLAYBACK_COMPLETE:
492 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is PLAYBACK_COMPLETE.");
493 break;
494 case PlaybackStatus::NONE:
495 TAG_LOGI(AceLogTag::ACE_VIDEO, "Player current status is NONE.");
496 break;
497 default:
498 TAG_LOGW(AceLogTag::ACE_VIDEO, "Invalid player status.");
499 break;
500 }
501 }
502
OnCurrentTimeChange(uint32_t currentPos)503 void VideoPattern::OnCurrentTimeChange(uint32_t currentPos)
504 {
505 isInitialState_ = isInitialState_ ? currentPos == 0 : false;
506 if (currentPos == currentPos_ || isStop_) {
507 return;
508 }
509
510 if (duration_ == 0) {
511 int32_t duration = 0;
512 if (mediaPlayer_ && mediaPlayer_->GetDuration(duration) == 0) {
513 duration_ = static_cast<uint32_t>(duration / MILLISECONDS_TO_SECONDS);
514 OnUpdateTime(duration_, DURATION_POS);
515 }
516 }
517
518 OnUpdateTime(currentPos, CURRENT_POS);
519 currentPos_ = currentPos;
520 auto eventHub = GetEventHub<VideoEventHub>();
521 CHECK_NULL_VOID(eventHub);
522 auto json = JsonUtil::Create(true);
523 json->Put("time", static_cast<double>(currentPos));
524 auto param = json->ToString();
525 eventHub->FireUpdateEvent(param);
526 }
527
ChangePlayerStatus(bool isPlaying,const PlaybackStatus & status)528 void VideoPattern::ChangePlayerStatus(bool isPlaying, const PlaybackStatus& status)
529 {
530 if (isPlaying) {
531 auto json = JsonUtil::Create(true);
532 json->Put("start", "");
533 auto param = json->ToString();
534 auto eventHub = GetEventHub<VideoEventHub>();
535 CHECK_NULL_VOID(eventHub);
536 eventHub->FireStartEvent(param);
537 }
538
539 if (status == PlaybackStatus::PAUSED) {
540 auto json = JsonUtil::Create(true);
541 json->Put("pause", "");
542 auto param = json->ToString();
543 auto eventHub = GetEventHub<VideoEventHub>();
544 CHECK_NULL_VOID(eventHub);
545 eventHub->FirePauseEvent(param);
546 }
547
548 if (status == PlaybackStatus::STOPPED) {
549 auto json = JsonUtil::Create(true);
550 json->Put("stop", "");
551 auto param = json->ToString();
552 auto eventHub = GetEventHub<VideoEventHub>();
553 CHECK_NULL_VOID(eventHub);
554 eventHub->FireStopEvent(param);
555 }
556
557 if (status == PlaybackStatus::PREPARED) {
558 ContainerScope scope(instanceId_);
559 auto host = GetHost();
560 CHECK_NULL_VOID(host);
561 auto context = host->GetContext();
562 CHECK_NULL_VOID(context);
563 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
564 return;
565 }
566 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
567 int32_t milliSecondDuration = 0;
568 mediaPlayer_->GetDuration(milliSecondDuration);
569 OnPrepared(milliSecondDuration / MILLISECONDS_TO_SECONDS, 0, true);
570 return;
571 }
572
573 if (status == PlaybackStatus::PLAYBACK_COMPLETE) {
574 OnCompletion();
575 }
576 }
577
OnPlayerStatus(PlaybackStatus status)578 void VideoPattern::OnPlayerStatus(PlaybackStatus status)
579 {
580 PrintPlayerStatus(status);
581 bool isPlaying = (status == PlaybackStatus::STARTED);
582 if (isPlaying_ != isPlaying) {
583 isPlaying_ = isPlaying;
584 ChangePlayButtonTag();
585 }
586
587 if (isInitialState_) {
588 isInitialState_ = !isPlaying;
589 }
590
591 ChangePlayerStatus(isPlaying, status);
592 }
593
OnError(const std::string & errorId)594 void VideoPattern::OnError(const std::string& errorId)
595 {
596 std::string errorcode = Localization::GetInstance()->GetErrorDescription(errorId);
597 auto json = JsonUtil::Create(true);
598 json->Put("error", "");
599 auto param = json->ToString();
600 auto eventHub = GetEventHub<VideoEventHub>();
601 CHECK_NULL_VOID(eventHub);
602 eventHub->FireErrorEvent(param);
603 }
604
OnResolutionChange() const605 void VideoPattern::OnResolutionChange() const
606 {
607 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
608 return;
609 }
610 auto host = GetHost();
611 CHECK_NULL_VOID(host);
612 auto videoLayoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
613 CHECK_NULL_VOID(videoLayoutProperty);
614 auto preVideoSize = videoLayoutProperty->GetVideoSize();
615 if (!preVideoSize.has_value()) {
616 SizeF videoSize = SizeF(
617 static_cast<float>(mediaPlayer_->GetVideoWidth()),
618 static_cast<float>(mediaPlayer_->GetVideoHeight()));
619 videoLayoutProperty->UpdateVideoSize(videoSize);
620 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
621 }
622 }
623
OnStartRenderFrameCb() const624 void VideoPattern::OnStartRenderFrameCb() const
625 {
626 auto host = GetHost();
627 CHECK_NULL_VOID(host);
628 auto video = AceType::DynamicCast<VideoNode>(host);
629 CHECK_NULL_VOID(video);
630 auto image = AceType::DynamicCast<FrameNode>(video->GetPreviewImage());
631 CHECK_NULL_VOID(image);
632 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
633 posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
634 image->MarkModifyDone();
635 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
636 return;
637 }
638 auto videoLayoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
639 CHECK_NULL_VOID(videoLayoutProperty);
640 SizeF videoSize =
641 SizeF(static_cast<float>(mediaPlayer_->GetVideoWidth()), static_cast<float>(mediaPlayer_->GetVideoHeight()));
642 TAG_LOGI(AceLogTag::ACE_VIDEO, "start render frame size:%{public}s", videoSize.ToString().c_str());
643 videoLayoutProperty->UpdateVideoSize(videoSize);
644 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
645 }
646
OnPrepared(uint32_t duration,uint32_t currentPos,bool needFireEvent)647 void VideoPattern::OnPrepared(uint32_t duration, uint32_t currentPos, bool needFireEvent)
648 {
649 auto host = GetHost();
650 CHECK_NULL_VOID(host);
651 CHECK_NULL_VOID(mediaPlayer_);
652
653 duration_ = duration;
654 currentPos_ = currentPos;
655 isInitialState_ = currentPos != 0 ? false : isInitialState_;
656 isPlaying_ = mediaPlayer_->IsPlaying();
657 OnUpdateTime(duration_, DURATION_POS);
658 OnUpdateTime(currentPos_, CURRENT_POS);
659
660 RefPtr<UINode> controlBar = nullptr;
661 auto children = host->GetChildren();
662 for (const auto& child : children) {
663 if (child->GetTag() == V2::ROW_ETS_TAG) {
664 controlBar = child;
665 break;
666 }
667 }
668 CHECK_NULL_VOID(controlBar);
669 auto sliderNode = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(SLIDER_POS));
670 auto sliderPaintProperty = sliderNode->GetPaintProperty<SliderPaintProperty>();
671 CHECK_NULL_VOID(sliderPaintProperty);
672 sliderPaintProperty->UpdateMin(0.0f);
673 sliderPaintProperty->UpdateMax(static_cast<float>(duration_));
674 sliderNode->MarkModifyDone();
675 auto playBtn = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(0));
676 ChangePlayButtonTag(playBtn);
677
678 if (needFireEvent) {
679 auto json = JsonUtil::Create(true);
680 json->Put("duration", static_cast<double>(duration_));
681 auto param = json->ToString();
682 auto eventHub = GetEventHub<VideoEventHub>();
683 CHECK_NULL_VOID(eventHub);
684 eventHub->FirePreparedEvent(param);
685 }
686 UpdateLooping();
687 UpdateSpeed();
688 UpdateMuted();
689
690 checkNeedAutoPlay();
691 }
692
checkNeedAutoPlay()693 void VideoPattern::checkNeedAutoPlay()
694 {
695 if (isStop_) {
696 isStop_ = false;
697 }
698 if (autoPlay_) {
699 Start();
700 }
701 }
702
OnCompletion()703 void VideoPattern::OnCompletion()
704 {
705 isPlaying_ = false;
706 currentPos_ = duration_;
707 OnUpdateTime(currentPos_, CURRENT_POS);
708 auto json = JsonUtil::Create(true);
709 json->Put("finish", "");
710 auto param = json->ToString();
711 auto eventHub = GetEventHub<VideoEventHub>();
712 CHECK_NULL_VOID(eventHub);
713 eventHub->FireFinishEvent(param);
714 }
715
HasPlayer() const716 bool VideoPattern::HasPlayer() const
717 {
718 return mediaPlayer_ != nullptr;
719 }
720
HiddenChange(bool hidden)721 void VideoPattern::HiddenChange(bool hidden)
722 {
723 if (isPlaying_ && hidden && HasPlayer()) {
724 pastPlayingStatus_ = isPlaying_;
725 Pause();
726 return;
727 }
728
729 if (!hidden && pastPlayingStatus_) {
730 pastPlayingStatus_ = false;
731 Start();
732 }
733 }
734
OnVisibleChange(bool isVisible)735 void VideoPattern::OnVisibleChange(bool isVisible)
736 {
737 if (hiddenChangeEvent_) {
738 hiddenChangeEvent_(!isVisible);
739 }
740 }
741
UpdateLooping()742 void VideoPattern::UpdateLooping()
743 {
744 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid()) {
745 ContainerScope scope(instanceId_);
746 auto host = GetHost();
747 CHECK_NULL_VOID(host);
748 auto context = host->GetContext();
749 CHECK_NULL_VOID(context);
750 auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
751 platformTask.PostTask([weak = WeakClaim(RawPtr(mediaPlayer_)), loop = loop_] {
752 auto mediaPlayer = weak.Upgrade();
753 CHECK_NULL_VOID(mediaPlayer);
754 mediaPlayer->SetLooping(loop);
755 }, "ArkUIVideoUpdateLooping");
756 }
757 }
758
UpdateSpeed()759 void VideoPattern::UpdateSpeed()
760 {
761 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid()) {
762 ContainerScope scope(instanceId_);
763 auto host = GetHost();
764 CHECK_NULL_VOID(host);
765 auto context = host->GetContext();
766 CHECK_NULL_VOID(context);
767 auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
768 platformTask.PostTask([weak = WeakClaim(RawPtr(mediaPlayer_)), progress = progressRate_] {
769 auto mediaPlayer = weak.Upgrade();
770 CHECK_NULL_VOID(mediaPlayer);
771 mediaPlayer->SetPlaybackSpeed(static_cast<float>(progress));
772 }, "ArkUIVideoUpdateSpeed");
773 }
774 }
775
UpdateMuted()776 void VideoPattern::UpdateMuted()
777 {
778 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid()) {
779 ContainerScope scope(instanceId_);
780 auto host = GetHost();
781 CHECK_NULL_VOID(host);
782 auto context = host->GetContext();
783 CHECK_NULL_VOID(context);
784 auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
785 platformTask.PostTask([weak = WeakClaim(RawPtr(mediaPlayer_)), isMuted = muted_] {
786 auto mediaPlayer = weak.Upgrade();
787 CHECK_NULL_VOID(mediaPlayer);
788 if (isMuted) {
789 mediaPlayer->SetMediaMuted(MEDIA_TYPE_AUD, true);
790 mediaPlayer->SetVolume(0.0f, 0.0f);
791 } else {
792 mediaPlayer->SetMediaMuted(MEDIA_TYPE_AUD, false);
793 mediaPlayer->SetVolume(1.0f, 1.0f);
794 }
795 }, "ArkUIVideoUpdateMuted");
796 }
797 }
798
OnUpdateTime(uint32_t time,int pos) const799 void VideoPattern::OnUpdateTime(uint32_t time, int pos) const
800 {
801 auto host = GetHost();
802 CHECK_NULL_VOID(host);
803 auto layoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
804 CHECK_NULL_VOID(layoutProperty);
805 bool needControlBar = layoutProperty->GetControlsValue(true);
806 if (!needControlBar) {
807 return;
808 }
809
810 RefPtr<UINode> controlBar = nullptr;
811 auto children = host->GetChildren();
812 for (const auto& child : children) {
813 if (child->GetTag() == V2::ROW_ETS_TAG) {
814 controlBar = child;
815 break;
816 }
817 }
818
819 CHECK_NULL_VOID(controlBar);
820 auto durationNode = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(pos));
821 CHECK_NULL_VOID(durationNode);
822 auto textLayoutProperty = durationNode->GetLayoutProperty<TextLayoutProperty>();
823 CHECK_NULL_VOID(textLayoutProperty);
824 std::string timeText = IntTimeToText(time);
825 textLayoutProperty->UpdateContent(timeText);
826 durationNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
827 durationNode->MarkModifyDone();
828 // if current status is seeking, no need to update slider's value
829 if (pos == CURRENT_POS && !isSeeking_) {
830 auto sliderNode = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(SLIDER_POS));
831 CHECK_NULL_VOID(sliderNode);
832 auto sliderPattern = sliderNode->GetPattern<SliderPattern>();
833 CHECK_NULL_VOID(sliderPattern);
834 sliderPattern->UpdateValue(static_cast<float>(time));
835 sliderNode->MarkModifyDone();
836 }
837 }
838
PrepareSurface()839 void VideoPattern::PrepareSurface()
840 {
841 if (!mediaPlayer_ || renderSurface_->IsSurfaceValid()) {
842 return;
843 }
844 if (!SystemProperties::GetExtSurfaceEnabled()) {
845 renderSurface_->SetRenderContext(renderContextForMediaPlayer_);
846 }
847 renderSurface_->InitSurface();
848 mediaPlayer_->SetRenderSurface(renderSurface_);
849 if (mediaPlayer_->SetSurface() != 0) {
850 TAG_LOGW(AceLogTag::ACE_VIDEO, "mediaPlayer renderSurface set failed");
851 }
852 }
853
OnAttachToFrameNode()854 void VideoPattern::OnAttachToFrameNode()
855 {
856 // full screen node is not supposed to register js controller event
857 if (!InstanceOf<VideoFullScreenPattern>(this)) {
858 SetMethodCall();
859 }
860 auto host = GetHost();
861 CHECK_NULL_VOID(host);
862 auto pipeline = host->GetContext();
863 CHECK_NULL_VOID(pipeline);
864 pipeline->AddWindowStateChangedCallback(host->GetId());
865 auto renderContext = host->GetRenderContext();
866 CHECK_NULL_VOID(renderContext);
867
868 #ifdef RENDER_EXTRACT_SUPPORTED
869 CHECK_NULL_VOID(renderSurface_);
870 auto contextType = renderSurface_->IsTexture() ?
871 RenderContext::ContextType::HARDWARE_TEXTURE : RenderContext::ContextType::HARDWARE_SURFACE;
872 static RenderContext::ContextParam param = { contextType, "MediaPlayerSurface",
873 RenderContext::PatternType::VIDEO };
874 #else
875 static RenderContext::ContextParam param = { RenderContext::ContextType::HARDWARE_SURFACE, "MediaPlayerSurface",
876 RenderContext::PatternType::VIDEO };
877 #endif
878 renderContextForMediaPlayer_->InitContext(false, param);
879
880 if (SystemProperties::GetExtSurfaceEnabled()) {
881 RegisterRenderContextCallBack();
882 }
883
884 renderContext->UpdateBackgroundColor(Color::BLACK);
885 renderContextForMediaPlayer_->UpdateBackgroundColor(Color::BLACK);
886 renderContext->SetClipToBounds(true);
887 }
888
OnDetachFromFrameNode(FrameNode * frameNode)889 void VideoPattern::OnDetachFromFrameNode(FrameNode* frameNode)
890 {
891 CHECK_NULL_VOID(frameNode);
892 auto id = frameNode->GetId();
893 auto pipeline = frameNode->GetContext();
894 CHECK_NULL_VOID(pipeline);
895 pipeline->RemoveWindowStateChangedCallback(id);
896 }
897
OnDetachFromMainTree()898 void VideoPattern::OnDetachFromMainTree()
899 {
900 auto host = GetHost();
901 if (host && host->GetNodeStatus() == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
902 Pause();
903 }
904 }
905
RegisterRenderContextCallBack()906 void VideoPattern::RegisterRenderContextCallBack()
907 {
908 #ifdef RENDER_EXTRACT_SUPPORTED
909 renderSurfaceWeakPtr_ = renderSurface_;
910 renderContextForMediaPlayerWeakPtr_ = renderContextForMediaPlayer_;
911 auto OnAttachCallBack = [weak = WeakClaim(this)](int64_t textureId, bool isAttach) mutable {
912 auto videoPattern = weak.Upgrade();
913 CHECK_NULL_VOID(videoPattern);
914 if (auto renderSurface = videoPattern->renderSurfaceWeakPtr_.Upgrade(); renderSurface) {
915 renderSurface->AttachToGLContext(textureId, isAttach);
916 }
917 };
918 renderContextForMediaPlayer_->AddAttachCallBack(OnAttachCallBack);
919 auto OnUpdateCallBack = [weak = WeakClaim(this)](std::vector<float>& matrix) mutable {
920 auto videoPattern = weak.Upgrade();
921 CHECK_NULL_VOID(videoPattern);
922 if (auto renderSurface = videoPattern->renderSurfaceWeakPtr_.Upgrade(); renderSurface) {
923 renderSurface->UpdateTextureImage(matrix);
924 }
925 };
926 renderContextForMediaPlayer_->AddUpdateCallBack(OnUpdateCallBack);
927 #endif
928 }
929
OnModifyDone()930 void VideoPattern::OnModifyDone()
931 {
932 Pattern::OnModifyDone();
933
934 if (!hiddenChangeEvent_) {
935 SetHiddenChangeEvent(CreateHiddenChangeEvent());
936 }
937
938 // src has changed
939 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
940 #ifdef RENDER_EXTRACT_SUPPORTED
941 if ((layoutProperty && layoutProperty->HasVideoSource() && layoutProperty->GetVideoSource() != videoSrcInfo_)) {
942 #else
943 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
944 (layoutProperty && layoutProperty->HasVideoSource() && layoutProperty->GetVideoSource() != videoSrcInfo_)) {
945 #endif
946 ResetStatus();
947 }
948
949 // update full screen pattern state
950 UpdateFsState();
951
952 // Update the control bar and preview image.
953 UpdatePreviewImage();
954 UpdateControllerBar();
955 auto host = GetHost();
956 CHECK_NULL_VOID(host);
957 // Update the media player when video node is not in full screen or current node is full screen node
958 if (!fullScreenNodeId_.has_value() || InstanceOf<VideoFullScreenNode>(this)) {
959 ContainerScope scope(instanceId_);
960 auto pipelineContext = host->GetContext();
961 CHECK_NULL_VOID(pipelineContext);
962 auto uiTaskExecutor = SingleTaskExecutor::Make(pipelineContext->GetTaskExecutor(), TaskExecutor::TaskType::UI);
963 uiTaskExecutor.PostTask([weak = WeakClaim(this)]() {
964 auto videoPattern = weak.Upgrade();
965 CHECK_NULL_VOID(videoPattern);
966 ContainerScope scope(videoPattern->instanceId_);
967 videoPattern->UpdateMediaPlayerOnBg();
968 }, "ArkUIVideoUpdateMediaPlayer");
969 }
970
971 if (SystemProperties::GetExtSurfaceEnabled()) {
972 auto pipelineContext = host->GetContext();
973 CHECK_NULL_VOID(pipelineContext);
974 pipelineContext->AddOnAreaChangeNode(host->GetId());
975 }
976 auto eventHub = GetEventHub<VideoEventHub>();
977 if (!AceType::InstanceOf<VideoFullScreenPattern>(this)) {
978 auto host = GetHost();
979 CHECK_NULL_VOID(host);
980 eventHub->SetInspectorId(host->GetInspectorIdValue(""));
981 }
982 if (!IsSupportImageAnalyzer()) {
983 DestroyAnalyzerOverlay();
984 } else if (isPaused_ && !isPlaying_ && !GetAnalyzerState()) {
985 StartImageAnalyzer();
986 }
987 }
988
989 HiddenChangeEvent VideoPattern::CreateHiddenChangeEvent()
990 {
991 return [weak = WeakClaim(this)](bool hidden) {
992 auto videoPattern = weak.Upgrade();
993 CHECK_NULL_VOID(videoPattern);
994 auto fullScreenNode = videoPattern->GetFullScreenNode();
995 if (fullScreenNode) {
996 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(fullScreenNode->GetPattern());
997 CHECK_NULL_VOID(fullScreenPattern);
998 fullScreenPattern->HiddenChange(hidden);
999 return;
1000 }
1001 videoPattern->HiddenChange(hidden);
1002 };
1003 }
1004
1005 void VideoPattern::UpdatePreviewImage()
1006 {
1007 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1008 CHECK_NULL_VOID(layoutProperty);
1009 if (!layoutProperty->HasPosterImageInfo()) {
1010 return;
1011 }
1012 auto posterSourceInfo = layoutProperty->GetPosterImageInfo().value();
1013 auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
1014 auto host = GetHost();
1015 CHECK_NULL_VOID(host);
1016
1017 auto video = AceType::DynamicCast<VideoNode>(host);
1018 CHECK_NULL_VOID(video);
1019 auto image = AceType::DynamicCast<FrameNode>(video->GetPreviewImage());
1020 CHECK_NULL_VOID(image);
1021 if (!isInitialState_) {
1022 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1023 posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1024 image->MarkModifyDone();
1025 return;
1026 }
1027
1028 if (!posterSourceInfo.IsValid()) {
1029 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1030 posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1031 image->MarkModifyDone();
1032 TAG_LOGI(AceLogTag::ACE_VIDEO, "Src image is not valid.");
1033 return;
1034 }
1035
1036 if (image) {
1037 image->SetDraggable(false);
1038 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1039 posterLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1040 posterLayoutProperty->UpdateImageSourceInfo(posterSourceInfo);
1041 posterLayoutProperty->UpdateImageFit(imageFit);
1042 image->MarkModifyDone();
1043 }
1044 }
1045
1046 void VideoPattern::UpdateControllerBar()
1047 {
1048 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1049 CHECK_NULL_VOID(layoutProperty);
1050 auto host = GetHost();
1051 CHECK_NULL_VOID(host);
1052 auto children = host->GetChildren();
1053 if (layoutProperty->GetControlsValue(true)) {
1054 auto video = AceType::DynamicCast<VideoNode>(host);
1055 CHECK_NULL_VOID(video);
1056 auto controller = AceType::DynamicCast<FrameNode>(video->GetControllerRow());
1057 if (controller) {
1058 auto sliderNode = DynamicCast<FrameNode>(controller->GetChildAtIndex(SLIDER_POS));
1059 CHECK_NULL_VOID(sliderNode);
1060 auto sliderPattern = sliderNode->GetPattern<SliderPattern>();
1061 CHECK_NULL_VOID(sliderPattern);
1062 sliderPattern->UpdateValue(static_cast<float>(currentPos_));
1063 sliderNode->MarkModifyDone();
1064
1065 auto textNode = DynamicCast<FrameNode>(controller->GetChildAtIndex(CURRENT_POS));
1066 CHECK_NULL_VOID(textNode);
1067 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1068 CHECK_NULL_VOID(textLayoutProperty);
1069 std::string label = IntTimeToText(currentPos_);
1070 textLayoutProperty->UpdateContent(label);
1071
1072 auto durationNode = DynamicCast<FrameNode>(controller->GetChildAtIndex(DURATION_POS));
1073 CHECK_NULL_VOID(durationNode);
1074 auto durationTextLayoutProperty = durationNode->GetLayoutProperty<TextLayoutProperty>();
1075 CHECK_NULL_VOID(durationTextLayoutProperty);
1076 std::string durationText = IntTimeToText(duration_);
1077 durationTextLayoutProperty->UpdateContent(durationText);
1078
1079 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1080 textNode->MarkModifyDone();
1081 durationNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1082 durationNode->MarkModifyDone();
1083 auto controllerLayoutProperty = controller->GetLayoutProperty<LinearLayoutProperty>();
1084 controllerLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1085 controller->MarkModifyDone();
1086 }
1087 } else {
1088 auto video = AceType::DynamicCast<VideoNode>(host);
1089 CHECK_NULL_VOID(video);
1090 auto controller = AceType::DynamicCast<FrameNode>(video->GetControllerRow());
1091 CHECK_NULL_VOID(controller);
1092 if (controller) {
1093 auto controllerLayoutProperty = controller->GetLayoutProperty<LinearLayoutProperty>();
1094 controllerLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1095 controller->MarkModifyDone();
1096 }
1097 }
1098 }
1099
1100 void VideoPattern::UpdateVideoProperty()
1101 {
1102 if (isInitialState_ && autoPlay_) {
1103 Start();
1104 }
1105
1106 UpdateSpeed();
1107 UpdateLooping();
1108 UpdateMuted();
1109 }
1110
1111 void VideoPattern::OnRebuildFrame()
1112 {
1113 if (!renderSurface_ || !renderSurface_->IsSurfaceValid()) {
1114 TAG_LOGW(AceLogTag::ACE_VIDEO, "MediaPlayer surface is not valid");
1115 return;
1116 }
1117 auto host = GetHost();
1118 CHECK_NULL_VOID(host);
1119 auto video = AceType::DynamicCast<VideoNode>(host);
1120 CHECK_NULL_VOID(video);
1121 auto column = AceType::DynamicCast<FrameNode>(video->GetMediaColumn());
1122 CHECK_NULL_VOID(column);
1123 auto renderContext = column->GetRenderContext();
1124 CHECK_NULL_VOID(renderContext);
1125 renderContext->AddChild(renderContextForMediaPlayer_, 0);
1126 }
1127
1128 void VideoPattern::RemoveMediaPlayerSurfaceNode()
1129 {
1130 auto host = GetHost();
1131 CHECK_NULL_VOID(host);
1132 auto video = AceType::DynamicCast<VideoNode>(host);
1133 CHECK_NULL_VOID(video);
1134 auto column = AceType::DynamicCast<FrameNode>(video->GetMediaColumn());
1135 CHECK_NULL_VOID(column);
1136 auto renderContext = column->GetRenderContext();
1137 CHECK_NULL_VOID(renderContext);
1138 renderContext->RemoveChild(renderContextForMediaPlayer_);
1139 }
1140
1141 bool VideoPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1142 {
1143 if (config.skipMeasure || dirty->SkipMeasureContent()) {
1144 return false;
1145 }
1146 auto geometryNode = dirty->GetGeometryNode();
1147 CHECK_NULL_RETURN(geometryNode, false);
1148 auto videoNodeSize = geometryNode->GetContentSize();
1149 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1150 CHECK_NULL_RETURN(layoutProperty, false);
1151 auto videoFrameSize = MeasureVideoContentLayout(videoNodeSize, layoutProperty);
1152 // Change the surface layout for drawing video frames
1153 if (renderContextForMediaPlayer_) {
1154 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1155 auto rect = AdjustPaintRect((videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE,
1156 (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE, videoFrameSize.Width(),
1157 videoFrameSize.Height(), true);
1158 renderContextForMediaPlayer_->SetBounds(rect.GetX(), rect.GetY(), rect.Width(), rect.Height());
1159 } else {
1160 renderContextForMediaPlayer_->SetBounds((videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE,
1161 (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE, videoFrameSize.Width(),
1162 videoFrameSize.Height());
1163 }
1164 }
1165
1166 if (IsSupportImageAnalyzer()) {
1167 Rect tmpRect;
1168 auto padding = layoutProperty->CreatePaddingAndBorder();
1169 auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
1170 if (imageFit == ImageFit::COVER || imageFit == ImageFit::NONE) {
1171 tmpRect = Rect(padding.left.value_or(0), padding.top.value_or(0),
1172 videoNodeSize.Width(), videoNodeSize.Height());
1173 } else {
1174 tmpRect = Rect((videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE + padding.left.value_or(0),
1175 (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE + padding.top.value_or(0),
1176 videoFrameSize.Width(), videoFrameSize.Height());
1177 }
1178 if (contentRect_ != tmpRect && ShouldUpdateImageAnalyzer()) {
1179 StartUpdateImageAnalyzer();
1180 }
1181 contentRect_ = tmpRect;
1182 UpdateAnalyzerUIConfig(geometryNode);
1183 }
1184
1185 auto host = GetHost();
1186 CHECK_NULL_RETURN(host, false);
1187 host->MarkNeedSyncRenderTree();
1188 auto video = AceType::DynamicCast<VideoNode>(host);
1189 CHECK_NULL_RETURN(video, false);
1190 auto column = AceType::DynamicCast<FrameNode>(video->GetMediaColumn());
1191 CHECK_NULL_RETURN(column, false);
1192 column->GetRenderContext()->SetClipToBounds(true);
1193 return false;
1194 }
1195
1196 void VideoPattern::OnAreaChangedInner()
1197 {
1198 if (SystemProperties::GetExtSurfaceEnabled()) {
1199 auto host = GetHost();
1200 CHECK_NULL_VOID(host);
1201 auto geometryNode = host->GetGeometryNode();
1202 CHECK_NULL_VOID(geometryNode);
1203 auto videoNodeSize = geometryNode->GetContentSize();
1204 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1205 CHECK_NULL_VOID(layoutProperty);
1206 auto videoFrameSize = MeasureVideoContentLayout(videoNodeSize, layoutProperty);
1207 auto transformRelativeOffset = host->GetTransformRelativeOffset();
1208
1209 Rect rect =
1210 Rect(transformRelativeOffset.GetX() + (videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE,
1211 transformRelativeOffset.GetY() + (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE,
1212 videoFrameSize.Width(), videoFrameSize.Height());
1213 if (renderSurface_ && (rect != lastBoundsRect_)) {
1214 renderSurface_->SetExtSurfaceBounds(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1215 lastBoundsRect_ = rect;
1216 }
1217 }
1218 }
1219
1220 void VideoPattern::OnColorConfigurationUpdate()
1221 {
1222 ContainerScope scope(instanceId_);
1223 auto host = GetHost();
1224 CHECK_NULL_VOID(host);
1225 auto pipelineContext = PipelineBase::GetCurrentContext();
1226 CHECK_NULL_VOID(pipelineContext);
1227 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1228 CHECK_NULL_VOID(videoTheme);
1229 auto renderContext = controlBar_->GetRenderContext();
1230 CHECK_NULL_VOID(renderContext);
1231 renderContext->UpdateBackgroundColor(videoTheme->GetBkgColor());
1232 for (const auto& child : controlBar_->GetChildren()) {
1233 if (child->GetTag() == V2::TEXT_ETS_TAG) {
1234 auto frameNode = AceType::DynamicCast<FrameNode>(child);
1235 if (frameNode) {
1236 auto textLayoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
1237 if (textLayoutProperty) {
1238 auto textStyle = videoTheme->GetTimeTextStyle();
1239 textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
1240 }
1241 }
1242 }
1243 }
1244 host->SetNeedCallChildrenUpdate(false);
1245 host->MarkModifyDone();
1246 host->MarkDirtyNode();
1247 }
1248
1249 bool VideoPattern::NeedLift() const
1250 {
1251 auto host = GetHost();
1252 CHECK_NULL_RETURN(host, false);
1253 auto renderContext = host->GetRenderContext();
1254 CHECK_NULL_RETURN(renderContext, false);
1255 return IsFullScreen() && renderContext->IsUniRenderEnabled();
1256 }
1257
1258 RefPtr<FrameNode> VideoPattern::CreateControlBar(int32_t nodeId)
1259 {
1260 ContainerScope scope(instanceId_);
1261 auto pipelineContext = PipelineBase::GetCurrentContext();
1262 CHECK_NULL_RETURN(pipelineContext, nullptr);
1263 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1264 CHECK_NULL_RETURN(videoTheme, nullptr);
1265 auto controlBar = FrameNode::GetOrCreateFrameNode(
1266 V2::ROW_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
1267 CHECK_NULL_RETURN(controlBar, nullptr);
1268 controlBar_ = controlBar;
1269
1270 auto playButton = CreateSVG();
1271 CHECK_NULL_RETURN(playButton, nullptr);
1272 ChangePlayButtonTag(playButton);
1273 controlBar->AddChild(playButton);
1274
1275 auto currentPosText = CreateText(currentPos_);
1276 CHECK_NULL_RETURN(currentPosText, nullptr);
1277 controlBar->AddChild(currentPosText);
1278
1279 auto slider = CreateSlider();
1280 CHECK_NULL_RETURN(currentPosText, nullptr);
1281 controlBar->AddChild(slider);
1282
1283 auto durationText = CreateText(duration_);
1284 CHECK_NULL_RETURN(durationText, nullptr);
1285 controlBar->AddChild(durationText);
1286
1287 auto fullScreenButton = CreateSVG();
1288 CHECK_NULL_RETURN(fullScreenButton, nullptr);
1289 SetFullScreenButtonCallBack(fullScreenButton);
1290 ChangeFullScreenButtonTag(InstanceOf<VideoFullScreenNode>(this), fullScreenButton);
1291 controlBar->AddChild(fullScreenButton);
1292
1293 auto renderContext = controlBar->GetRenderContext();
1294 renderContext->UpdateBackgroundColor(videoTheme->GetBkgColor());
1295 auto controlBarLayoutProperty = controlBar->GetLayoutProperty<LinearLayoutProperty>();
1296 controlBarLayoutProperty->UpdateMainAxisAlign(FlexAlign::SPACE_BETWEEN);
1297 if (NeedLift()) {
1298 PaddingProperty padding;
1299 padding.bottom = CalcLength(LIFT_HEIGHT);
1300 controlBarLayoutProperty->UpdatePadding(padding);
1301 }
1302 return controlBar;
1303 }
1304
1305 RefPtr<FrameNode> VideoPattern::CreateSlider()
1306 {
1307 auto pipelineContext = PipelineBase::GetCurrentContext();
1308 CHECK_NULL_RETURN(pipelineContext, nullptr);
1309 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1310 CHECK_NULL_RETURN(videoTheme, nullptr);
1311
1312 auto sliderNode = FrameNode::CreateFrameNode(V2::SLIDER_ETS_TAG, -1, AceType::MakeRefPtr<SliderPattern>());
1313 CHECK_NULL_RETURN(sliderNode, nullptr);
1314 auto sliderLayoutProperty = sliderNode->GetLayoutProperty<SliderLayoutProperty>();
1315 CHECK_NULL_RETURN(sliderLayoutProperty, nullptr);
1316
1317 auto sliderEdge = videoTheme->GetSliderEdge();
1318 PaddingProperty padding;
1319 padding.left = CalcLength(sliderEdge.Left());
1320 padding.right = CalcLength(sliderEdge.Right());
1321 padding.top = CalcLength(sliderEdge.Top());
1322 padding.bottom = CalcLength(sliderEdge.Bottom());
1323 sliderLayoutProperty->UpdatePadding(padding);
1324 sliderLayoutProperty->UpdateLayoutWeight(1.0);
1325
1326 SliderOnChangeEvent sliderOnChangeEvent = [weak = WeakClaim(this)](float value, int32_t mode) {
1327 auto videoPattern = weak.Upgrade();
1328 CHECK_NULL_VOID(videoPattern);
1329 videoPattern->OnSliderChange(value, mode);
1330 };
1331 auto sliderEventHub = sliderNode->GetEventHub<SliderEventHub>();
1332 sliderEventHub->SetOnChange(std::move(sliderOnChangeEvent));
1333 if (InstanceOf<VideoFullScreenPattern>(this)) {
1334 auto focusHub = sliderNode->GetOrCreateFocusHub();
1335 focusHub->SetIsDefaultFocus(true);
1336 }
1337
1338 auto sliderPaintProperty = sliderNode->GetPaintProperty<SliderPaintProperty>();
1339 CHECK_NULL_RETURN(sliderPaintProperty, nullptr);
1340 sliderPaintProperty->UpdateMax(static_cast<float>(duration_));
1341 sliderPaintProperty->UpdateSelectColor(videoTheme->GetSelectColor());
1342 sliderPaintProperty->UpdateTrackBackgroundColor(ConvertToGradient(videoTheme->GetTrackBgColor()));
1343 sliderPaintProperty->UpdateTrackBackgroundIsResourceColor(true);
1344 sliderPaintProperty->UpdateValue(static_cast<float>(currentPos_));
1345 sliderNode->MarkModifyDone();
1346 return sliderNode;
1347 }
1348
1349 RefPtr<FrameNode> VideoPattern::CreateText(uint32_t time)
1350 {
1351 auto pipelineContext = PipelineBase::GetCurrentContext();
1352 CHECK_NULL_RETURN(pipelineContext, nullptr);
1353 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1354 CHECK_NULL_RETURN(videoTheme, nullptr);
1355
1356 auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, -1, AceType::MakeRefPtr<TextPattern>());
1357 CHECK_NULL_RETURN(textNode, nullptr);
1358 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1359 CHECK_NULL_RETURN(textLayoutProperty, nullptr);
1360 auto videoLayoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1361 CHECK_NULL_RETURN(videoLayoutProperty, nullptr);
1362 std::string label = "";
1363 if (videoLayoutProperty->GetControlsValue(true)) {
1364 label = IntTimeToText(time);
1365 }
1366 textLayoutProperty->UpdateContent(label);
1367 auto textEdge = videoTheme->GetTextEdge();
1368 PaddingProperty padding;
1369 padding.left = CalcLength(textEdge.Left());
1370 padding.right = CalcLength(textEdge.Right());
1371 padding.top = CalcLength(textEdge.Top());
1372 padding.bottom = CalcLength(textEdge.Bottom());
1373 textLayoutProperty->UpdatePadding(padding);
1374 auto textStyle = videoTheme->GetTimeTextStyle();
1375 textLayoutProperty->UpdateFontSize(textStyle.GetFontSize());
1376 textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
1377 return textNode;
1378 }
1379
1380 RefPtr<FrameNode> VideoPattern::CreateSVG()
1381 {
1382 auto pipelineContext = GetHost()->GetContext();
1383 CHECK_NULL_RETURN(pipelineContext, nullptr);
1384 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1385 CHECK_NULL_RETURN(videoTheme, nullptr);
1386
1387 auto svgNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
1388 CHECK_NULL_RETURN(svgNode, nullptr);
1389
1390 auto imageRenderProperty = svgNode->GetPaintPropertyPtr<ImageRenderProperty>();
1391 imageRenderProperty->UpdateSvgFillColor(videoTheme->GetIconColor());
1392 auto renderContext = svgNode->GetRenderContext();
1393 renderContext->UpdateForegroundColor(videoTheme->GetIconColor());
1394
1395 auto svgLayoutProperty = svgNode->GetLayoutProperty<ImageLayoutProperty>();
1396
1397 auto btnEdge = videoTheme->GetBtnEdge();
1398 PaddingProperty padding;
1399 padding.left = CalcLength(btnEdge.Left());
1400 padding.right = CalcLength(btnEdge.Right());
1401 padding.top = CalcLength(btnEdge.Top());
1402 padding.bottom = CalcLength(btnEdge.Bottom());
1403 svgLayoutProperty->UpdatePadding(padding);
1404
1405 auto btnSize = videoTheme->GetBtnSize();
1406 SizeF size { static_cast<float>(btnSize.Width()), static_cast<float>(btnSize.Height()) };
1407 svgLayoutProperty->UpdateMarginSelfIdealSize(size);
1408 auto width = Dimension(btnSize.Width(), DimensionUnit::VP).ConvertToPx();
1409 auto height = Dimension(btnSize.Height(), DimensionUnit::VP).ConvertToPx();
1410 CalcSize idealSize = { CalcLength(width), CalcLength(height) };
1411 MeasureProperty layoutConstraint;
1412 layoutConstraint.selfIdealSize = idealSize;
1413 layoutConstraint.maxSize = idealSize;
1414 svgNode->UpdateLayoutConstraint(layoutConstraint);
1415 return svgNode;
1416 }
1417
1418 void VideoPattern::SetStartImpl(
1419 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1420 {
1421 videoController->SetStartImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1422 uiTaskExecutor.PostTask([weak]() {
1423 auto pattern = weak.Upgrade();
1424 CHECK_NULL_VOID(pattern);
1425 ContainerScope scope(pattern->instanceId_);
1426 auto targetPattern = pattern->GetTargetVideoPattern();
1427 CHECK_NULL_VOID(targetPattern);
1428 targetPattern->Start();
1429 }, "ArkUIVideoStart");
1430 });
1431 }
1432
1433 void VideoPattern::SetPausetImpl(
1434 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1435 {
1436 videoController->SetPausetImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1437 uiTaskExecutor.PostTask([weak]() {
1438 auto pattern = weak.Upgrade();
1439 CHECK_NULL_VOID(pattern);
1440 ContainerScope scope(pattern->instanceId_);
1441 auto targetPattern = pattern->GetTargetVideoPattern();
1442 CHECK_NULL_VOID(targetPattern);
1443 targetPattern->Pause();
1444 }, "ArkUIVideoPause");
1445 });
1446 }
1447
1448 void VideoPattern::SetStopImpl(
1449 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1450 {
1451 videoController->SetStopImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1452 uiTaskExecutor.PostTask([weak]() {
1453 auto pattern = weak.Upgrade();
1454 CHECK_NULL_VOID(pattern);
1455 ContainerScope scope(pattern->instanceId_);
1456 auto targetPattern = pattern->GetTargetVideoPattern();
1457 CHECK_NULL_VOID(targetPattern);
1458 targetPattern->Stop();
1459 }, "ArkUIVideoStop");
1460 });
1461 }
1462
1463 void VideoPattern::SetSeekToImpl(
1464 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1465 {
1466 videoController->SetSeekToImpl([weak = WeakClaim(this), uiTaskExecutor](float pos, SeekMode seekMode) {
1467 uiTaskExecutor.PostTask([weak, pos, seekMode]() {
1468 auto pattern = weak.Upgrade();
1469 CHECK_NULL_VOID(pattern);
1470 ContainerScope scope(pattern->instanceId_);
1471 auto targetPattern = pattern->GetTargetVideoPattern();
1472 CHECK_NULL_VOID(targetPattern);
1473 targetPattern->SetCurrentTime(pos, seekMode);
1474 }, "ArkUIVideoSetCurrentTime");
1475 });
1476 }
1477
1478 void VideoPattern::SetRequestFullscreenImpl(
1479 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1480 {
1481 videoController->SetRequestFullscreenImpl([weak = WeakClaim(this), uiTaskExecutor](bool isFullScreen) {
1482 uiTaskExecutor.PostTask([weak, isFullScreen]() {
1483 auto videoPattern = weak.Upgrade();
1484 CHECK_NULL_VOID(videoPattern);
1485 ContainerScope scope(videoPattern->instanceId_);
1486 if (isFullScreen) {
1487 videoPattern->FullScreen();
1488 } else {
1489 videoPattern->ResetLastBoundsRect();
1490 auto targetPattern = videoPattern->GetTargetVideoPattern();
1491 CHECK_NULL_VOID(targetPattern);
1492 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(targetPattern);
1493 CHECK_NULL_VOID(fullScreenPattern);
1494 fullScreenPattern->ExitFullScreen();
1495 }
1496 }, "ArkUIVideoFullScreen");
1497 });
1498 }
1499
1500 void VideoPattern::SetExitFullscreenImpl(
1501 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1502 {
1503 videoController->SetExitFullscreenImpl([weak = WeakClaim(this), uiTaskExecutor](bool isSync) {
1504 if (isSync) {
1505 auto pattern = weak.Upgrade();
1506 CHECK_NULL_VOID(pattern);
1507 auto targetPattern = pattern->GetTargetVideoPattern();
1508 CHECK_NULL_VOID(targetPattern);
1509 pattern->ResetLastBoundsRect();
1510 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(targetPattern);
1511 fullScreenPattern->ExitFullScreen();
1512 return;
1513 }
1514 uiTaskExecutor.PostTask([weak]() {
1515 auto pattern = weak.Upgrade();
1516 CHECK_NULL_VOID(pattern);
1517 ContainerScope scope(pattern->instanceId_);
1518 pattern->ResetLastBoundsRect();
1519 auto targetPattern = pattern->GetTargetVideoPattern();
1520 CHECK_NULL_VOID(targetPattern);
1521 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(targetPattern);
1522 CHECK_NULL_VOID(fullScreenPattern);
1523 fullScreenPattern->ExitFullScreen();
1524 }, "ArkUIVideoExitFullScreen");
1525 });
1526 }
1527
1528 void VideoPattern::SetResetImpl(
1529 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1530 {
1531 videoController->SetResetImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1532 uiTaskExecutor.PostTask([weak]() {
1533 auto pattern = weak.Upgrade();
1534 CHECK_NULL_VOID(pattern);
1535 auto targetPattern = pattern->GetTargetVideoPattern();
1536 CHECK_NULL_VOID(targetPattern);
1537 targetPattern->ResetMediaPlayer();
1538 }, "ArkUIVideoReset");
1539 });
1540 }
1541
1542 void VideoPattern::SetMethodCall()
1543 {
1544 ContainerScope scope(instanceId_);
1545 auto videoController = AceType::MakeRefPtr<VideoController>();
1546 auto host = GetHost();
1547 CHECK_NULL_VOID(host);
1548 auto context = host->GetContext();
1549 CHECK_NULL_VOID(context);
1550 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1551
1552 SetStartImpl(videoController, uiTaskExecutor);
1553 SetPausetImpl(videoController, uiTaskExecutor);
1554 SetStopImpl(videoController, uiTaskExecutor);
1555 SetSeekToImpl(videoController, uiTaskExecutor);
1556 SetRequestFullscreenImpl(videoController, uiTaskExecutor);
1557 SetExitFullscreenImpl(videoController, uiTaskExecutor);
1558 SetResetImpl(videoController, uiTaskExecutor);
1559
1560 CHECK_NULL_VOID(videoControllerV2_);
1561 videoControllerV2_->AddVideoController(videoController);
1562 }
1563
1564 void VideoPattern::Start()
1565 {
1566 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1567 return;
1568 }
1569
1570 if (isStop_ && mediaPlayer_->PrepareAsync() != 0) {
1571 TAG_LOGW(AceLogTag::ACE_VIDEO, "Player has not prepared");
1572 return;
1573 }
1574 ContainerScope scope(instanceId_);
1575 auto host = GetHost();
1576 CHECK_NULL_VOID(host);
1577 auto context = host->GetContext();
1578 CHECK_NULL_VOID(context);
1579
1580 DestroyAnalyzerOverlay();
1581 isPaused_ = false;
1582
1583 auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1584 platformTask.PostTask([weak = WeakClaim(RawPtr(mediaPlayer_))] {
1585 auto mediaPlayer = weak.Upgrade();
1586 CHECK_NULL_VOID(mediaPlayer);
1587 TAG_LOGI(AceLogTag::ACE_VIDEO, "trigger mediaPlayer play");
1588 mediaPlayer->Play();
1589 }, "ArkUIVideoPlay");
1590 }
1591
1592 void VideoPattern::Pause()
1593 {
1594 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1595 return;
1596 }
1597 auto ret = mediaPlayer_->Pause();
1598 if (ret != -1 && !isPaused_) {
1599 isPaused_ = true;
1600 StartImageAnalyzer();
1601 }
1602 }
1603
1604 void VideoPattern::Stop()
1605 {
1606 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1607 return;
1608 }
1609
1610 OnCurrentTimeChange(0);
1611 mediaPlayer_->Stop();
1612 isStop_ = true;
1613 }
1614
1615 void VideoPattern::FireError()
1616 {
1617 ContainerScope scope(instanceId_);
1618 auto host = GetHost();
1619 CHECK_NULL_VOID(host);
1620 auto context = host->GetContext();
1621 CHECK_NULL_VOID(context);
1622
1623 // OnError function must be excuted on ui, so get the uiTaskExecutor.
1624 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1625 uiTaskExecutor.PostTask([weak = WeakClaim(this)] {
1626 auto videoPattern = weak.Upgrade();
1627 CHECK_NULL_VOID(videoPattern);
1628 ContainerScope scope(videoPattern->instanceId_);
1629 videoPattern->OnError("");
1630 }, "ArkUIVideoError");
1631 }
1632
1633 void VideoPattern::ChangePlayButtonTag()
1634 {
1635 ContainerScope scope(instanceId_);
1636 auto host = GetHost();
1637 CHECK_NULL_VOID(host);
1638 auto context = host->GetContext();
1639 CHECK_NULL_VOID(context);
1640 const auto& children = host->GetChildren();
1641 for (const auto& child : children) {
1642 if (child->GetTag() == V2::ROW_ETS_TAG) {
1643 auto playBtn = DynamicCast<FrameNode>(child->GetChildAtIndex(0));
1644 ChangePlayButtonTag(playBtn);
1645 break;
1646 }
1647 }
1648 }
1649
1650 void VideoPattern::ChangePlayButtonTag(RefPtr<FrameNode>& playBtn)
1651 {
1652 CHECK_NULL_VOID(playBtn);
1653 auto playClickCallback = [weak = WeakClaim(this), playing = isPlaying_](GestureEvent& /* info */) {
1654 auto videoPattern = weak.Upgrade();
1655 CHECK_NULL_VOID(videoPattern);
1656 if (playing) {
1657 videoPattern->Pause();
1658 } else {
1659 videoPattern->Start();
1660 }
1661 };
1662 auto playBtnEvent = playBtn->GetOrCreateGestureEventHub();
1663 playBtnEvent->SetUserOnClick(std::move(playClickCallback));
1664 auto svgLayoutProperty = playBtn->GetLayoutProperty<ImageLayoutProperty>();
1665 auto resourceId = isPlaying_ ? InternalResource::ResourceId::PAUSE_SVG : InternalResource::ResourceId::PLAY_SVG;
1666 auto svgSourceInfo = ImageSourceInfo("");
1667 svgSourceInfo.SetResourceId(resourceId);
1668 svgLayoutProperty->UpdateImageSourceInfo(svgSourceInfo);
1669 playBtn->MarkModifyDone();
1670 playBtn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1671 }
1672
1673 void VideoPattern::SetFullScreenButtonCallBack(RefPtr<FrameNode>& fullScreenBtn)
1674 {
1675 CHECK_NULL_VOID(fullScreenBtn);
1676 auto fsClickCallback = [weak = WeakClaim(this)](GestureEvent& /* info */) {
1677 auto videoPattern = weak.Upgrade();
1678 CHECK_NULL_VOID(videoPattern);
1679 if (InstanceOf<VideoFullScreenPattern>(videoPattern)) {
1680 auto pattern = AceType::DynamicCast<VideoFullScreenPattern>(videoPattern);
1681 CHECK_NULL_VOID(pattern);
1682 videoPattern->ResetLastBoundsRect();
1683 pattern->ExitFullScreen();
1684 } else {
1685 videoPattern->FullScreen();
1686 }
1687 };
1688 auto fullScreenBtnEvent = fullScreenBtn->GetOrCreateGestureEventHub();
1689 fullScreenBtnEvent->SetUserOnClick(std::move(fsClickCallback));
1690 }
1691
1692 void VideoPattern::ChangeFullScreenButtonTag(bool isFullScreen, RefPtr<FrameNode>& fullScreenBtn)
1693 {
1694 CHECK_NULL_VOID(fullScreenBtn);
1695 auto svgLayoutProperty = fullScreenBtn->GetLayoutProperty<ImageLayoutProperty>();
1696 auto resourceId =
1697 isFullScreen ? InternalResource::ResourceId::QUIT_FULLSCREEN_SVG : InternalResource::ResourceId::FULLSCREEN_SVG;
1698 auto svgSourceInfo = ImageSourceInfo("");
1699 svgSourceInfo.SetResourceId(resourceId);
1700 svgLayoutProperty->UpdateImageSourceInfo(svgSourceInfo);
1701 fullScreenBtn->MarkModifyDone();
1702 fullScreenBtn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1703 }
1704
1705 void VideoPattern::SetCurrentTime(float currentPos, OHOS::Ace::SeekMode seekMode)
1706 {
1707 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1708 return;
1709 }
1710 if (GreatOrEqual(currentPos, 0.0)) {
1711 SetIsSeeking(true);
1712 mediaPlayer_->Seek(static_cast<int32_t>(currentPos * MILLISECONDS_TO_SECONDS), seekMode);
1713 }
1714 }
1715
1716 void VideoPattern::OnSliderChange(float posTime, int32_t mode)
1717 {
1718 SetCurrentTime(posTime, OHOS::Ace::SeekMode::SEEK_CLOSEST);
1719 auto eventHub = GetEventHub<VideoEventHub>();
1720 CHECK_NULL_VOID(eventHub);
1721 auto json = JsonUtil::Create(true);
1722 json->Put("time", static_cast<double>(posTime));
1723 auto param = json->ToString();
1724 CHECK_NULL_VOID(eventHub);
1725 if (mode == SliderChangeMode::BEGIN || mode == SliderChangeMode::MOVING) {
1726 eventHub->FireSeekingEvent(param);
1727 } else if (mode == SliderChangeMode::END) {
1728 eventHub->FireSeekedEvent(param);
1729 }
1730 }
1731
1732 void VideoPattern::OnFullScreenChange(bool isFullScreen)
1733 {
1734 auto json = JsonUtil::Create(true);
1735 json->Put("fullscreen", isFullScreen);
1736 auto param = json->ToString();
1737 auto eventHub = GetEventHub<VideoEventHub>();
1738 CHECK_NULL_VOID(eventHub);
1739 eventHub->FireFullScreenChangeEvent(param);
1740 auto host = GetHost();
1741 CHECK_NULL_VOID(host);
1742 const auto& children = host->GetChildren();
1743 for (const auto& child : children) {
1744 if (child->GetTag() == V2::ROW_ETS_TAG) {
1745 auto fsBtn = DynamicCast<FrameNode>(child->GetChildAtIndex(FULL_SCREEN_POS));
1746 ChangeFullScreenButtonTag(isFullScreen, fsBtn);
1747 break;
1748 }
1749 }
1750 if (isEnableAnalyzer_) {
1751 if (!imageAnalyzerManager_) {
1752 EnableAnalyzer(isEnableAnalyzer_);
1753 }
1754 if (imageAnalyzerManager_ && isAnalyzerCreated_) {
1755 StartImageAnalyzer();
1756 }
1757 }
1758
1759 if (!SystemProperties::GetExtSurfaceEnabled()) {
1760 return;
1761 }
1762 if (!fullScreenNodeId_.has_value()) {
1763 SetMediaFullScreen(isFullScreen);
1764 return;
1765 }
1766 auto fullScreenNode = FrameNode::GetFrameNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value());
1767 CHECK_NULL_VOID(fullScreenNode);
1768 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(fullScreenNode->GetPattern());
1769 CHECK_NULL_VOID(fullScreenPattern);
1770 fullScreenPattern->SetMediaFullScreen(isFullScreen);
1771 }
1772
1773 void VideoPattern::FullScreen()
1774 {
1775 if (fullScreenNodeId_.has_value()) {
1776 return;
1777 }
1778 ResetLastBoundsRect();
1779 auto host = GetHost();
1780 CHECK_NULL_VOID(host);
1781 auto videoNode = AceType::DynamicCast<VideoNode>(host);
1782 CHECK_NULL_VOID(videoNode);
1783 auto fullScreenPattern = AceType::MakeRefPtr<VideoFullScreenPattern>(videoControllerV2_);
1784 fullScreenPattern->InitFullScreenParam(
1785 AceType::Claim(this), renderSurface_, mediaPlayer_, renderContextForMediaPlayer_);
1786 fullScreenNodeId_ = ElementRegister::GetInstance()->MakeUniqueId();
1787 auto fullScreenNode =
1788 VideoFullScreenNode::CreateFullScreenNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value(), fullScreenPattern);
1789 CHECK_NULL_VOID(fullScreenNode);
1790 fullScreenPattern->RequestFullScreen(videoNode);
1791 }
1792
1793 VideoPattern::~VideoPattern()
1794 {
1795 #ifdef RENDER_EXTRACT_SUPPORTED
1796 if (renderContextForMediaPlayer_) {
1797 renderContextForMediaPlayer_->RemoveSurfaceChangedCallBack();
1798 }
1799 #endif
1800 if (IsSupportImageAnalyzer()) {
1801 DestroyAnalyzerOverlay();
1802 }
1803 if (!fullScreenNodeId_.has_value()) {
1804 return;
1805 }
1806 auto fullScreenNode = FrameNode::GetFrameNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value());
1807 CHECK_NULL_VOID(fullScreenNode);
1808 auto parent = fullScreenNode->GetParent();
1809 CHECK_NULL_VOID(parent);
1810 parent->RemoveChild(fullScreenNode);
1811 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1812 }
1813
1814 void VideoPattern::RecoverState(const RefPtr<VideoPattern>& videoPattern)
1815 {
1816 CHECK_NULL_VOID(videoPattern);
1817 currentPos_ = videoPattern->GetCurrentPos();
1818 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid() && mediaPlayer_->IsPlaying() != isPlaying_) {
1819 isPlaying_ = mediaPlayer_->IsPlaying();
1820 ChangePlayButtonTag();
1821 }
1822 isInitialState_ = videoPattern->GetInitialState();
1823 auto layoutProperty = videoPattern->GetLayoutProperty<VideoLayoutProperty>();
1824 CHECK_NULL_VOID(layoutProperty);
1825 auto videoSrcInfo = layoutProperty->GetVideoSourceValue(VideoSourceInfo());
1826 videoSrcInfo_.src = videoSrcInfo.GetSrc();
1827 videoSrcInfo_.bundleName = videoSrcInfo.GetBundleName();
1828 videoSrcInfo_.moduleName = videoSrcInfo.GetModuleName();
1829 isStop_ = videoPattern->GetIsStop();
1830 muted_ = videoPattern->GetMuted();
1831 autoPlay_ = videoPattern->GetAutoPlay();
1832 loop_ = videoPattern->GetLoop();
1833 duration_ = videoPattern->GetDuration();
1834 progressRate_ = videoPattern->GetProgressRate();
1835 isAnalyzerCreated_ = videoPattern->GetAnalyzerState();
1836 isEnableAnalyzer_ = videoPattern->isEnableAnalyzer_;
1837 fullScreenNodeId_.reset();
1838 RegisterMediaPlayerEvent();
1839 auto videoNode = GetHost();
1840 CHECK_NULL_VOID(videoNode);
1841 // change event hub to the origin video node
1842 videoPattern->GetEventHub<VideoEventHub>()->AttachHost(videoNode);
1843 videoNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1844 }
1845
1846 void VideoPattern::UpdateFsState()
1847 {
1848 if (!fullScreenNodeId_.has_value()) {
1849 return;
1850 }
1851 auto videoNode = FrameNode::GetFrameNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value());
1852 CHECK_NULL_VOID(videoNode);
1853 auto videoPattern = AceType::DynamicCast<VideoFullScreenPattern>(videoNode->GetPattern());
1854 CHECK_NULL_VOID(videoPattern);
1855 // update full screen state
1856 videoPattern->UpdateState();
1857 }
1858
1859 bool VideoPattern::IsFullScreen() const
1860 {
1861 return fullScreenNodeId_.has_value();
1862 }
1863
1864 RefPtr<VideoPattern> VideoPattern::GetTargetVideoPattern()
1865 {
1866 auto isFullScreen = IsFullScreen();
1867 auto patternIsFullScreen = AceType::InstanceOf<VideoFullScreenPattern>(this);
1868 if ((isFullScreen && patternIsFullScreen) || (!isFullScreen && !patternIsFullScreen)) {
1869 return AceType::Claim(this);
1870 }
1871 if (patternIsFullScreen) {
1872 // current is full screen,need to be released
1873 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(this);
1874 CHECK_NULL_RETURN(fullScreenPattern, nullptr);
1875 return fullScreenPattern->GetVideoPattern();
1876 }
1877 // current node is origin video node, need to operate full screen node
1878 auto fullScreenNode = GetFullScreenNode();
1879 CHECK_NULL_RETURN(fullScreenNode, nullptr);
1880 return fullScreenNode->GetPattern<VideoPattern>();
1881 }
1882
1883 void VideoPattern::EnableAnalyzer(bool enable)
1884 {
1885 isEnableAnalyzer_ = enable;
1886 if (!isEnableAnalyzer_) {
1887 DestroyAnalyzerOverlay();
1888 return;
1889 }
1890
1891 CHECK_NULL_VOID(!imageAnalyzerManager_);
1892 auto host = GetHost();
1893 CHECK_NULL_VOID(host);
1894 imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(host, ImageAnalyzerHolder::VIDEO_CUSTOM);
1895 }
1896
1897 void VideoPattern::SetImageAnalyzerConfig(void* config)
1898 {
1899 if (isEnableAnalyzer_) {
1900 CHECK_NULL_VOID(imageAnalyzerManager_);
1901 imageAnalyzerManager_->SetImageAnalyzerConfig(config);
1902 }
1903 }
1904
1905 void VideoPattern::SetImageAIOptions(void* options)
1906 {
1907 if (!imageAnalyzerManager_) {
1908 imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::VIDEO_CUSTOM);
1909 }
1910 CHECK_NULL_VOID(imageAnalyzerManager_);
1911 imageAnalyzerManager_->SetImageAIOptions(options);
1912 }
1913
1914 bool VideoPattern::IsSupportImageAnalyzer()
1915 {
1916 auto host = GetHost();
1917 CHECK_NULL_RETURN(host, false);
1918 auto layoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
1919 CHECK_NULL_RETURN(layoutProperty, false);
1920 bool needControlBar = layoutProperty->GetControlsValue(true);
1921 CHECK_NULL_RETURN(imageAnalyzerManager_, false);
1922 return isEnableAnalyzer_ && !needControlBar && imageAnalyzerManager_->IsSupportImageAnalyzerFeature();
1923 }
1924
1925 bool VideoPattern::ShouldUpdateImageAnalyzer()
1926 {
1927 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1928 CHECK_NULL_RETURN(layoutProperty, false);
1929 const auto& constraint = layoutProperty->GetCalcLayoutConstraint();
1930 if (!constraint || !constraint->selfIdealSize.has_value() || !constraint->selfIdealSize->IsValid()) {
1931 return false;
1932 }
1933 auto selfIdealSize = constraint->selfIdealSize;
1934 if (!selfIdealSize->PercentWidth() && !selfIdealSize->PercentHeight()) {
1935 return false;
1936 }
1937 auto imageFit = layoutProperty->GetObjectFit().value_or(ImageFit::COVER);
1938 if (imageFit != ImageFit::COVER && imageFit != ImageFit::NONE) {
1939 return false;
1940 }
1941 return true;
1942 }
1943
1944 void VideoPattern::StartImageAnalyzer()
1945 {
1946 if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_) {
1947 return;
1948 }
1949
1950 if (imageAnalyzerManager_->IsOverlayCreated()) {
1951 DestroyAnalyzerOverlay();
1952 }
1953
1954 ContainerScope scope(instanceId_);
1955 auto host = GetHost();
1956 CHECK_NULL_VOID(host);
1957 auto context = host->GetContext();
1958 CHECK_NULL_VOID(context);
1959 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1960 uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
1961 auto pattern = weak.Upgrade();
1962 CHECK_NULL_VOID(pattern);
1963 pattern->CreateAnalyzerOverlay();
1964 }, ANALYZER_DELAY_TIME, "ArkUIVideoCreateAnalyzerOverlay");
1965 }
1966
1967 void VideoPattern::CreateAnalyzerOverlay()
1968 {
1969 auto host = GetHost();
1970 CHECK_NULL_VOID(host);
1971 host->SetOverlayNode(nullptr);
1972 auto context = host->GetRenderContext();
1973 CHECK_NULL_VOID(context);
1974 auto nailPixelMap = context->GetThumbnailPixelMap();
1975 CHECK_NULL_VOID(nailPixelMap);
1976 auto pixelMap = nailPixelMap->GetCropPixelMap(contentRect_);
1977 CHECK_NULL_VOID(pixelMap);
1978 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1979 CHECK_NULL_VOID(layoutProperty);
1980 auto padding = layoutProperty->CreatePaddingAndBorder();
1981 OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
1982 contentRect_.Top() - padding.top.value_or(0) };
1983 CHECK_NULL_VOID(imageAnalyzerManager_);
1984 imageAnalyzerManager_->CreateAnalyzerOverlay(pixelMap, contentOffset);
1985 }
1986
1987 void VideoPattern::StartUpdateImageAnalyzer()
1988 {
1989 CHECK_NULL_VOID(imageAnalyzerManager_);
1990 if (!imageAnalyzerManager_->IsOverlayCreated()) {
1991 return;
1992 }
1993
1994 UpdateOverlayVisibility(VisibleType::GONE);
1995 ContainerScope scope(instanceId_);
1996 auto host = GetHost();
1997 CHECK_NULL_VOID(host);
1998 auto context = host->GetContext();
1999 CHECK_NULL_VOID(context);
2000 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
2001 uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
2002 auto pattern = weak.Upgrade();
2003 CHECK_NULL_VOID(pattern);
2004 if (!pattern->isContentSizeChanged_) {
2005 return;
2006 }
2007 pattern->UpdateAnalyzerOverlay();
2008 pattern->isContentSizeChanged_ = false;
2009 }, ANALYZER_CAPTURE_DELAY_TIME, "ArkUIVideoUpdateAnalyzerOverlay");
2010 isContentSizeChanged_ = true;
2011 }
2012
2013 void VideoPattern::UpdateAnalyzerOverlay()
2014 {
2015 auto host = GetHost();
2016 CHECK_NULL_VOID(host);
2017 auto context = host->GetRenderContext();
2018 CHECK_NULL_VOID(context);
2019 auto nailPixelMap = context->GetThumbnailPixelMap();
2020 CHECK_NULL_VOID(nailPixelMap);
2021 auto pixelMap = nailPixelMap->GetCropPixelMap(contentRect_);
2022 CHECK_NULL_VOID(pixelMap);
2023 UpdateOverlayVisibility(VisibleType::VISIBLE);
2024
2025 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
2026 CHECK_NULL_VOID(layoutProperty);
2027 auto padding = layoutProperty->CreatePaddingAndBorder();
2028 OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
2029 contentRect_.Top() - padding.top.value_or(0) };
2030 CHECK_NULL_VOID(imageAnalyzerManager_);
2031 imageAnalyzerManager_->UpdateAnalyzerOverlay(pixelMap, contentOffset);
2032 }
2033
2034 void VideoPattern::UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)
2035 {
2036 if (IsSupportImageAnalyzer()) {
2037 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
2038 CHECK_NULL_VOID(layoutProperty);
2039 auto padding = layoutProperty->CreatePaddingAndBorder();
2040 OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
2041 contentRect_.Top() - padding.top.value_or(0) };
2042 PixelMapInfo info = { contentRect_.GetSize().Width(), contentRect_.GetSize().Height(), contentOffset };
2043 CHECK_NULL_VOID(imageAnalyzerManager_);
2044 imageAnalyzerManager_->UpdateAnalyzerUIConfig(geometryNode, info);
2045 }
2046 }
2047
2048 void VideoPattern::DestroyAnalyzerOverlay()
2049 {
2050 CHECK_NULL_VOID(imageAnalyzerManager_);
2051 imageAnalyzerManager_->DestroyAnalyzerOverlay();
2052 }
2053
2054 bool VideoPattern::GetAnalyzerState()
2055 {
2056 CHECK_NULL_RETURN(imageAnalyzerManager_, false);
2057 return imageAnalyzerManager_->IsOverlayCreated();
2058 }
2059
2060 void VideoPattern::UpdateOverlayVisibility(VisibleType type)
2061 {
2062 auto host = GetHost();
2063 CHECK_NULL_VOID(host);
2064 auto overlayNode = host->GetOverlayNode();
2065 CHECK_NULL_VOID(overlayNode);
2066 auto prop = overlayNode->GetLayoutProperty();
2067 CHECK_NULL_VOID(prop);
2068 prop->UpdateVisibility(type);
2069 }
2070
2071 void VideoPattern::OnWindowHide()
2072 {
2073 #if defined(OHOS_PLATFORM)
2074 if (!BackgroundTaskHelper::GetInstance().HasBackgroundTask()) {
2075 autoPlay_ = false;
2076 Pause();
2077 }
2078 #else
2079 Pause();
2080 #endif
2081 }
2082
2083 } // namespace OHOS::Ace::NG
2084