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