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