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