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