1/*
2 * Copyright (c) 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 <unistd.h>
17
18#include "movingphoto_pattern.h"
19#include "movingphoto_node.h"
20#include "movingphoto_utils.h"
21
22#include "base/image/pixel_map.h"
23#include "core/components_ng/pattern/image/image_pattern.h"
24
25namespace OHOS::Ace::NG {
26namespace {
27constexpr int32_t LONG_PRESS_DELAY = 300;
28constexpr int32_t ANIMATION_DURATION_300 = 300;
29constexpr int32_t ANIMATION_DURATION_400 = 400;
30constexpr float NORMAL_SCALE = 1.0f;
31constexpr float ZOOM_IN_SCALE = 1.1f;
32constexpr double NORMAL_PLAY_SPEED = 1.0;
33constexpr int32_t HALF = 2;
34constexpr int64_t PERIOD_START = 0;
35constexpr int32_t PREPARE_RETURN = 0;
36constexpr int64_t VIDEO_PLAYTIME_START_POSITION = 0;
37constexpr int64_t VIDEO_PLAYTIME_END_POSITION = 3000;
38constexpr int32_t IMAGE_LOADING_COMPLETE = 0;
39constexpr int32_t DURATION_FLAG = -1;
40const std::string THUMBNAIL_MEDIUM_JOINT = "?&oper=thumbnail&width=-1&height=-1&path=";
41const std::string COVER_POSITION = "cover_positon";
42const std::string IMAGE_URI = "uri";
43constexpr int32_t ANALYZER_DELAY_TIME = 100;
44constexpr int32_t ANALYZER_CAPTURE_DELAY_TIME = 1000;
45constexpr int32_t AVERAGE_VALUE = 2;
46}
47MovingPhotoPattern::MovingPhotoPattern(const RefPtr<MovingPhotoController>& controller)
48    : instanceId_(Container::CurrentId()), controller_(controller)
49{}
50
51void MovingPhotoPattern::OnModifyDone()
52{
53    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto onModifydone start.");
54    Pattern::OnModifyDone();
55    UpdateImageNode();
56    UpdateVideoNode();
57    if (SystemProperties::GetExtSurfaceEnabled()) {
58        auto pipelineContext = PipelineContext::GetCurrentContext();
59        CHECK_NULL_VOID(pipelineContext);
60        auto host = GetHost();
61        CHECK_NULL_VOID(host);
62        pipelineContext->AddOnAreaChangeNode(host->GetId());
63    }
64    InitEvent();
65    UpdatePlayMode();
66    HandleImageAnalyzerMode();
67}
68
69void MovingPhotoPattern::OnAttachToFrameNode()
70{
71    auto host = GetHost();
72    CHECK_NULL_VOID(host);
73    auto renderContext = host->GetRenderContext();
74    CHECK_NULL_VOID(renderContext);
75    static RenderContext::ContextParam param = { RenderContext::ContextType::HARDWARE_SURFACE, "MediaPlayerSurface",
76                                                 RenderContext::PatternType::VIDEO };
77    renderContextForMediaPlayer_->InitContext(false, param);
78    renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
79    renderContextForMediaPlayer_->UpdateBackgroundColor(Color::TRANSPARENT);
80    renderContext->SetClipToBounds(true);
81
82    auto pipelineContext = PipelineContext::GetCurrentContext();
83    CHECK_NULL_VOID(pipelineContext);
84    pipelineContext->AddWindowStateChangedCallback(host->GetId());
85
86    CHECK_NULL_VOID(controller_);
87    ContainerScope scope(instanceId_);
88    auto context = PipelineContext::GetCurrentContext();
89    CHECK_NULL_VOID(context);
90    auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
91    controller_->SetStartPlaybackImpl([weak = WeakClaim(this), uiTaskExecutor]() {
92        uiTaskExecutor.PostTask(
93            [weak]() {
94                auto pattern = weak.Upgrade();
95                CHECK_NULL_VOID(pattern);
96                ContainerScope scope(pattern->instanceId_);
97                pattern->StartPlayback();
98            },
99            "ArkUIMovingPhotoStart");
100    });
101
102    controller_->SetStopPlaybackImpl([weak = WeakClaim(this), uiTaskExecutor]() {
103        uiTaskExecutor.PostTask(
104            [weak]() {
105                auto pattern = weak.Upgrade();
106                CHECK_NULL_VOID(pattern);
107                ContainerScope scope(pattern->instanceId_);
108                pattern->StopPlayback();
109            },
110            "ArkUIMovingPhotoStop");
111    });
112
113    RegisterVisibleAreaChange();
114}
115
116void MovingPhotoPattern::OnDetachFromFrameNode(FrameNode* frameNode)
117{
118    auto id = frameNode->GetId();
119    auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
120    CHECK_NULL_VOID(pipeline);
121    pipeline->RemoveWindowStateChangedCallback(id);
122    hasVisibleChangeRegistered_ = false;
123}
124
125void MovingPhotoPattern::OnDetachFromMainTree()
126{
127    auto host = GetHost();
128    CHECK_NULL_VOID(host);
129    if (host->GetNodeStatus() == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
130        Stop();
131    }
132}
133
134void MovingPhotoPattern::OnRebuildFrame()
135{
136    if (!renderSurface_ || !renderSurface_->IsSurfaceValid()) {
137        return;
138    }
139    auto host = GetHost();
140    CHECK_NULL_VOID(host);
141    auto movingPhotoNode = AceType::DynamicCast<MovingPhotoNode>(host);
142    CHECK_NULL_VOID(movingPhotoNode);
143    auto video = AceType::DynamicCast<FrameNode>(movingPhotoNode->GetVideo());
144    CHECK_NULL_VOID(video);
145    auto renderContext = video->GetRenderContext();
146    renderContext->AddChild(renderContextForMediaPlayer_, 0);
147}
148
149void MovingPhotoPattern::InitEvent()
150{
151    auto host = GetHost();
152    CHECK_NULL_VOID(host);
153    auto gestureHub = host->GetOrCreateGestureEventHub();
154    CHECK_NULL_VOID(gestureHub);
155    if (longPressEvent_) {
156        gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
157        return;
158    }
159    auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
160        auto pattern = weak.Upgrade();
161        CHECK_NULL_VOID(pattern);
162        pattern->HandleLongPress(info);
163    };
164    longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
165    gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
166
167    if (touchEvent_) {
168        gestureHub->AddTouchEvent(touchEvent_);
169        return;
170    }
171    auto touchTask = [weak = WeakClaim(this)](TouchEventInfo& info) {
172        auto pattern = weak.Upgrade();
173        CHECK_NULL_VOID(pattern);
174        pattern->HandleTouchEvent(info);
175    };
176    touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
177    gestureHub->AddTouchEvent(touchEvent_);
178}
179
180void MovingPhotoPattern::LongPressEventModify(bool status)
181{
182    auto host = GetHost();
183    CHECK_NULL_VOID(host);
184    auto gestureHub = host->GetOrCreateGestureEventHub();
185    CHECK_NULL_VOID(gestureHub);
186    if (status) {
187        auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
188            auto pattern = weak.Upgrade();
189            CHECK_NULL_VOID(pattern);
190            pattern->HandleLongPress(info);
191        };
192        longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
193        gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
194    } else {
195        gestureHub->SetLongPressEvent(nullptr);
196        longPressEvent_ = nullptr;
197    }
198}
199
200void MovingPhotoPattern::HandleLongPress(GestureEvent& info)
201{
202    isFastKeyUp_ = false;
203    if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_ || isPlayByController_) {
204        return;
205    }
206    if (autoAndRepeatLevel_ == PlaybackMode::NONE && isEnableAnalyzer_) {
207        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleLongPress isEnableAnalyzer_ return.");
208        return;
209    }
210    if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
211        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleLongPress auto&Repeat return.");
212        return;
213    }
214    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto HandleLongPress start.");
215    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
216        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
217        FireMediaPlayerError();
218        return;
219    }
220    if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
221        mediaPlayer_->PrepareAsync();
222    }
223    if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
224        currentPlayStatus_ == PlaybackStatus::PAUSED)) {
225        isSetAutoPlayPeriod_ = false;
226        int32_t duration = DURATION_FLAG;
227        mediaPlayer_->GetDuration(duration);
228        SetAutoPlayPeriod(PERIOD_START, duration);
229    }
230    Start();
231}
232
233void MovingPhotoPattern::HandleTouchEvent(TouchEventInfo& info)
234{
235    if (currentPlayStatus_ == PlaybackStatus::ERROR) {
236        ResetMediaPlayer();
237    }
238    if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
239        TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "HandleTouchEvent auto&Repeat return.");
240        return;
241    }
242    if (!isPrepared_ || isPlayByController_) {
243        return;
244    }
245    if (autoAndRepeatLevel_ == PlaybackMode::NONE && isEnableAnalyzer_) {
246        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleTouchEvent isEnableAnalyzer_ return.");
247        return;
248    }
249    auto touchList = info.GetChangedTouches();
250    CHECK_NULL_VOID(!touchList.empty());
251    auto touchInfo = touchList.front();
252    auto touchType = touchInfo.GetTouchType();
253    isFastKeyUp_ = false;
254    if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
255        if (currentPlayStatus_ == PlaybackStatus::STARTED) {
256            PausePlayback();
257        } else if (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE) {
258            currentPlayStatus_ = PlaybackStatus::NONE;
259            StopAnimation();
260        } else {
261            isFastKeyUp_ = true;
262        }
263    }
264}
265
266void MovingPhotoPattern::UpdateImageNode()
267{
268    if (startAnimationFlag_) {
269        needUpdateImageNode_ = true;
270        return;
271    }
272    auto host = GetHost();
273    CHECK_NULL_VOID(host);
274    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
275    CHECK_NULL_VOID(movingPhoto);
276    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
277    CHECK_NULL_VOID(image);
278    ACE_UPDATE_NODE_PAINT_PROPERTY(ImageRenderProperty, DynamicMode, DynamicRangeMode::HIGH, image);
279    ACE_UPDATE_NODE_RENDER_CONTEXT(DynamicRangeMode, DynamicRangeMode::HIGH, image);
280    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto set HDR.");
281    auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
282    CHECK_NULL_VOID(layoutProperty);
283    if (!layoutProperty->HasImageSourceInfo()) {
284        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "image info is null.");
285        auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
286        posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
287        image->MarkModifyDone();
288        return;
289    }
290    auto imageSourceInfo = layoutProperty->GetImageSourceInfo().value();
291    auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
292    if (!imageSourceInfo.IsValid()) {
293        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "image info is invalid.");
294        auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
295        posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
296        image->MarkModifyDone();
297        return;
298    }
299    if (image) {
300        image->SetDraggable(false);
301        auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
302        imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
303        imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
304        imageLayoutProperty->UpdateImageFit(imageFit);
305        image->MarkModifyDone();
306    }
307    RegisterImageEvent();
308}
309
310void MovingPhotoPattern::RegisterImageEvent()
311{
312    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto RegisterImageEvent start.");
313    auto host = GetHost();
314    CHECK_NULL_VOID(host);
315    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
316    CHECK_NULL_VOID(movingPhoto);
317    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
318    CHECK_NULL_VOID(image);
319    auto imageHub = image->GetEventHub<ImageEventHub>();
320    CHECK_NULL_VOID(imageHub);
321    auto imageCompleteEventCallback = [weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
322        auto pattern = weak.Upgrade();
323        CHECK_NULL_VOID(pattern);
324        pattern->HandleImageCompleteEvent(info);
325    };
326    imageHub->SetOnComplete(imageCompleteEventCallback);
327}
328
329void MovingPhotoPattern::HandleImageCompleteEvent(const LoadImageSuccessEvent& info)
330{
331    auto loadingStatus = info.GetLoadingStatus();
332    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "HandleImageCompleteEvent start:%{public}d.", loadingStatus);
333    if (loadingStatus == IMAGE_LOADING_COMPLETE) {
334        FireMediaPlayerImageComplete();
335    }
336}
337
338void MovingPhotoPattern::UpdateVideoNode()
339{
340    ContainerScope scope(instanceId_);
341    auto pipelineContext = PipelineContext::GetCurrentContext();
342    CHECK_NULL_VOID(pipelineContext);
343    auto uiTaskExecutor = SingleTaskExecutor::Make(pipelineContext->GetTaskExecutor(), TaskExecutor::TaskType::UI);
344    uiTaskExecutor.PostTask(
345        [weak = WeakClaim(this)]() {
346            auto movingPhotoPattern = weak.Upgrade();
347            CHECK_NULL_VOID(movingPhotoPattern);
348            ContainerScope scope(movingPhotoPattern->instanceId_);
349            movingPhotoPattern->PrepareMediaPlayer();
350            movingPhotoPattern->UpdateMediaPlayerSpeed();
351            movingPhotoPattern->UpdateMediaPlayerMuted();
352        },
353        "ArkUIMovingPhotoUpdateVideo");
354}
355
356void MovingPhotoPattern::PrepareMediaPlayer()
357{
358    auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
359    CHECK_NULL_VOID(layoutProperty);
360    if (!layoutProperty->HasMovingPhotoUri() || !layoutProperty->HasVideoSource()) {
361        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto source is null.");
362        return;
363    }
364    if (layoutProperty->GetMovingPhotoUri().value() == uri_ &&
365        layoutProperty->GetVideoSource().value() == fd_) {
366        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer source has not changed.");
367        return;
368    }
369    uri_ = layoutProperty->GetMovingPhotoUri().value();
370    fd_ = layoutProperty->GetVideoSource().value();
371    if (!mediaPlayer_) {
372        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null.");
373        FireMediaPlayerError();
374        return;
375    }
376    if (!mediaPlayer_->IsMediaPlayerValid()) {
377        mediaPlayer_->CreateMediaPlayer();
378    }
379    if (!mediaPlayer_->IsMediaPlayerValid()) {
380        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is invalid.");
381        FireMediaPlayerError();
382        return;
383    }
384    ContainerScope scope(instanceId_);
385    auto context = PipelineContext::GetCurrentContext();
386    CHECK_NULL_VOID(context);
387    auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
388    platformTask.PostTask(
389        [weak = WeakClaim(this)] {
390            auto movingPhotoPattern = weak.Upgrade();
391            CHECK_NULL_VOID(movingPhotoPattern);
392            movingPhotoPattern->ResetMediaPlayer();
393        },
394        "ArkUIMovingPhotoPrepare");
395}
396
397void MovingPhotoPattern::ResetMediaPlayer()
398{
399    CHECK_NULL_VOID(mediaPlayer_);
400    isPrepared_ = false;
401    mediaPlayer_->ResetMediaPlayer();
402    RegisterMediaPlayerEvent();
403    if (!mediaPlayer_->SetSourceByFd(fd_)) {
404        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "set source for MediaPlayer failed.");
405        ContainerScope scope(instanceId_);
406        auto context = PipelineContext::GetCurrentContext();
407        CHECK_NULL_VOID(context);
408
409        auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
410        uiTaskExecutor.PostTask(
411            [weak = WeakClaim(this)] {
412                auto pattern = weak.Upgrade();
413                CHECK_NULL_VOID(pattern);
414                ContainerScope scope(pattern->instanceId_);
415                pattern->FireMediaPlayerError();
416            },
417            "ArkUIMovingPhotoReset");
418        return;
419    }
420}
421
422void MovingPhotoPattern::RegisterMediaPlayerEvent()
423{
424    if (fd_ == -1 || !mediaPlayer_) {
425        return;
426    }
427    ContainerScope scope(instanceId_);
428    auto context = PipelineContext::GetCurrentContext();
429    CHECK_NULL_VOID(context);
430    auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
431    auto movingPhotoPattern = WeakClaim(this);
432
433    auto&& positionUpdatedEvent = [movingPhotoPattern, uiTaskExecutor](uint32_t currentPos) {
434        uiTaskExecutor.PostTask([movingPhotoPattern, currentPos] {
435            auto movingPhoto = movingPhotoPattern.Upgrade();
436            CHECK_NULL_VOID(movingPhoto);
437            ContainerScope scope(movingPhoto->instanceId_);
438            movingPhoto->OnPlayPositionChanged(currentPos);
439        }, "ArkUIMovingPhotoPositionChanged");
440    };
441
442    auto&& stateChangedEvent = [movingPhotoPattern, uiTaskExecutor](PlaybackStatus status) {
443        uiTaskExecutor.PostTask([movingPhotoPattern, status] {
444            auto movingPhoto = movingPhotoPattern.Upgrade();
445            CHECK_NULL_VOID(movingPhoto);
446            ContainerScope scope(movingPhoto->instanceId_);
447            movingPhoto->OnMediaPlayerStatusChanged(status);
448        }, "ArkUIMovingPhotoStatusChanged");
449    };
450
451    auto&& errorEvent = [movingPhotoPattern, uiTaskExecutor]() {
452        uiTaskExecutor.PostSyncTask([movingPhotoPattern] {
453            auto movingPhoto = movingPhotoPattern.Upgrade();
454            CHECK_NULL_VOID(movingPhoto);
455            ContainerScope scope(movingPhoto->instanceId_);
456            movingPhoto->FireMediaPlayerError();
457        }, "ArkUIMovingPhotoOnError");
458    };
459
460    auto&& resolutionChangeEvent = [movingPhotoPattern, uiTaskExecutor]() {
461        uiTaskExecutor.PostTask([movingPhotoPattern] {
462            auto movingPhoto = movingPhotoPattern.Upgrade();
463            CHECK_NULL_VOID(movingPhoto);
464            ContainerScope scope(movingPhoto->instanceId_);
465            movingPhoto->OnResolutionChange();
466        }, "ArkUIMovingPhotoResolutionChanged");
467    };
468
469    auto&& startRenderFrameEvent = [movingPhotoPattern, uiTaskExecutor]() {
470        uiTaskExecutor.PostTask([movingPhotoPattern] {
471            auto movingPhoto = movingPhotoPattern.Upgrade();
472            CHECK_NULL_VOID(movingPhoto);
473            ContainerScope scope(movingPhoto->instanceId_);
474            movingPhoto->OnStartRenderFrame();
475        }, "ArkUIMovingPhotoStartRender");
476    };
477
478    mediaPlayer_->RegisterMediaPlayerEvent(
479        positionUpdatedEvent, stateChangedEvent, errorEvent, resolutionChangeEvent, startRenderFrameEvent);
480}
481
482void MovingPhotoPattern::PrepareSurface()
483{
484    if (!mediaPlayer_ || renderSurface_->IsSurfaceValid()) {
485        return;
486    }
487    if (!SystemProperties::GetExtSurfaceEnabled()) {
488        renderSurface_->SetRenderContext(renderContextForMediaPlayer_);
489    }
490    renderSurface_->InitSurface();
491    mediaPlayer_->SetRenderSurface(renderSurface_);
492    if (mediaPlayer_->SetSurface() != 0) {
493        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "prepare MediaPlayer failed.");
494    }
495}
496
497void MovingPhotoPattern::UpdatePlayMode()
498{
499    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto UpdatePlayMode.%{public}d", isChangePlayMode_);
500    if (isChangePlayMode_) {
501        if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
502            SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
503        }
504        MediaResetToPlay();
505        isChangePlayMode_ = false;
506    }
507}
508
509void MovingPhotoPattern::HandleImageAnalyzerMode()
510{
511    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto HandleImageAnalyzerMode.");
512    if (isEnableAnalyzer_ && autoAndRepeatLevel_ == PlaybackMode::NONE) {
513        if (!imageAnalyzerManager_) {
514            EnableAnalyzer(isEnableAnalyzer_);
515        }
516        if (imageAnalyzerManager_ && !GetAnalyzerState()) {
517            StartImageAnalyzer();
518        }
519    }
520    if (!isEnableAnalyzer_ && IsSupportImageAnalyzer()) {
521        DestroyAnalyzerOverlay();
522        LongPressEventModify(true);
523    }
524}
525
526void MovingPhotoPattern::MediaResetToPlay()
527{
528    autoAndRepeatLevel_ = historyAutoAndRepeatLevel_;
529    if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
530        mediaPlayer_->PrepareAsync();
531    } else if (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
532        currentPlayStatus_ == PlaybackStatus::PAUSED ||
533        currentPlayStatus_ == PlaybackStatus::PREPARED) {
534            SelectPlaybackMode(historyAutoAndRepeatLevel_);
535    }
536}
537
538void MovingPhotoPattern::FireMediaPlayerImageComplete()
539{
540    auto eventHub = GetEventHub<MovingPhotoEventHub>();
541    CHECK_NULL_VOID(eventHub);
542    eventHub->FireCompleteEvent();
543}
544
545void MovingPhotoPattern::FireMediaPlayerStart()
546{
547    auto eventHub = GetEventHub<MovingPhotoEventHub>();
548    CHECK_NULL_VOID(eventHub);
549    eventHub->FireStartEvent();
550    if (isFastKeyUp_) {
551        isFastKeyUp_ = false;
552        PausePlayback();
553    }
554}
555
556void MovingPhotoPattern::FireMediaPlayerStop()
557{
558    auto eventHub = GetEventHub<MovingPhotoEventHub>();
559    CHECK_NULL_VOID(eventHub);
560    eventHub->FireStopEvent();
561}
562
563void MovingPhotoPattern::FireMediaPlayerPause()
564{
565    auto eventHub = GetEventHub<MovingPhotoEventHub>();
566    CHECK_NULL_VOID(eventHub);
567    eventHub->FirePauseEvent();
568}
569
570void MovingPhotoPattern::FireMediaPlayerFinish()
571{
572    auto eventHub = GetEventHub<MovingPhotoEventHub>();
573    CHECK_NULL_VOID(eventHub);
574    eventHub->FireFinishEvent();
575}
576
577void MovingPhotoPattern::FireMediaPlayerError()
578{
579    auto eventHub = GetEventHub<MovingPhotoEventHub>();
580    CHECK_NULL_VOID(eventHub);
581    eventHub->FireErrorEvent();
582}
583
584void MovingPhotoPattern::OnResolutionChange()
585{
586    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
587        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
588        return;
589    }
590    auto host = GetHost();
591    CHECK_NULL_VOID(host);
592    SizeF videoSize =
593        SizeF(static_cast<float>(mediaPlayer_->GetVideoWidth()), static_cast<float>(mediaPlayer_->GetVideoHeight()));
594    auto movingPhotoLayoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
595    CHECK_NULL_VOID(movingPhotoLayoutProperty);
596    movingPhotoLayoutProperty->UpdateVideoSize(videoSize);
597    host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
598}
599
600void MovingPhotoPattern::OnStartRenderFrame()
601{
602    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartRenderFrame.");
603}
604
605void MovingPhotoPattern::OnStartedStatusCallback()
606{
607    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartedStatusCallback.");
608    ACE_FUNCTION_TRACE();
609    auto host = GetHost();
610    CHECK_NULL_VOID(host);
611    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
612    CHECK_NULL_VOID(movingPhoto);
613    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
614    CHECK_NULL_VOID(image);
615    StartAnimation();
616}
617
618bool MovingPhotoPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
619{
620    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartedStatusCallback.");
621    if (config.skipMeasure || dirty->SkipMeasureContent()) {
622        return false;
623    }
624    auto geometryNode = dirty->GetGeometryNode();
625    CHECK_NULL_RETURN(geometryNode, false);
626    auto movingPhotoNodeSize = geometryNode->GetContentSize();
627    auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
628    CHECK_NULL_RETURN(layoutProperty, false);
629    auto videoFrameSize = MeasureContentLayout(movingPhotoNodeSize, layoutProperty);
630    if (renderContextForMediaPlayer_) {
631        renderContextForMediaPlayer_->SetBounds((movingPhotoNodeSize.Width() - videoFrameSize.Width()) / HALF,
632            (movingPhotoNodeSize.Height() - videoFrameSize.Height()) / HALF, videoFrameSize.Width(),
633            videoFrameSize.Height());
634    }
635
636    if (IsSupportImageAnalyzer() && isEnableAnalyzer_ && autoAndRepeatLevel_ == PlaybackMode::NONE) {
637        if (imageAnalyzerManager_ && !GetAnalyzerState()) {
638            StartImageAnalyzer();
639        } else {
640            Rect tmpRect;
641            auto padding = layoutProperty->CreatePaddingAndBorder();
642            auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
643            if (imageFit == ImageFit::COVER || imageFit == ImageFit::NONE) {
644                tmpRect = Rect(padding.left.value_or(0), padding.top.value_or(0),
645                               movingPhotoNodeSize.Width(), movingPhotoNodeSize.Height());
646            } else {
647                tmpRect = Rect(
648                    (movingPhotoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE + padding.left.value_or(0),
649                    (movingPhotoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE + padding.top.value_or(0),
650                    videoFrameSize.Width(), videoFrameSize.Height());
651            }
652            contentRect_ = tmpRect;
653            UpdateAnalyzerUIConfig(geometryNode);
654        }
655    }
656    if (IsSupportImageAnalyzer() && !isEnableAnalyzer_) {
657        DestroyAnalyzerOverlay();
658        LongPressEventModify(true);
659    }
660
661    auto host = GetHost();
662    CHECK_NULL_RETURN(host, false);
663    host->MarkNeedSyncRenderTree();
664    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
665    CHECK_NULL_RETURN(movingPhoto, false);
666    auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
667    CHECK_NULL_RETURN(video, false);
668    video->GetRenderContext()->SetClipToBounds(true);
669    return false;
670}
671
672SizeF MovingPhotoPattern::CalculateFitContain(const SizeF& rawSize, const SizeF& layoutSize)
673{
674    if (NearZero(rawSize.Height()) || NearZero(rawSize.Width()) || NearZero(layoutSize.Height())) {
675        return layoutSize;
676    }
677    double sourceRatio = rawSize.Width() / rawSize.Height();
678    double layoutRatio = layoutSize.Width() / layoutSize.Height();
679    if (sourceRatio < layoutRatio) {
680        float ratio = layoutSize.Height() / rawSize.Height();
681        return { rawSize.Width() * ratio, layoutSize.Height() };
682    } else {
683        float ratio = layoutSize.Width() / rawSize.Width();
684        return { layoutSize.Width(), rawSize.Height() * ratio };
685    }
686}
687
688SizeF MovingPhotoPattern::CalculateFitFill(const SizeF& layoutSize)
689{
690    return layoutSize;
691}
692
693SizeF MovingPhotoPattern::CalculateFitCover(const SizeF& rawSize, const SizeF& layoutSize)
694{
695    if (NearZero(rawSize.Height()) || NearZero(rawSize.Width()) || NearZero(layoutSize.Height())) {
696        return layoutSize;
697    }
698    double sourceRatio = rawSize.Width() / rawSize.Height();
699    double layoutRatio = layoutSize.Width() / layoutSize.Height();
700    float ratio = 1.0;
701    if (sourceRatio < layoutRatio) {
702        ratio = static_cast<float>(layoutSize.Width() / rawSize.Width());
703    } else {
704        ratio = static_cast<float>(layoutSize.Height() / rawSize.Height());
705    }
706    return { rawSize.Width() * ratio, rawSize.Height() * ratio};
707}
708
709SizeF MovingPhotoPattern::CalculateFitNone(const SizeF& rawSize)
710{
711    return rawSize;
712}
713
714SizeF MovingPhotoPattern::CalculateFitScaleDown(const SizeF& rawSize, const SizeF& layoutSize)
715{
716    if ((rawSize.Width() <= layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
717        return CalculateFitNone(rawSize);
718    } else {
719        return CalculateFitContain(rawSize, layoutSize);
720    }
721}
722
723SizeF MovingPhotoPattern::CalculateFitAuto(const SizeF& rawSize, const SizeF& layoutSize)
724{
725    if (NearZero(rawSize.Width()) || NearZero(rawSize.Height())) {
726        return layoutSize;
727    }
728    if ((rawSize.Width() <= layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
729        double widthRatio = layoutSize.Width() / rawSize.Width();
730        double heightRatio = layoutSize.Height() / rawSize.Height();
731        float ratio = static_cast<float>(std::min(widthRatio, heightRatio));
732        return { rawSize.Width() * ratio, rawSize.Height() * ratio };
733    } else if ((rawSize.Width() > layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
734        return CalculateFitContain(rawSize, layoutSize);
735    } else {
736        return CalculateFitCover(rawSize, layoutSize);
737    }
738}
739
740SizeF MovingPhotoPattern::GetRawImageSize()
741{
742    auto host = GetHost();
743    CHECK_NULL_RETURN(host, SizeF(-1, -1));
744    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
745    CHECK_NULL_RETURN(movingPhoto, SizeF(-1, -1));
746    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
747    CHECK_NULL_RETURN(image, SizeF(-1, -1));
748    auto imagePattern = image->GetPattern<ImagePattern>();
749    CHECK_NULL_RETURN(image, SizeF(-1, -1));
750    return imagePattern->GetRawImageSize();
751}
752
753SizeF MovingPhotoPattern::MeasureContentLayout(const SizeF& layoutSize,
754    const RefPtr<MovingPhotoLayoutProperty>& layoutProperty)
755{
756    if (!layoutProperty || !layoutProperty->HasVideoSize()) {
757        return layoutSize;
758    }
759
760    auto rawImageSize = GetRawImageSize();
761    auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
762    SizeF contentSize = { 0.0, 0.0 };
763    switch (imageFit) {
764        case ImageFit::CONTAIN:
765            contentSize = CalculateFitContain(rawImageSize, layoutSize);
766            break;
767        case ImageFit::FILL:
768            contentSize = CalculateFitFill(layoutSize);
769            break;
770        case ImageFit::COVER:
771            contentSize = CalculateFitCover(rawImageSize, layoutSize);
772            break;
773        case ImageFit::NONE:
774            contentSize = CalculateFitNone(rawImageSize);
775            break;
776        case ImageFit::SCALE_DOWN:
777            contentSize = CalculateFitScaleDown(rawImageSize, layoutSize);
778            break;
779        default:
780            contentSize = CalculateFitAuto(rawImageSize, layoutSize);
781    }
782
783    return contentSize;
784}
785
786void MovingPhotoPattern::OnMediaPlayerStatusChanged(PlaybackStatus status)
787{
788    currentPlayStatus_ = status;
789    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is %{public}d.", status);
790    switch (status) {
791        case PlaybackStatus::ERROR:
792            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is ERROR.");
793            FireMediaPlayerError();
794            break;
795        case PlaybackStatus::IDLE:
796            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is IDLE.");
797            break;
798        case PlaybackStatus::INITIALIZED:
799            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is INITIALIZED.");
800            OnMediaPlayerInitialized();
801            break;
802        case PlaybackStatus::PREPARED:
803            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PREPARED.");
804            OnMediaPlayerPrepared();
805            break;
806        case PlaybackStatus::STARTED:
807            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is STARTED.");
808            OnStartedStatusCallback();
809            FireMediaPlayerStart();
810            break;
811        case PlaybackStatus::PAUSED:
812            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PAUSED.");
813            FireMediaPlayerPause();
814            break;
815        case PlaybackStatus::STOPPED:
816            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is STOPPED.");
817            OnMediaPlayerStoped();
818            break;
819        case PlaybackStatus::PLAYBACK_COMPLETE:
820            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PLAYBACK_COMPLETE.");
821            OnMediaPlayerCompletion();
822            break;
823        case PlaybackStatus::NONE:
824            TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is NONE.");
825            break;
826        default:
827            TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "Invalid player status.");
828            break;
829    }
830}
831
832void MovingPhotoPattern::OnMediaPlayerInitialized()
833{
834    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnMediaPlayerInitialized.");
835    if (!isSetAutoPlayPeriod_ && autoAndRepeatLevel_ == PlaybackMode::AUTO) {
836        isSetAutoPlayPeriod_ = true;
837        SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
838    }
839    PrepareSurface();
840    if (mediaPlayer_->PrepareAsync() != PREPARE_RETURN) {
841        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "prepare MediaPlayer failed.");
842    }
843}
844
845void MovingPhotoPattern::OnMediaPlayerPrepared()
846{
847    ContainerScope scope(instanceId_);
848    auto context = PipelineContext::GetCurrentContext();
849    CHECK_NULL_VOID(context);
850    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
851        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
852        return;
853    }
854    isPrepared_ = true;
855    Size videoSize = Size(mediaPlayer_->GetVideoWidth(), mediaPlayer_->GetVideoHeight());
856    auto host = GetHost();
857    CHECK_NULL_VOID(host);
858    auto videoLayoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
859    CHECK_NULL_VOID(videoLayoutProperty);
860    CHECK_NULL_VOID(mediaPlayer_);
861    videoLayoutProperty->UpdateVideoSize(
862        SizeF(static_cast<float>(videoSize.Width()), static_cast<float>(videoSize.Height())));
863    host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
864    UpdateMediaPlayerSpeed();
865    UpdateMediaPlayerMuted();
866    VisiblePlayback();
867}
868
869void MovingPhotoPattern::OnMediaPlayerStoped()
870{
871    isPlayByController_ = false;
872    FireMediaPlayerStop();
873}
874
875void MovingPhotoPattern::OnMediaPlayerCompletion()
876{
877    if (isPlayByController_ || autoAndRepeatLevel_ != PlaybackMode::NONE) {
878        isPlayByController_ = false;
879        StopAnimation();
880    }
881    FireMediaPlayerFinish();
882}
883
884void MovingPhotoPattern::HideImageNode()
885{
886    auto host = GetHost();
887    CHECK_NULL_VOID(host);
888    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
889    CHECK_NULL_VOID(movingPhoto);
890    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
891    CHECK_NULL_VOID(image);
892    auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
893    CHECK_NULL_VOID(imageLayoutProperty);
894    imageLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
895    image->MarkModifyDone();
896}
897
898void MovingPhotoPattern::VisiblePlayback()
899{
900    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto VisiblePlayback.");
901    if (!isVisible_) {
902        return;
903    }
904    if (historyAutoAndRepeatLevel_ != PlaybackMode::NONE &&
905        autoAndRepeatLevel_ == PlaybackMode::NONE) {
906        SelectPlaybackMode(historyAutoAndRepeatLevel_);
907    } else {
908        SelectPlaybackMode(autoAndRepeatLevel_);
909    }
910}
911
912void MovingPhotoPattern::SelectPlaybackMode(PlaybackMode mode)
913{
914    if (mode == PlaybackMode::REPEAT) {
915        StartRepeatPlay();
916    } else if (mode == PlaybackMode::AUTO) {
917        StartAutoPlay();
918    }
919}
920
921void MovingPhotoPattern::StartPlayback()
922{
923    if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_) {
924        return;
925    }
926    if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
927        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "StartPlayback autoAndRepeatLevel_:%{public}d.",
928            autoAndRepeatLevel_);
929        return;
930    }
931    if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
932        mediaPlayer_->PrepareAsync();
933    }
934    isPlayByController_ = true;
935    isFastKeyUp_ = false;
936    if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
937        currentPlayStatus_ == PlaybackStatus::PAUSED)) {
938        int32_t duration = DURATION_FLAG;
939        mediaPlayer_->GetDuration(duration);
940        TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "StartPlayback duration:%{public}d.",
941            duration);
942        SetAutoPlayPeriod(PERIOD_START, duration);
943    }
944    Start();
945}
946
947void MovingPhotoPattern::StartAnimation()
948{
949    if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
950        if (!isFirstRepeatPlay_) {
951            return;
952        }
953        isFirstRepeatPlay_ = false;
954    }
955    auto host = GetHost();
956    CHECK_NULL_VOID(host);
957    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
958    CHECK_NULL_VOID(movingPhoto);
959    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
960    CHECK_NULL_VOID(image);
961    auto imageRsContext = image->GetRenderContext();
962    CHECK_NULL_VOID(imageRsContext);
963    auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
964    CHECK_NULL_VOID(video);
965    auto videoRsContext = video->GetRenderContext();
966    CHECK_NULL_VOID(videoRsContext);
967
968    imageRsContext->UpdateOpacity(1.0);
969    imageRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
970    videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
971    auto movingPhotoPattern = WeakClaim(this);
972    AnimationOption animationOption;
973    animationOption.SetDuration(ANIMATION_DURATION_400);
974    animationOption.SetCurve(Curves::FRICTION);
975    animationOption.SetOnFinishEvent([movingPhotoPattern]() {
976        auto movingPhoto = movingPhotoPattern.Upgrade();
977        TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartAnimation OnFinishEvent.");
978        CHECK_NULL_VOID(movingPhoto);
979        if (movingPhoto->currentPlayStatus_ == PlaybackStatus::PAUSED
980            || movingPhoto->currentPlayStatus_ == PlaybackStatus::STOPPED
981            || !movingPhoto->startAnimationFlag_) {
982            return;
983        }
984        movingPhoto->HideImageNode();
985    });
986    startAnimationFlag_ = true;
987    AnimationUtils::Animate(animationOption,
988        [imageRsContext, videoRsContext, repeatFlag = historyAutoAndRepeatLevel_]() {
989            imageRsContext->UpdateOpacity(0.0);
990            imageRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
991            if (repeatFlag == PlaybackMode::REPEAT) {
992                videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
993            } else {
994                videoRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
995            }
996        }, animationOption.GetOnFinishEvent());
997}
998
999void MovingPhotoPattern::StopPlayback()
1000{
1001    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StopPlayback");
1002    isFastKeyUp_ = false;
1003    isPlayByController_ = false;
1004    Pause();
1005    autoAndRepeatLevel_ = PlaybackMode::NONE;
1006    if (historyAutoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1007        StopAnimation();
1008    }
1009}
1010
1011void MovingPhotoPattern::PausePlayback()
1012{
1013    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto PausePlayback");
1014    isFastKeyUp_ = false;
1015    if (currentPlayStatus_ != PlaybackStatus::STARTED || !isPrepared_) {
1016        return;
1017    }
1018    if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
1019        TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "PausePlayback autoAndRepeatLevel_:%{public}d.",
1020            autoAndRepeatLevel_);
1021        return;
1022    }
1023    isPlayByController_ = false;
1024    Pause();
1025    StopAnimation();
1026}
1027
1028void MovingPhotoPattern::StopAnimation()
1029{
1030    startAnimationFlag_ = false;
1031    if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1032        StopAnimationCallback();
1033        return;
1034    }
1035    auto host = GetHost();
1036    CHECK_NULL_VOID(host);
1037    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
1038    CHECK_NULL_VOID(movingPhoto);
1039    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
1040    CHECK_NULL_VOID(image);
1041    auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1042    CHECK_NULL_VOID(imageLayoutProperty);
1043    auto imageRsContext = image->GetRenderContext();
1044    CHECK_NULL_VOID(imageRsContext);
1045    auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
1046    CHECK_NULL_VOID(video);
1047    auto videoRsContext = video->GetRenderContext();
1048    CHECK_NULL_VOID(videoRsContext);
1049    videoRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
1050    video->MarkModifyDone();
1051
1052    imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1053    imageRsContext->UpdateOpacity(0.0);
1054    imageRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
1055    image->MarkModifyDone();
1056    auto movingPhotoPattern = WeakClaim(this);
1057    AnimationOption option;
1058    option.SetDuration(ANIMATION_DURATION_300);
1059    option.SetCurve(Curves::FRICTION);
1060    option.SetOnFinishEvent([movingPhotoPattern]() {
1061        auto movingPhoto = movingPhotoPattern.Upgrade();
1062        CHECK_NULL_VOID(movingPhoto);
1063        movingPhoto->StopAnimationCallback();
1064    });
1065    AnimationUtils::Animate(option, [imageRsContext, videoRsContext]() {
1066            imageRsContext->UpdateOpacity(1.0);
1067            imageRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
1068            videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
1069        }, option.GetOnFinishEvent());
1070}
1071
1072void MovingPhotoPattern::StopAnimationCallback()
1073{
1074    Seek(0);
1075    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "StopAnimation OnFinishEvent:%{public}d.", autoAndRepeatLevel_);
1076    if (needUpdateImageNode_) {
1077        UpdateImageNode();
1078        needUpdateImageNode_ = false;
1079    }
1080    if (autoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1081        StartRepeatPlay();
1082    } else if (autoAndRepeatLevel_ == PlaybackMode::AUTO) {
1083        autoAndRepeatLevel_ = PlaybackMode::NONE;
1084    }
1085    if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1086        HandleImageAnalyzerMode();
1087    }
1088}
1089
1090void MovingPhotoPattern::AutoPlay(bool isAutoPlay)
1091{
1092    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto AutoPlay: %{public}d.", isAutoPlay);
1093    if (isAutoPlay) {
1094        if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1095            return;
1096        }
1097        isChangePlayMode_ = true;
1098        if (autoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1099            historyAutoAndRepeatLevel_ = PlaybackMode::AUTO;
1100            autoAndRepeatLevel_ = PlaybackMode::AUTO;
1101            if (!isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
1102                currentPlayStatus_ == PlaybackStatus::PAUSED)) {
1103                isSetAutoPlayPeriod_ = true;
1104                SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
1105            }
1106        }
1107    }
1108}
1109
1110void MovingPhotoPattern::StartAutoPlay()
1111{
1112    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartAutoPlay in.");
1113    isFastKeyUp_ = false;
1114    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1115        return;
1116    }
1117
1118    if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1119        mediaPlayer_->PrepareAsync();
1120    }
1121    Start();
1122}
1123
1124void MovingPhotoPattern::StartRepeatPlay()
1125{
1126    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartRepeatPlay in.");
1127    isFastKeyUp_ = false;
1128    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1129        return;
1130    }
1131
1132    if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1133        mediaPlayer_->PrepareAsync();
1134    }
1135    if (!isFirstRepeatPlay_ && isSetAutoPlayPeriod_) {
1136        int32_t duration = DURATION_FLAG;
1137        mediaPlayer_->GetDuration(duration);
1138        SetAutoPlayPeriod(PERIOD_START, duration);
1139    }
1140    Start();
1141}
1142
1143void MovingPhotoPattern::RepeatPlay(bool isRepeatPlay)
1144{
1145    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto RepeatPlay status: %{public}d.", isRepeatPlay);
1146    if (isRepeatPlay && historyAutoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1147        isChangePlayMode_ = true;
1148        isFirstRepeatPlay_ = true;
1149    }
1150    if (!isRepeatPlay && historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1151        isChangePlayMode_ = true;
1152        historyAutoAndRepeatLevel_ = PlaybackMode::NONE;
1153        Pause();
1154        StopAnimation();
1155    }
1156    if (isRepeatPlay) {
1157        historyAutoAndRepeatLevel_ = PlaybackMode::REPEAT;
1158        autoAndRepeatLevel_ = PlaybackMode::REPEAT;
1159    }
1160}
1161
1162void MovingPhotoPattern::AutoPlayPeriod(int64_t startTime, int64_t endTime)
1163{
1164    if (startTime >= VIDEO_PLAYTIME_START_POSITION && startTime < endTime
1165            && endTime <= VIDEO_PLAYTIME_END_POSITION) {
1166        TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer set Period.");
1167        autoPlayPeriodStartTime_ = startTime;
1168        autoPlayPeriodEndTime_ = endTime;
1169    }
1170}
1171
1172void MovingPhotoPattern::SetAutoPlayPeriod(int64_t startTime, int64_t endTime)
1173{
1174    if (startTime < VIDEO_PLAYTIME_START_POSITION || startTime >= endTime
1175            || endTime > VIDEO_PLAYTIME_END_POSITION) {
1176        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer SetAutoPlayPeriod error.");
1177        return;
1178    }
1179    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1180        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1181        return;
1182    }
1183
1184    ContainerScope scope(instanceId_);
1185    auto context = PipelineContext::GetCurrentContext();
1186    CHECK_NULL_VOID(context);
1187
1188    mediaPlayer_->SetPlayRange(startTime, endTime);
1189}
1190
1191void MovingPhotoPattern::HandleImageAnalyzerPlayCallBack()
1192{
1193    TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleImageAnalyzerPlayCallBack start.");
1194    isFastKeyUp_ = false;
1195    if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_ || isPlayByController_) {
1196        return;
1197    }
1198    if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
1199        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleImageAnalyzerPlayCallBack auto&Repeat return.");
1200        return;
1201    }
1202    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1203        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1204        FireMediaPlayerError();
1205        return;
1206    }
1207    if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1208        mediaPlayer_->PrepareAsync();
1209    }
1210    if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
1211        currentPlayStatus_ == PlaybackStatus::PAUSED)) {
1212        int32_t duration = DURATION_FLAG;
1213        mediaPlayer_->GetDuration(duration);
1214        SetAutoPlayPeriod(PERIOD_START, duration);
1215    }
1216    Start();
1217}
1218
1219void MovingPhotoPattern::Start()
1220{
1221    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1222        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1223        return;
1224    }
1225    if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1226        mediaPlayer_->PrepareAsync();
1227    }
1228    ContainerScope scope(instanceId_);
1229    auto context = PipelineContext::GetCurrentContext();
1230    CHECK_NULL_VOID(context);
1231
1232    auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1233    platformTask.PostTask(
1234        [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1235            auto mediaPlayer = weak.Upgrade();
1236            CHECK_NULL_VOID(mediaPlayer);
1237            mediaPlayer->Play();
1238        },
1239        "ArkUIMovingPhotoStartPlay");
1240}
1241
1242void MovingPhotoPattern::Pause()
1243{
1244    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1245        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1246        return;
1247    }
1248    ContainerScope scope(instanceId_);
1249    auto context = PipelineContext::GetCurrentContext();
1250    CHECK_NULL_VOID(context);
1251
1252    auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1253    platformTask.PostTask(
1254        [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1255            auto mediaPlayer = weak.Upgrade();
1256            CHECK_NULL_VOID(mediaPlayer);
1257            mediaPlayer->Pause();
1258        },
1259        "ArkUIMovingPhotoPausePlay");
1260}
1261
1262void MovingPhotoPattern::Stop()
1263{
1264    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1265        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1266        return;
1267    }
1268    ContainerScope scope(instanceId_);
1269    auto context = PipelineContext::GetCurrentContext();
1270    CHECK_NULL_VOID(context);
1271
1272    auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1273    platformTask.PostTask(
1274        [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1275            auto mediaPlayer = weak.Upgrade();
1276            CHECK_NULL_VOID(mediaPlayer);
1277            mediaPlayer->Stop();
1278        },
1279        "ArkUIMovingPhotoStopPlay");
1280}
1281
1282void MovingPhotoPattern::Seek(int32_t position)
1283{
1284    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1285        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1286        return;
1287    }
1288    ContainerScope scope(instanceId_);
1289    auto context = PipelineContext::GetCurrentContext();
1290    CHECK_NULL_VOID(context);
1291
1292    auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1293    platformTask.PostTask(
1294        [weak = WeakClaim(RawPtr(mediaPlayer_)), pos = position] {
1295            auto mediaPlayer = weak.Upgrade();
1296            CHECK_NULL_VOID(mediaPlayer);
1297            mediaPlayer->Seek(pos, SeekMode::SEEK_PREVIOUS_SYNC);
1298        },
1299        "ArkUIMovingPhotoSeek");
1300}
1301
1302void MovingPhotoPattern::UpdateMediaPlayerSpeed()
1303{
1304    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1305        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1306        return;
1307    }
1308    ContainerScope scope(instanceId_);
1309    auto context = PipelineContext::GetCurrentContext();
1310    CHECK_NULL_VOID(context);
1311    auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1312    platformTask.PostTask(
1313        [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1314            auto mediaPlayer = weak.Upgrade();
1315            CHECK_NULL_VOID(mediaPlayer);
1316            mediaPlayer->SetPlaybackSpeed(static_cast<float>(NORMAL_PLAY_SPEED));
1317        },
1318        "ArkUIMovingPhotoUpdateSpeed");
1319}
1320
1321void MovingPhotoPattern::UpdateMediaPlayerMuted()
1322{
1323    if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1324        TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1325        return;
1326    }
1327    ContainerScope scope(instanceId_);
1328    float volume = isMuted_ ? 0.0f : 1.0f;
1329    auto context = PipelineContext::GetCurrentContext();
1330    CHECK_NULL_VOID(context);
1331    auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1332    platformTask.PostTask(
1333        [weak = WeakClaim(RawPtr(mediaPlayer_)), videoVolume = volume] {
1334            auto mediaPlayer = weak.Upgrade();
1335            CHECK_NULL_VOID(mediaPlayer);
1336            mediaPlayer->SetVolume(videoVolume, videoVolume);
1337        },
1338        "ArkUIMovingPhotoUpdateMuted");
1339}
1340
1341void MovingPhotoPattern::OnAreaChangedInner()
1342{
1343    if (!SystemProperties::GetExtSurfaceEnabled()) {
1344        return;
1345    }
1346    auto host = GetHost();
1347    CHECK_NULL_VOID(host);
1348    auto geometryNode = host->GetGeometryNode();
1349    CHECK_NULL_VOID(geometryNode);
1350    auto videoNodeSize = geometryNode->GetContentSize();
1351    auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1352    CHECK_NULL_VOID(layoutProperty);
1353    auto videoFrameSize = MeasureContentLayout(videoNodeSize, layoutProperty);
1354    auto transformRelativeOffset = host->GetTransformRelativeOffset();
1355
1356    Rect rect = Rect(transformRelativeOffset.GetX() + (videoNodeSize.Width() - videoFrameSize.Width()) / HALF,
1357        transformRelativeOffset.GetY() + (videoNodeSize.Height() - videoFrameSize.Height()) / HALF,
1358        videoFrameSize.Width(), videoFrameSize.Height());
1359    if (renderSurface_ && (rect != lastBoundsRect_)) {
1360        renderSurface_->SetExtSurfaceBounds(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1361        lastBoundsRect_ = rect;
1362    }
1363}
1364
1365void MovingPhotoPattern::OnVisibleChange(bool isVisible)
1366{
1367    CHECK_NULL_VOID(mediaPlayer_);
1368    if (!isVisible) {
1369        StopPlayback();
1370    }
1371}
1372
1373void MovingPhotoPattern::OnWindowHide()
1374{
1375    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto OnWindowHide.");
1376    if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1377        PausePlayback();
1378    } else if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1379        StopPlayback();
1380        return;
1381    }
1382    auto host = GetHost();
1383    CHECK_NULL_VOID(host);
1384    auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
1385    CHECK_NULL_VOID(movingPhoto);
1386    auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
1387    CHECK_NULL_VOID(image);
1388    auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1389    CHECK_NULL_VOID(imageLayoutProperty);
1390    imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1391    auto rsContext = image->GetRenderContext();
1392    CHECK_NULL_VOID(rsContext);
1393    rsContext->UpdateOpacity(1.0);
1394    image->MarkModifyDone();
1395}
1396
1397void MovingPhotoPattern::OnWindowShow()
1398{
1399    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto OnWindowShow.");
1400    CHECK_NULL_VOID(mediaPlayer_);
1401    if (autoAndRepeatLevel_ == PlaybackMode::REPEAT && currentPlayStatus_ == PlaybackStatus::STOPPED) {
1402        mediaPlayer_->PrepareAsync();
1403    }
1404}
1405
1406void MovingPhotoPattern::RegisterVisibleAreaChange()
1407{
1408    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto RegisterVisibleAreaChange.");
1409    if (hasVisibleChangeRegistered_) {
1410        return;
1411    }
1412    auto pipeline = PipelineContext::GetCurrentContextSafely();
1413    CHECK_NULL_VOID(pipeline);
1414    auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
1415        auto pattern = weak.Upgrade();
1416        CHECK_NULL_VOID(pattern);
1417        pattern->isVisible_ = visible;
1418        pattern->VisibleAreaCallback(visible);
1419    };
1420    auto host = GetHost();
1421    CHECK_NULL_VOID(host);
1422    std::vector<double> ratioList = {1.0};
1423    pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false);
1424    hasVisibleChangeRegistered_ = true;
1425}
1426
1427void MovingPhotoPattern::VisibleAreaCallback(bool visible)
1428{
1429    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto VisibleAreaCallback:%{public}d.", visible);
1430    if (visible) {
1431        if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1432            SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
1433        }
1434        MediaResetToPlay();
1435    } else {
1436        if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1437            PausePlayback();
1438        } else if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1439            StopPlayback();
1440        }
1441    }
1442}
1443
1444void MovingPhotoPattern::EnableAnalyzer(bool enable)
1445{
1446    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto EnableAnalyzer:%{public}d.", enable);
1447    isEnableAnalyzer_ = enable;
1448    if (!isEnableAnalyzer_) {
1449        DestroyAnalyzerOverlay();
1450        LongPressEventModify(true);
1451        return;
1452    }
1453
1454    CHECK_NULL_VOID(!imageAnalyzerManager_);
1455    auto host = GetHost();
1456    CHECK_NULL_VOID(host);
1457    imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(host, ImageAnalyzerHolder::MOVINGPHOTO);
1458}
1459
1460void MovingPhotoPattern::SetImageAIOptions(void* options)
1461{
1462    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto SetImageAIOptions");
1463    if (!imageAnalyzerManager_) {
1464        imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::MOVINGPHOTO);
1465    }
1466    CHECK_NULL_VOID(imageAnalyzerManager_);
1467    imageAnalyzerManager_->SetImageAIOptions(options);
1468}
1469
1470bool MovingPhotoPattern::IsSupportImageAnalyzer()
1471{
1472    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto IsSupportImageAnalyzer");
1473    auto host = GetHost();
1474    CHECK_NULL_RETURN(host, false);
1475    auto layoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
1476    CHECK_NULL_RETURN(layoutProperty, false);
1477    CHECK_NULL_RETURN(imageAnalyzerManager_, false);
1478    return imageAnalyzerManager_->IsSupportImageAnalyzerFeature();
1479}
1480
1481bool MovingPhotoPattern::ShouldUpdateImageAnalyzer()
1482{
1483    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto ShouldUpdateImageAnalyzer");
1484    auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1485    CHECK_NULL_RETURN(layoutProperty, false);
1486    const auto& constraint = layoutProperty->GetCalcLayoutConstraint();
1487    if (!constraint || !constraint->selfIdealSize.has_value() || !constraint->selfIdealSize->IsValid()) {
1488        return false;
1489    }
1490    auto selfIdealSize = constraint->selfIdealSize;
1491    if (!selfIdealSize->PercentWidth() && !selfIdealSize->PercentHeight()) {
1492        return false;
1493    }
1494    auto imageFit = layoutProperty->GetObjectFit().value_or(ImageFit::COVER);
1495    if (imageFit != ImageFit::COVER && imageFit != ImageFit::NONE) {
1496        return false;
1497    }
1498    return true;
1499}
1500
1501void MovingPhotoPattern::StartImageAnalyzer()
1502{
1503    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartImageAnalyzer");
1504    if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_) {
1505        return;
1506    }
1507
1508    if (imageAnalyzerManager_->IsOverlayCreated()) {
1509        DestroyAnalyzerOverlay();
1510        LongPressEventModify(true);
1511    }
1512
1513    ContainerScope scope(instanceId_);
1514    auto host = GetHost();
1515    CHECK_NULL_VOID(host);
1516    auto context = host->GetContext();
1517    CHECK_NULL_VOID(context);
1518    auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1519    uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
1520        auto pattern = weak.Upgrade();
1521        CHECK_NULL_VOID(pattern);
1522        pattern->CreateAnalyzerOverlay();
1523        }, ANALYZER_DELAY_TIME, "ArkUIMovingPhotoCreateAnalyzerOverlay");
1524    LongPressEventModify(false);
1525}
1526
1527void MovingPhotoPattern::CreateAnalyzerOverlay()
1528{
1529    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto CreateAnalyzerOverlay");
1530    CHECK_NULL_VOID(imageAnalyzerManager_);
1531    if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_->IsOverlayCreated()) {
1532        return;
1533    }
1534    GetPixelMap();
1535    int64_t coverPosition = GetUriCoverPosition();
1536    auto onCanPlay = [weak = AceType::WeakClaim(this)](bool canPlay) {
1537        auto pattern = weak.Upgrade();
1538        CHECK_NULL_VOID(pattern);
1539        pattern->HandleAnalyzerPlayEvent(canPlay);
1540    };
1541    auto host = GetHost();
1542    CHECK_NULL_VOID(host);
1543    auto geometryNode = host->GetGeometryNode();
1544    CHECK_NULL_VOID(geometryNode);
1545    auto movingPhotoNodeSize = geometryNode->GetContentSize();
1546    MovingPhotoAnalyzerInfo info = {uri_, coverPosition,
1547                                    movingPhotoNodeSize.Width(),
1548                                    movingPhotoNodeSize.Height()};
1549    imageAnalyzerManager_->SetOnCanPlayCallback(std::move(onCanPlay));
1550    imageAnalyzerManager_->CreateMovingPhotoAnalyzerOverlay(pixelMap_, info);
1551}
1552
1553void MovingPhotoPattern::StartUpdateImageAnalyzer()
1554{
1555    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartUpdateImageAnalyzer");
1556    CHECK_NULL_VOID(imageAnalyzerManager_);
1557    if (!imageAnalyzerManager_->IsOverlayCreated()) {
1558        return;
1559    }
1560
1561    UpdateOverlayVisibility(VisibleType::GONE);
1562    ContainerScope scope(instanceId_);
1563    auto host = GetHost();
1564    CHECK_NULL_VOID(host);
1565    auto context = host->GetContext();
1566    CHECK_NULL_VOID(context);
1567    auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1568    uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
1569        auto pattern = weak.Upgrade();
1570        CHECK_NULL_VOID(pattern);
1571        if (!pattern->isContentSizeChanged_) {
1572            return;
1573        }
1574        pattern->UpdateAnalyzerOverlay();
1575        pattern->isContentSizeChanged_ = false;
1576        }, ANALYZER_CAPTURE_DELAY_TIME, "ArkUIMovingPhotoUpdateAnalyzerOverlay");
1577    isContentSizeChanged_ = true;
1578}
1579
1580void MovingPhotoPattern::UpdateAnalyzerOverlay()
1581{
1582    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto UpdateAnalyzerOverlay");
1583    CHECK_NULL_VOID(imageAnalyzerManager_);
1584    if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_->IsOverlayCreated()) {
1585        return;
1586    }
1587    GetPixelMap();
1588    int64_t coverPosition = GetUriCoverPosition();
1589    UpdateOverlayVisibility(VisibleType::VISIBLE);
1590    auto host = GetHost();
1591    CHECK_NULL_VOID(host);
1592    auto geometryNode = host->GetGeometryNode();
1593    CHECK_NULL_VOID(geometryNode);
1594    auto movingPhotoNodeSize = geometryNode->GetContentSize();
1595    MovingPhotoAnalyzerInfo info = {uri_, coverPosition,
1596                                    movingPhotoNodeSize.Width(),
1597                                    movingPhotoNodeSize.Height()};
1598    imageAnalyzerManager_->UpdateMovingPhotoAnalyzerOverlay(pixelMap_, info);
1599}
1600
1601void MovingPhotoPattern::UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)
1602{
1603    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto UpdateAnalyzerUIConfig");
1604    if (IsSupportImageAnalyzer()) {
1605        auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1606        CHECK_NULL_VOID(layoutProperty);
1607        auto padding  = layoutProperty->CreatePaddingAndBorder();
1608        OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
1609                                  contentRect_.Top() - padding.top.value_or(0) };
1610        PixelMapInfo info = { contentRect_.GetSize().Width(), contentRect_.GetSize().Height(), contentOffset };
1611        CHECK_NULL_VOID(imageAnalyzerManager_);
1612        imageAnalyzerManager_->UpdateAnalyzerUIConfig(geometryNode, info);
1613    }
1614}
1615
1616void MovingPhotoPattern::DestroyAnalyzerOverlay()
1617{
1618    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto DestroyAnalyzerOverlay");
1619    CHECK_NULL_VOID(imageAnalyzerManager_);
1620    imageAnalyzerManager_->DestroyAnalyzerOverlay();
1621}
1622
1623bool MovingPhotoPattern::GetAnalyzerState()
1624{
1625    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto GetAnalyzerState");
1626    CHECK_NULL_RETURN(imageAnalyzerManager_, false);
1627    return imageAnalyzerManager_->IsOverlayCreated();
1628}
1629
1630void MovingPhotoPattern::UpdateOverlayVisibility(VisibleType type)
1631{
1632    auto host = GetHost();
1633    CHECK_NULL_VOID(host);
1634    auto overlayNode = host->GetOverlayNode();
1635    CHECK_NULL_VOID(overlayNode);
1636    auto prop = overlayNode->GetLayoutProperty();
1637    CHECK_NULL_VOID(prop);
1638    prop->UpdateVisibility(type);
1639}
1640
1641void MovingPhotoPattern::GetPixelMap()
1642{
1643    auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1644    CHECK_NULL_VOID(layoutProperty);
1645    if (!layoutProperty->HasMovingPhotoUri() || !layoutProperty->HasVideoSource()) {
1646        TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "GetPixelMap MovingPhoto source is null.");
1647        return;
1648    }
1649    auto pipeline = PipelineBase::GetCurrentContext();
1650    CHECK_NULL_VOID(pipeline);
1651    auto dataProvider = AceType::DynamicCast<DataProviderManagerStandard>(pipeline->GetDataProviderManager());
1652    CHECK_NULL_VOID(dataProvider);
1653    std::string imageSrc = dataProvider->GetMovingPhotoImagePath(uri_);
1654    std::string thumbnailUrl = uri_ + THUMBNAIL_MEDIUM_JOINT + imageSrc;
1655    void* pixelMapMediauniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(thumbnailUrl);
1656    CHECK_NULL_VOID(pixelMapMediauniquePtr);
1657    auto pixelMap = PixelMap::CreatePixelMapFromDataAbility(pixelMapMediauniquePtr);
1658    CHECK_NULL_VOID(pixelMap);
1659    pixelMap_ = pixelMap;
1660}
1661
1662int64_t MovingPhotoPattern::GetUriCoverPosition()
1663{
1664    auto pipeline = PipelineBase::GetCurrentContext();
1665    CHECK_NULL_RETURN(pipeline, -1);
1666    auto dataProvider = AceType::DynamicCast<DataProviderManagerStandard>(pipeline->GetDataProviderManager());
1667    CHECK_NULL_RETURN(dataProvider, -1);
1668    std::vector<std::string> columns = {COVER_POSITION};
1669    auto result = dataProvider->GetMovingPhotoCoverPosition(IMAGE_URI, uri_, columns);
1670    return result;
1671}
1672
1673void MovingPhotoPattern::HandleAnalyzerPlayEvent(bool canPlay)
1674{
1675    TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto HandleAnalyzerPlayEvent:%{public}d", canPlay);
1676    if (isAnalyzerPlaying_ && !canPlay) {
1677        Pause();
1678        StopAnimation();
1679    }
1680    isAnalyzerPlaying_ = canPlay;
1681    if (canPlay) {
1682        HandleImageAnalyzerPlayCallBack();
1683    }
1684}
1685
1686MovingPhotoPattern::~MovingPhotoPattern()
1687{
1688    if (IsSupportImageAnalyzer()) {
1689        TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "~MovingPhotoPattern DestroyAnalyzerOverlay.");
1690        DestroyAnalyzerOverlay();
1691    }
1692    if (fd_ > 0) {
1693        close(fd_);
1694    }
1695}
1696} // namespace OHOS::Ace::NG