• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/components_ng/pattern/image/image_pattern.h"
23 
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr int32_t LONG_PRESS_DELAY = 300;
27 constexpr int32_t ANIMATION_DURATION_300 = 300;
28 constexpr int32_t ANIMATION_DURATION_400 = 400;
29 constexpr float NORMAL_SCALE = 1.0f;
30 constexpr float ZOOM_IN_SCALE = 1.1f;
31 constexpr double NORMAL_PLAY_SPEED = 1.0;
32 constexpr int32_t HALF = 2;
33 constexpr int64_t PERIOD_START = 0;
34 constexpr int32_t PREPARE_RETURN = 0;
35 constexpr int64_t VIDEO_PLAYTIME_START_POSITION = 0;
36 constexpr int64_t VIDEO_PLAYTIME_END_POSITION = 3000;
37 constexpr int32_t IMAGE_LOADING_COMPLETE = 0;
38 constexpr int32_t DURATION_FLAG = -1;
39 }
MovingPhotoPattern(const RefPtr<MovingPhotoController> & controller)40 MovingPhotoPattern::MovingPhotoPattern(const RefPtr<MovingPhotoController>& controller)
41     : instanceId_(Container::CurrentId()), controller_(controller)
42 {}
43 
OnModifyDone()44 void MovingPhotoPattern::OnModifyDone()
45 {
46     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto onModifydone start.");
47     Pattern::OnModifyDone();
48     UpdateImageNode();
49     UpdateVideoNode();
50     if (SystemProperties::GetExtSurfaceEnabled()) {
51         auto pipelineContext = PipelineContext::GetCurrentContext();
52         CHECK_NULL_VOID(pipelineContext);
53         auto host = GetHost();
54         CHECK_NULL_VOID(host);
55         pipelineContext->AddOnAreaChangeNode(host->GetId());
56     }
57     InitEvent();
58     UpdatePlayMode();
59 }
60 
OnAttachToFrameNode()61 void MovingPhotoPattern::OnAttachToFrameNode()
62 {
63     auto host = GetHost();
64     CHECK_NULL_VOID(host);
65     auto renderContext = host->GetRenderContext();
66     CHECK_NULL_VOID(renderContext);
67     static RenderContext::ContextParam param = { RenderContext::ContextType::HARDWARE_SURFACE, "MediaPlayerSurface",
68                                                  RenderContext::PatternType::VIDEO };
69     renderContextForMediaPlayer_->InitContext(false, param);
70     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
71     renderContextForMediaPlayer_->UpdateBackgroundColor(Color::TRANSPARENT);
72     renderContext->SetClipToBounds(true);
73 
74     auto pipelineContext = PipelineContext::GetCurrentContext();
75     CHECK_NULL_VOID(pipelineContext);
76     pipelineContext->AddWindowStateChangedCallback(host->GetId());
77 
78     CHECK_NULL_VOID(controller_);
79     ContainerScope scope(instanceId_);
80     auto context = PipelineContext::GetCurrentContext();
81     CHECK_NULL_VOID(context);
82     auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
83     controller_->SetStartPlaybackImpl([weak = WeakClaim(this), uiTaskExecutor]() {
84         uiTaskExecutor.PostTask(
85             [weak]() {
86                 auto pattern = weak.Upgrade();
87                 CHECK_NULL_VOID(pattern);
88                 ContainerScope scope(pattern->instanceId_);
89                 pattern->StartPlayback();
90             },
91             "ArkUIMovingPhotoStart");
92     });
93 
94     controller_->SetStopPlaybackImpl([weak = WeakClaim(this), uiTaskExecutor]() {
95         uiTaskExecutor.PostTask(
96             [weak]() {
97                 auto pattern = weak.Upgrade();
98                 CHECK_NULL_VOID(pattern);
99                 ContainerScope scope(pattern->instanceId_);
100                 pattern->StopPlayback();
101             },
102             "ArkUIMovingPhotoStop");
103     });
104 
105     RegisterVisibleAreaChange();
106 }
107 
OnDetachFromFrameNode(FrameNode * frameNode)108 void MovingPhotoPattern::OnDetachFromFrameNode(FrameNode* frameNode)
109 {
110     auto id = frameNode->GetId();
111     auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
112     CHECK_NULL_VOID(pipeline);
113     pipeline->RemoveWindowStateChangedCallback(id);
114     hasVisibleChangeRegistered_ = false;
115 }
116 
OnDetachFromMainTree()117 void MovingPhotoPattern::OnDetachFromMainTree()
118 {
119     auto host = GetHost();
120     CHECK_NULL_VOID(host);
121     if (host->GetNodeStatus() == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
122         Stop();
123     }
124 }
125 
OnRebuildFrame()126 void MovingPhotoPattern::OnRebuildFrame()
127 {
128     if (!renderSurface_ || !renderSurface_->IsSurfaceValid()) {
129         return;
130     }
131     auto host = GetHost();
132     CHECK_NULL_VOID(host);
133     auto movingPhotoNode = AceType::DynamicCast<MovingPhotoNode>(host);
134     CHECK_NULL_VOID(movingPhotoNode);
135     auto video = AceType::DynamicCast<FrameNode>(movingPhotoNode->GetVideo());
136     CHECK_NULL_VOID(video);
137     auto renderContext = video->GetRenderContext();
138     renderContext->AddChild(renderContextForMediaPlayer_, 0);
139 }
140 
InitEvent()141 void MovingPhotoPattern::InitEvent()
142 {
143     auto host = GetHost();
144     CHECK_NULL_VOID(host);
145     auto gestureHub = host->GetOrCreateGestureEventHub();
146     CHECK_NULL_VOID(gestureHub);
147     if (longPressEvent_) {
148         gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
149         return;
150     }
151     auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
152         auto pattern = weak.Upgrade();
153         CHECK_NULL_VOID(pattern);
154         pattern->HandleLongPress(info);
155     };
156     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
157     gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
158 
159     if (touchEvent_) {
160         gestureHub->AddTouchEvent(touchEvent_);
161         return;
162     }
163     auto touchTask = [weak = WeakClaim(this)](TouchEventInfo& info) {
164         auto pattern = weak.Upgrade();
165         CHECK_NULL_VOID(pattern);
166         pattern->HandleTouchEvent(info);
167     };
168     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
169     gestureHub->AddTouchEvent(touchEvent_);
170 }
171 
HandleLongPress(GestureEvent & info)172 void MovingPhotoPattern::HandleLongPress(GestureEvent& info)
173 {
174     isFastKeyUp_ = false;
175     if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_ || isPlayByController_) {
176         return;
177     }
178     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
179         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleLongPress auto&Repeat return.");
180         return;
181     }
182     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto HandleLongPress start.");
183     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
184         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
185         FireMediaPlayerError();
186         return;
187     }
188     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
189         mediaPlayer_->PrepareAsync();
190     }
191     if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
192         currentPlayStatus_ == PlaybackStatus::PAUSED)) {
193         isSetAutoPlayPeriod_ = false;
194         int32_t duration = DURATION_FLAG;
195         mediaPlayer_->GetDuration(duration);
196         SetAutoPlayPeriod(PERIOD_START, duration);
197     }
198     Start();
199 }
200 
HandleTouchEvent(TouchEventInfo & info)201 void MovingPhotoPattern::HandleTouchEvent(TouchEventInfo& info)
202 {
203     if (currentPlayStatus_ == PlaybackStatus::ERROR) {
204         ResetMediaPlayer();
205     }
206     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
207         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "HandleLongPress auto&Repeat return.");
208         return;
209     }
210     if (!isPrepared_ || isPlayByController_) {
211         return;
212     }
213     auto touchList = info.GetChangedTouches();
214     CHECK_NULL_VOID(!touchList.empty());
215     auto touchInfo = touchList.front();
216     auto touchType = touchInfo.GetTouchType();
217     isFastKeyUp_ = false;
218     if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
219         if (currentPlayStatus_ == PlaybackStatus::STARTED) {
220             PausePlayback();
221         } else if (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE) {
222             currentPlayStatus_ = PlaybackStatus::NONE;
223             StopAnimation();
224         } else {
225             isFastKeyUp_ = true;
226         }
227     }
228 }
229 
UpdateImageNode()230 void MovingPhotoPattern::UpdateImageNode()
231 {
232     if (startAnimationFlag_) {
233         needUpdateImageNode_ = true;
234         return;
235     }
236     auto host = GetHost();
237     CHECK_NULL_VOID(host);
238     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
239     CHECK_NULL_VOID(movingPhoto);
240     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
241     CHECK_NULL_VOID(image);
242     ACE_UPDATE_NODE_PAINT_PROPERTY(ImageRenderProperty, DynamicMode, DynamicRangeMode::HIGH, image);
243     ACE_UPDATE_NODE_RENDER_CONTEXT(DynamicRangeMode, DynamicRangeMode::HIGH, image);
244     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto set HDR.");
245     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
246     CHECK_NULL_VOID(layoutProperty);
247     if (!layoutProperty->HasImageSourceInfo()) {
248         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "image info is null.");
249         auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
250         posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
251         image->MarkModifyDone();
252         return;
253     }
254     auto imageSourceInfo = layoutProperty->GetImageSourceInfo().value();
255     auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
256     if (!imageSourceInfo.IsValid()) {
257         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "image info is invalid.");
258         auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
259         posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
260         image->MarkModifyDone();
261         return;
262     }
263     if (image) {
264         image->SetDraggable(false);
265         auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
266         imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
267         imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
268         imageLayoutProperty->UpdateImageFit(imageFit);
269         image->MarkModifyDone();
270     }
271     RegisterImageEvent();
272 }
273 
RegisterImageEvent()274 void MovingPhotoPattern::RegisterImageEvent()
275 {
276     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto RegisterImageEvent start.");
277     auto host = GetHost();
278     CHECK_NULL_VOID(host);
279     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
280     CHECK_NULL_VOID(movingPhoto);
281     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
282     CHECK_NULL_VOID(image);
283     auto imageHub = image->GetEventHub<ImageEventHub>();
284     CHECK_NULL_VOID(imageHub);
285     auto imageCompleteEventCallback = [weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
286         auto pattern = weak.Upgrade();
287         CHECK_NULL_VOID(pattern);
288         pattern->HandleImageCompleteEvent(info);
289     };
290     imageHub->SetOnComplete(imageCompleteEventCallback);
291 }
292 
HandleImageCompleteEvent(const LoadImageSuccessEvent & info)293 void MovingPhotoPattern::HandleImageCompleteEvent(const LoadImageSuccessEvent& info)
294 {
295     auto loadingStatus = info.GetLoadingStatus();
296     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "HandleImageCompleteEvent start:%{public}d.", loadingStatus);
297     if (loadingStatus == IMAGE_LOADING_COMPLETE) {
298         FireMediaPlayerImageComplete();
299     }
300 }
301 
UpdateVideoNode()302 void MovingPhotoPattern::UpdateVideoNode()
303 {
304     ContainerScope scope(instanceId_);
305     auto pipelineContext = PipelineContext::GetCurrentContext();
306     CHECK_NULL_VOID(pipelineContext);
307     auto uiTaskExecutor = SingleTaskExecutor::Make(pipelineContext->GetTaskExecutor(), TaskExecutor::TaskType::UI);
308     uiTaskExecutor.PostTask(
309         [weak = WeakClaim(this)]() {
310             auto movingPhotoPattern = weak.Upgrade();
311             CHECK_NULL_VOID(movingPhotoPattern);
312             ContainerScope scope(movingPhotoPattern->instanceId_);
313             movingPhotoPattern->PrepareMediaPlayer();
314             movingPhotoPattern->UpdateMediaPlayerSpeed();
315             movingPhotoPattern->UpdateMediaPlayerMuted();
316         },
317         "ArkUIMovingPhotoUpdateVideo");
318 }
319 
PrepareMediaPlayer()320 void MovingPhotoPattern::PrepareMediaPlayer()
321 {
322     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
323     CHECK_NULL_VOID(layoutProperty);
324     if (!layoutProperty->HasMovingPhotoUri() || !layoutProperty->HasVideoSource()) {
325         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto source is null.");
326         return;
327     }
328     if (layoutProperty->GetMovingPhotoUri().value() == uri_ &&
329         layoutProperty->GetVideoSource().value() == fd_) {
330         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer source has not changed.");
331         return;
332     }
333     uri_ = layoutProperty->GetMovingPhotoUri().value();
334     fd_ = layoutProperty->GetVideoSource().value();
335     if (!mediaPlayer_) {
336         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null.");
337         FireMediaPlayerError();
338         return;
339     }
340     if (!mediaPlayer_->IsMediaPlayerValid()) {
341         mediaPlayer_->CreateMediaPlayer();
342     }
343     if (!mediaPlayer_->IsMediaPlayerValid()) {
344         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is invalid.");
345         FireMediaPlayerError();
346         return;
347     }
348     ContainerScope scope(instanceId_);
349     auto context = PipelineContext::GetCurrentContext();
350     CHECK_NULL_VOID(context);
351     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
352     platformTask.PostTask(
353         [weak = WeakClaim(this)] {
354             auto movingPhotoPattern = weak.Upgrade();
355             CHECK_NULL_VOID(movingPhotoPattern);
356             movingPhotoPattern->ResetMediaPlayer();
357         },
358         "ArkUIMovingPhotoPrepare");
359 }
360 
ResetMediaPlayer()361 void MovingPhotoPattern::ResetMediaPlayer()
362 {
363     CHECK_NULL_VOID(mediaPlayer_);
364     isPrepared_ = false;
365     mediaPlayer_->ResetMediaPlayer();
366     RegisterMediaPlayerEvent();
367     if (!mediaPlayer_->SetSourceByFd(fd_)) {
368         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "set source for MediaPlayer failed.");
369         ContainerScope scope(instanceId_);
370         auto context = PipelineContext::GetCurrentContext();
371         CHECK_NULL_VOID(context);
372 
373         auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
374         uiTaskExecutor.PostTask(
375             [weak = WeakClaim(this)] {
376                 auto pattern = weak.Upgrade();
377                 CHECK_NULL_VOID(pattern);
378                 ContainerScope scope(pattern->instanceId_);
379                 pattern->FireMediaPlayerError();
380             },
381             "ArkUIMovingPhotoReset");
382         return;
383     }
384 }
385 
RegisterMediaPlayerEvent()386 void MovingPhotoPattern::RegisterMediaPlayerEvent()
387 {
388     if (fd_ == -1 || !mediaPlayer_) {
389         return;
390     }
391     ContainerScope scope(instanceId_);
392     auto context = PipelineContext::GetCurrentContext();
393     CHECK_NULL_VOID(context);
394     auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
395     auto movingPhotoPattern = WeakClaim(this);
396 
397     auto&& positionUpdatedEvent = [movingPhotoPattern, uiTaskExecutor](uint32_t currentPos) {
398         uiTaskExecutor.PostTask([movingPhotoPattern, currentPos] {
399             auto movingPhoto = movingPhotoPattern.Upgrade();
400             CHECK_NULL_VOID(movingPhoto);
401             ContainerScope scope(movingPhoto->instanceId_);
402             movingPhoto->OnPlayPositionChanged(currentPos);
403         }, "ArkUIMovingPhotoPositionChanged");
404     };
405 
406     auto&& stateChangedEvent = [movingPhotoPattern, uiTaskExecutor](PlaybackStatus status) {
407         uiTaskExecutor.PostTask([movingPhotoPattern, status] {
408             auto movingPhoto = movingPhotoPattern.Upgrade();
409             CHECK_NULL_VOID(movingPhoto);
410             ContainerScope scope(movingPhoto->instanceId_);
411             movingPhoto->OnMediaPlayerStatusChanged(status);
412         }, "ArkUIMovingPhotoStatusChanged");
413     };
414 
415     auto&& errorEvent = [movingPhotoPattern, uiTaskExecutor]() {
416         uiTaskExecutor.PostSyncTask([movingPhotoPattern] {
417             auto movingPhoto = movingPhotoPattern.Upgrade();
418             CHECK_NULL_VOID(movingPhoto);
419             ContainerScope scope(movingPhoto->instanceId_);
420             movingPhoto->FireMediaPlayerError();
421         }, "ArkUIMovingPhotoOnError");
422     };
423 
424     auto&& resolutionChangeEvent = [movingPhotoPattern, uiTaskExecutor]() {
425         uiTaskExecutor.PostTask([movingPhotoPattern] {
426             auto movingPhoto = movingPhotoPattern.Upgrade();
427             CHECK_NULL_VOID(movingPhoto);
428             ContainerScope scope(movingPhoto->instanceId_);
429             movingPhoto->OnResolutionChange();
430         }, "ArkUIMovingPhotoResolutionChanged");
431     };
432 
433     auto&& startRenderFrameEvent = [movingPhotoPattern, uiTaskExecutor]() {
434         uiTaskExecutor.PostTask([movingPhotoPattern] {
435             auto movingPhoto = movingPhotoPattern.Upgrade();
436             CHECK_NULL_VOID(movingPhoto);
437             ContainerScope scope(movingPhoto->instanceId_);
438             movingPhoto->OnStartRenderFrame();
439         }, "ArkUIMovingPhotoStartRender");
440     };
441 
442     mediaPlayer_->RegisterMediaPlayerEvent(
443         positionUpdatedEvent, stateChangedEvent, errorEvent, resolutionChangeEvent, startRenderFrameEvent);
444 }
445 
PrepareSurface()446 void MovingPhotoPattern::PrepareSurface()
447 {
448     if (!mediaPlayer_ || renderSurface_->IsSurfaceValid()) {
449         return;
450     }
451     if (!SystemProperties::GetExtSurfaceEnabled()) {
452         renderSurface_->SetRenderContext(renderContextForMediaPlayer_);
453     }
454     renderSurface_->InitSurface();
455     mediaPlayer_->SetRenderSurface(renderSurface_);
456     if (mediaPlayer_->SetSurface() != 0) {
457         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "prepare MediaPlayer failed.");
458     }
459 }
460 
UpdatePlayMode()461 void MovingPhotoPattern::UpdatePlayMode()
462 {
463     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto UpdatePlayMode.%{public}d", isChangePlayMode_);
464     if (isChangePlayMode_) {
465         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
466             SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
467         }
468         MediaResetToPlay();
469         isChangePlayMode_ = false;
470     }
471 }
472 
MediaResetToPlay()473 void MovingPhotoPattern::MediaResetToPlay()
474 {
475     autoAndRepeatLevel_ = historyAutoAndRepeatLevel_;
476     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
477         mediaPlayer_->PrepareAsync();
478     } else if (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
479         currentPlayStatus_ == PlaybackStatus::PAUSED ||
480         currentPlayStatus_ == PlaybackStatus::PREPARED) {
481             SelectPlaybackMode(historyAutoAndRepeatLevel_);
482     }
483 }
484 
FireMediaPlayerImageComplete()485 void MovingPhotoPattern::FireMediaPlayerImageComplete()
486 {
487     auto eventHub = GetEventHub<MovingPhotoEventHub>();
488     CHECK_NULL_VOID(eventHub);
489     eventHub->FireCompleteEvent();
490 }
491 
FireMediaPlayerStart()492 void MovingPhotoPattern::FireMediaPlayerStart()
493 {
494     auto eventHub = GetEventHub<MovingPhotoEventHub>();
495     CHECK_NULL_VOID(eventHub);
496     eventHub->FireStartEvent();
497     if (isFastKeyUp_) {
498         isFastKeyUp_ = false;
499         PausePlayback();
500     }
501 }
502 
FireMediaPlayerStop()503 void MovingPhotoPattern::FireMediaPlayerStop()
504 {
505     auto eventHub = GetEventHub<MovingPhotoEventHub>();
506     CHECK_NULL_VOID(eventHub);
507     eventHub->FireStopEvent();
508 }
509 
FireMediaPlayerPause()510 void MovingPhotoPattern::FireMediaPlayerPause()
511 {
512     auto eventHub = GetEventHub<MovingPhotoEventHub>();
513     CHECK_NULL_VOID(eventHub);
514     eventHub->FirePauseEvent();
515 }
516 
FireMediaPlayerFinish()517 void MovingPhotoPattern::FireMediaPlayerFinish()
518 {
519     auto eventHub = GetEventHub<MovingPhotoEventHub>();
520     CHECK_NULL_VOID(eventHub);
521     eventHub->FireFinishEvent();
522 }
523 
FireMediaPlayerError()524 void MovingPhotoPattern::FireMediaPlayerError()
525 {
526     auto eventHub = GetEventHub<MovingPhotoEventHub>();
527     CHECK_NULL_VOID(eventHub);
528     eventHub->FireErrorEvent();
529 }
530 
OnResolutionChange()531 void MovingPhotoPattern::OnResolutionChange()
532 {
533     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
534         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
535         return;
536     }
537     auto host = GetHost();
538     CHECK_NULL_VOID(host);
539     SizeF videoSize =
540         SizeF(static_cast<float>(mediaPlayer_->GetVideoWidth()), static_cast<float>(mediaPlayer_->GetVideoHeight()));
541     auto movingPhotoLayoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
542     CHECK_NULL_VOID(movingPhotoLayoutProperty);
543     movingPhotoLayoutProperty->UpdateVideoSize(videoSize);
544     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
545 }
546 
OnStartRenderFrame()547 void MovingPhotoPattern::OnStartRenderFrame()
548 {
549     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartRenderFrame.");
550 }
551 
OnStartedStatusCallback()552 void MovingPhotoPattern::OnStartedStatusCallback()
553 {
554     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartedStatusCallback.");
555     ACE_FUNCTION_TRACE();
556     auto host = GetHost();
557     CHECK_NULL_VOID(host);
558     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
559     CHECK_NULL_VOID(movingPhoto);
560     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
561     CHECK_NULL_VOID(image);
562     StartAnimation();
563 }
564 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)565 bool MovingPhotoPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
566 {
567     if (config.skipMeasure || dirty->SkipMeasureContent()) {
568         return false;
569     }
570     auto geometryNode = dirty->GetGeometryNode();
571     CHECK_NULL_RETURN(geometryNode, false);
572     auto movingPhotoNodeSize = geometryNode->GetContentSize();
573     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
574     CHECK_NULL_RETURN(layoutProperty, false);
575     auto videoFrameSize = MeasureContentLayout(movingPhotoNodeSize, layoutProperty);
576     if (renderContextForMediaPlayer_) {
577         renderContextForMediaPlayer_->SetBounds((movingPhotoNodeSize.Width() - videoFrameSize.Width()) / HALF,
578             (movingPhotoNodeSize.Height() - videoFrameSize.Height()) / HALF, videoFrameSize.Width(),
579             videoFrameSize.Height());
580     }
581     auto host = GetHost();
582     CHECK_NULL_RETURN(host, false);
583     host->MarkNeedSyncRenderTree();
584     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
585     CHECK_NULL_RETURN(movingPhoto, false);
586     auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
587     CHECK_NULL_RETURN(video, false);
588     video->GetRenderContext()->SetClipToBounds(true);
589     return false;
590 }
591 
CalculateFitContain(const SizeF & rawSize,const SizeF & layoutSize)592 SizeF MovingPhotoPattern::CalculateFitContain(const SizeF& rawSize, const SizeF& layoutSize)
593 {
594     if (NearZero(rawSize.Height()) || NearZero(rawSize.Width()) || NearZero(layoutSize.Height())) {
595         return layoutSize;
596     }
597     double sourceRatio = rawSize.Width() / rawSize.Height();
598     double layoutRatio = layoutSize.Width() / layoutSize.Height();
599     if (sourceRatio < layoutRatio) {
600         float ratio = layoutSize.Height() / rawSize.Height();
601         return { rawSize.Width() * ratio, layoutSize.Height() };
602     } else {
603         float ratio = layoutSize.Width() / rawSize.Width();
604         return { layoutSize.Width(), rawSize.Height() * ratio };
605     }
606 }
607 
CalculateFitFill(const SizeF & layoutSize)608 SizeF MovingPhotoPattern::CalculateFitFill(const SizeF& layoutSize)
609 {
610     return layoutSize;
611 }
612 
CalculateFitCover(const SizeF & rawSize,const SizeF & layoutSize)613 SizeF MovingPhotoPattern::CalculateFitCover(const SizeF& rawSize, const SizeF& layoutSize)
614 {
615     if (NearZero(rawSize.Height()) || NearZero(rawSize.Width()) || NearZero(layoutSize.Height())) {
616         return layoutSize;
617     }
618     double sourceRatio = rawSize.Width() / rawSize.Height();
619     double layoutRatio = layoutSize.Width() / layoutSize.Height();
620     float ratio = 1.0;
621     if (sourceRatio < layoutRatio) {
622         ratio = static_cast<float>(layoutSize.Width() / rawSize.Width());
623     } else {
624         ratio = static_cast<float>(layoutSize.Height() / rawSize.Height());
625     }
626     return { rawSize.Width() * ratio, rawSize.Height() * ratio};
627 }
628 
CalculateFitNone(const SizeF & rawSize)629 SizeF MovingPhotoPattern::CalculateFitNone(const SizeF& rawSize)
630 {
631     return rawSize;
632 }
633 
CalculateFitScaleDown(const SizeF & rawSize,const SizeF & layoutSize)634 SizeF MovingPhotoPattern::CalculateFitScaleDown(const SizeF& rawSize, const SizeF& layoutSize)
635 {
636     if ((rawSize.Width() <= layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
637         return CalculateFitNone(rawSize);
638     } else {
639         return CalculateFitContain(rawSize, layoutSize);
640     }
641 }
642 
CalculateFitAuto(const SizeF & rawSize,const SizeF & layoutSize)643 SizeF MovingPhotoPattern::CalculateFitAuto(const SizeF& rawSize, const SizeF& layoutSize)
644 {
645     if (NearZero(rawSize.Width()) || NearZero(rawSize.Height())) {
646         return layoutSize;
647     }
648     if ((rawSize.Width() <= layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
649         double widthRatio = layoutSize.Width() / rawSize.Width();
650         double heightRatio = layoutSize.Height() / rawSize.Height();
651         float ratio = static_cast<float>(std::min(widthRatio, heightRatio));
652         return { rawSize.Width() * ratio, rawSize.Height() * ratio };
653     } else if ((rawSize.Width() > layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
654         return CalculateFitContain(rawSize, layoutSize);
655     } else {
656         return CalculateFitCover(rawSize, layoutSize);
657     }
658 }
659 
GetRawImageSize()660 SizeF MovingPhotoPattern::GetRawImageSize()
661 {
662     auto host = GetHost();
663     CHECK_NULL_RETURN(host, SizeF(-1, -1));
664     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
665     CHECK_NULL_RETURN(movingPhoto, SizeF(-1, -1));
666     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
667     CHECK_NULL_RETURN(image, SizeF(-1, -1));
668     auto imagePattern = image->GetPattern<ImagePattern>();
669     CHECK_NULL_RETURN(image, SizeF(-1, -1));
670     return imagePattern->GetRawImageSize();
671 }
672 
MeasureContentLayout(const SizeF & layoutSize,const RefPtr<MovingPhotoLayoutProperty> & layoutProperty)673 SizeF MovingPhotoPattern::MeasureContentLayout(const SizeF& layoutSize,
674     const RefPtr<MovingPhotoLayoutProperty>& layoutProperty)
675 {
676     if (!layoutProperty || !layoutProperty->HasVideoSize()) {
677         return layoutSize;
678     }
679 
680     auto rawImageSize = GetRawImageSize();
681     auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
682     SizeF contentSize = { 0.0, 0.0 };
683     switch (imageFit) {
684         case ImageFit::CONTAIN:
685             contentSize = CalculateFitContain(rawImageSize, layoutSize);
686             break;
687         case ImageFit::FILL:
688             contentSize = CalculateFitFill(layoutSize);
689             break;
690         case ImageFit::COVER:
691             contentSize = CalculateFitCover(rawImageSize, layoutSize);
692             break;
693         case ImageFit::NONE:
694             contentSize = CalculateFitNone(rawImageSize);
695             break;
696         case ImageFit::SCALE_DOWN:
697             contentSize = CalculateFitScaleDown(rawImageSize, layoutSize);
698             break;
699         default:
700             contentSize = CalculateFitAuto(rawImageSize, layoutSize);
701     }
702 
703     return contentSize;
704 }
705 
OnMediaPlayerStatusChanged(PlaybackStatus status)706 void MovingPhotoPattern::OnMediaPlayerStatusChanged(PlaybackStatus status)
707 {
708     currentPlayStatus_ = status;
709     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is %{public}d.", status);
710     switch (status) {
711         case PlaybackStatus::ERROR:
712             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is ERROR.");
713             FireMediaPlayerError();
714             break;
715         case PlaybackStatus::IDLE:
716             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is IDLE.");
717             break;
718         case PlaybackStatus::INITIALIZED:
719             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is INITIALIZED.");
720             OnMediaPlayerInitialized();
721             break;
722         case PlaybackStatus::PREPARED:
723             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PREPARED.");
724             OnMediaPlayerPrepared();
725             break;
726         case PlaybackStatus::STARTED:
727             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is STARTED.");
728             OnStartedStatusCallback();
729             FireMediaPlayerStart();
730             break;
731         case PlaybackStatus::PAUSED:
732             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PAUSED.");
733             FireMediaPlayerPause();
734             break;
735         case PlaybackStatus::STOPPED:
736             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is STOPPED.");
737             OnMediaPlayerStoped();
738             break;
739         case PlaybackStatus::PLAYBACK_COMPLETE:
740             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PLAYBACK_COMPLETE.");
741             OnMediaPlayerCompletion();
742             break;
743         case PlaybackStatus::NONE:
744             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is NONE.");
745             break;
746         default:
747             TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "Invalid player status.");
748             break;
749     }
750 }
751 
OnMediaPlayerInitialized()752 void MovingPhotoPattern::OnMediaPlayerInitialized()
753 {
754     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnMediaPlayerInitialized.");
755     if (!isSetAutoPlayPeriod_ && autoAndRepeatLevel_ == PlaybackMode::AUTO) {
756         isSetAutoPlayPeriod_ = true;
757         SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
758     }
759     PrepareSurface();
760     if (mediaPlayer_->PrepareAsync() != PREPARE_RETURN) {
761         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "prepare MediaPlayer failed.");
762     }
763 }
764 
OnMediaPlayerPrepared()765 void MovingPhotoPattern::OnMediaPlayerPrepared()
766 {
767     ContainerScope scope(instanceId_);
768     auto context = PipelineContext::GetCurrentContext();
769     CHECK_NULL_VOID(context);
770     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
771         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
772         return;
773     }
774     isPrepared_ = true;
775     Size videoSize = Size(mediaPlayer_->GetVideoWidth(), mediaPlayer_->GetVideoHeight());
776     auto host = GetHost();
777     CHECK_NULL_VOID(host);
778     auto videoLayoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
779     CHECK_NULL_VOID(videoLayoutProperty);
780     CHECK_NULL_VOID(mediaPlayer_);
781     videoLayoutProperty->UpdateVideoSize(
782         SizeF(static_cast<float>(videoSize.Width()), static_cast<float>(videoSize.Height())));
783     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
784     UpdateMediaPlayerSpeed();
785     UpdateMediaPlayerMuted();
786     VisiblePlayback();
787 }
788 
OnMediaPlayerStoped()789 void MovingPhotoPattern::OnMediaPlayerStoped()
790 {
791     isPlayByController_ = false;
792     FireMediaPlayerStop();
793 }
794 
OnMediaPlayerCompletion()795 void MovingPhotoPattern::OnMediaPlayerCompletion()
796 {
797     if (isPlayByController_ || autoAndRepeatLevel_ != PlaybackMode::NONE) {
798         isPlayByController_ = false;
799         StopAnimation();
800     }
801     FireMediaPlayerFinish();
802 }
803 
HideImageNode()804 void MovingPhotoPattern::HideImageNode()
805 {
806     auto host = GetHost();
807     CHECK_NULL_VOID(host);
808     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
809     CHECK_NULL_VOID(movingPhoto);
810     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
811     CHECK_NULL_VOID(image);
812     auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
813     CHECK_NULL_VOID(imageLayoutProperty);
814     imageLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
815     image->MarkModifyDone();
816 }
817 
VisiblePlayback()818 void MovingPhotoPattern::VisiblePlayback()
819 {
820     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto VisiblePlayback.");
821     if (!isVisible_) {
822         return;
823     }
824     if (historyAutoAndRepeatLevel_ != PlaybackMode::NONE &&
825         autoAndRepeatLevel_ == PlaybackMode::NONE) {
826         SelectPlaybackMode(historyAutoAndRepeatLevel_);
827     } else {
828         SelectPlaybackMode(autoAndRepeatLevel_);
829     }
830 }
831 
SelectPlaybackMode(PlaybackMode mode)832 void MovingPhotoPattern::SelectPlaybackMode(PlaybackMode mode)
833 {
834     if (mode == PlaybackMode::REPEAT) {
835         StartRepeatPlay();
836     } else if (mode == PlaybackMode::AUTO) {
837         StartAutoPlay();
838     }
839 }
840 
StartPlayback()841 void MovingPhotoPattern::StartPlayback()
842 {
843     if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_) {
844         return;
845     }
846     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
847         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "StartPlayback autoAndRepeatLevel_:%{public}d.",
848             autoAndRepeatLevel_);
849         return;
850     }
851     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
852         mediaPlayer_->PrepareAsync();
853     }
854     isPlayByController_ = true;
855     isFastKeyUp_ = false;
856     if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
857         currentPlayStatus_ == PlaybackStatus::PAUSED)) {
858         int32_t duration = DURATION_FLAG;
859         mediaPlayer_->GetDuration(duration);
860         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "StartPlayback duration:%{public}d.",
861             duration);
862         SetAutoPlayPeriod(PERIOD_START, duration);
863     }
864     Start();
865 }
866 
StartAnimation()867 void MovingPhotoPattern::StartAnimation()
868 {
869     if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
870         if (!isFirstRepeatPlay_) {
871             return;
872         }
873         isFirstRepeatPlay_ = false;
874     }
875     auto host = GetHost();
876     CHECK_NULL_VOID(host);
877     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
878     CHECK_NULL_VOID(movingPhoto);
879     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
880     CHECK_NULL_VOID(image);
881     auto imageRsContext = image->GetRenderContext();
882     CHECK_NULL_VOID(imageRsContext);
883     auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
884     CHECK_NULL_VOID(video);
885     auto videoRsContext = video->GetRenderContext();
886     CHECK_NULL_VOID(videoRsContext);
887 
888     imageRsContext->UpdateOpacity(1.0);
889     imageRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
890     videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
891     auto movingPhotoPattern = WeakClaim(this);
892     AnimationOption animationOption;
893     animationOption.SetDuration(ANIMATION_DURATION_400);
894     animationOption.SetCurve(Curves::FRICTION);
895     animationOption.SetOnFinishEvent([movingPhotoPattern]() {
896         auto movingPhoto = movingPhotoPattern.Upgrade();
897         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartAnimation OnFinishEvent.");
898         CHECK_NULL_VOID(movingPhoto);
899         if (movingPhoto->currentPlayStatus_ == PlaybackStatus::PAUSED
900             || movingPhoto->currentPlayStatus_ == PlaybackStatus::STOPPED
901             || !movingPhoto->startAnimationFlag_) {
902             return;
903         }
904         movingPhoto->HideImageNode();
905     });
906     startAnimationFlag_ = true;
907     AnimationUtils::Animate(animationOption,
908         [imageRsContext, videoRsContext, repeatFlag = historyAutoAndRepeatLevel_]() {
909             imageRsContext->UpdateOpacity(0.0);
910             imageRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
911             if (repeatFlag == PlaybackMode::REPEAT) {
912                 videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
913             } else {
914                 videoRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
915             }
916         }, animationOption.GetOnFinishEvent());
917 }
918 
StopPlayback()919 void MovingPhotoPattern::StopPlayback()
920 {
921     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StopPlayback");
922     isFastKeyUp_ = false;
923     isPlayByController_ = false;
924     Pause();
925     autoAndRepeatLevel_ = PlaybackMode::NONE;
926     if (historyAutoAndRepeatLevel_ != PlaybackMode::REPEAT) {
927         StopAnimation();
928     }
929 }
930 
PausePlayback()931 void MovingPhotoPattern::PausePlayback()
932 {
933     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto PausePlayback");
934     isFastKeyUp_ = false;
935     if (currentPlayStatus_ != PlaybackStatus::STARTED || !isPrepared_) {
936         return;
937     }
938     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
939         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "PausePlayback autoAndRepeatLevel_:%{public}d.",
940             autoAndRepeatLevel_);
941         return;
942     }
943     isPlayByController_ = false;
944     Pause();
945     StopAnimation();
946 }
947 
StopAnimation()948 void MovingPhotoPattern::StopAnimation()
949 {
950     startAnimationFlag_ = false;
951     if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
952         StopAnimationCallback();
953         return;
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 imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
962     CHECK_NULL_VOID(imageLayoutProperty);
963     auto imageRsContext = image->GetRenderContext();
964     CHECK_NULL_VOID(imageRsContext);
965     auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
966     CHECK_NULL_VOID(video);
967     auto videoRsContext = video->GetRenderContext();
968     CHECK_NULL_VOID(videoRsContext);
969     videoRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
970     video->MarkModifyDone();
971 
972     imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
973     imageRsContext->UpdateOpacity(0.0);
974     imageRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
975     image->MarkModifyDone();
976     auto movingPhotoPattern = WeakClaim(this);
977     AnimationOption option;
978     option.SetDuration(ANIMATION_DURATION_300);
979     option.SetCurve(Curves::FRICTION);
980     option.SetOnFinishEvent([movingPhotoPattern]() {
981         auto movingPhoto = movingPhotoPattern.Upgrade();
982         CHECK_NULL_VOID(movingPhoto);
983         movingPhoto->StopAnimationCallback();
984     });
985     AnimationUtils::Animate(option, [imageRsContext, videoRsContext]() {
986             imageRsContext->UpdateOpacity(1.0);
987             imageRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
988             videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
989         }, option.GetOnFinishEvent());
990 }
991 
StopAnimationCallback()992 void MovingPhotoPattern::StopAnimationCallback()
993 {
994     Seek(0);
995     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "StopAnimation OnFinishEvent:%{public}d.", autoAndRepeatLevel_);
996     if (needUpdateImageNode_) {
997         UpdateImageNode();
998         needUpdateImageNode_ = false;
999     }
1000     if (autoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1001         StartRepeatPlay();
1002     } else if (autoAndRepeatLevel_ == PlaybackMode::AUTO) {
1003         autoAndRepeatLevel_ = PlaybackMode::NONE;
1004     }
1005 }
1006 
AutoPlay(bool isAutoPlay)1007 void MovingPhotoPattern::AutoPlay(bool isAutoPlay)
1008 {
1009     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto AutoPlay: %{public}d.", isAutoPlay);
1010     if (isAutoPlay) {
1011         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1012             return;
1013         }
1014         isChangePlayMode_ = true;
1015         if (autoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1016             historyAutoAndRepeatLevel_ = PlaybackMode::AUTO;
1017             autoAndRepeatLevel_ = PlaybackMode::AUTO;
1018         }
1019     }
1020 }
1021 
StartAutoPlay()1022 void MovingPhotoPattern::StartAutoPlay()
1023 {
1024     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartAutoPlay in.");
1025     isFastKeyUp_ = false;
1026     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1027         return;
1028     }
1029 
1030     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1031         mediaPlayer_->PrepareAsync();
1032     }
1033     Start();
1034 }
1035 
StartRepeatPlay()1036 void MovingPhotoPattern::StartRepeatPlay()
1037 {
1038     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartRepeatPlay in.");
1039     isFastKeyUp_ = false;
1040     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1041         return;
1042     }
1043 
1044     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1045         mediaPlayer_->PrepareAsync();
1046     }
1047     if (!isFirstRepeatPlay_ && isSetAutoPlayPeriod_) {
1048         int32_t duration = DURATION_FLAG;
1049         mediaPlayer_->GetDuration(duration);
1050         SetAutoPlayPeriod(PERIOD_START, duration);
1051     }
1052     Start();
1053 }
1054 
RepeatPlay(bool isRepeatPlay)1055 void MovingPhotoPattern::RepeatPlay(bool isRepeatPlay)
1056 {
1057     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto RepeatPlay status: %{public}d.", isRepeatPlay);
1058     if (isRepeatPlay && historyAutoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1059         isChangePlayMode_ = true;
1060         isFirstRepeatPlay_ = true;
1061     }
1062     if (!isRepeatPlay && historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1063         isChangePlayMode_ = true;
1064         historyAutoAndRepeatLevel_ = PlaybackMode::NONE;
1065         Pause();
1066         StopAnimation();
1067     }
1068     if (isRepeatPlay) {
1069         historyAutoAndRepeatLevel_ = PlaybackMode::REPEAT;
1070         autoAndRepeatLevel_ = PlaybackMode::REPEAT;
1071     }
1072 }
1073 
AutoPlayPeriod(int64_t startTime,int64_t endTime)1074 void MovingPhotoPattern::AutoPlayPeriod(int64_t startTime, int64_t endTime)
1075 {
1076     if (startTime >= VIDEO_PLAYTIME_START_POSITION && startTime < endTime
1077             && endTime <= VIDEO_PLAYTIME_END_POSITION) {
1078         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer set Period.");
1079         autoPlayPeriodStartTime_ = startTime;
1080         autoPlayPeriodEndTime_ = endTime;
1081     }
1082 }
1083 
SetAutoPlayPeriod(int64_t startTime,int64_t endTime)1084 void MovingPhotoPattern::SetAutoPlayPeriod(int64_t startTime, int64_t endTime)
1085 {
1086     if (startTime < VIDEO_PLAYTIME_START_POSITION || startTime >= endTime
1087             || endTime > VIDEO_PLAYTIME_END_POSITION) {
1088         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer SetAutoPlayPeriod error.");
1089         return;
1090     }
1091     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1092         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1093         return;
1094     }
1095 
1096     ContainerScope scope(instanceId_);
1097     auto context = PipelineContext::GetCurrentContext();
1098     CHECK_NULL_VOID(context);
1099 
1100     mediaPlayer_->SetPlayRange(startTime, endTime);
1101 }
1102 
Start()1103 void MovingPhotoPattern::Start()
1104 {
1105     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1106         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1107         return;
1108     }
1109     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1110         mediaPlayer_->PrepareAsync();
1111     }
1112     ContainerScope scope(instanceId_);
1113     auto context = PipelineContext::GetCurrentContext();
1114     CHECK_NULL_VOID(context);
1115 
1116     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1117     platformTask.PostTask(
1118         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1119             auto mediaPlayer = weak.Upgrade();
1120             CHECK_NULL_VOID(mediaPlayer);
1121             mediaPlayer->Play();
1122         },
1123         "ArkUIMovingPhotoStartPlay");
1124 }
1125 
Pause()1126 void MovingPhotoPattern::Pause()
1127 {
1128     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1129         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1130         return;
1131     }
1132     ContainerScope scope(instanceId_);
1133     auto context = PipelineContext::GetCurrentContext();
1134     CHECK_NULL_VOID(context);
1135 
1136     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1137     platformTask.PostTask(
1138         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1139             auto mediaPlayer = weak.Upgrade();
1140             CHECK_NULL_VOID(mediaPlayer);
1141             mediaPlayer->Pause();
1142         },
1143         "ArkUIMovingPhotoPausePlay");
1144 }
1145 
Stop()1146 void MovingPhotoPattern::Stop()
1147 {
1148     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1149         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1150         return;
1151     }
1152     ContainerScope scope(instanceId_);
1153     auto context = PipelineContext::GetCurrentContext();
1154     CHECK_NULL_VOID(context);
1155 
1156     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1157     platformTask.PostTask(
1158         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1159             auto mediaPlayer = weak.Upgrade();
1160             CHECK_NULL_VOID(mediaPlayer);
1161             mediaPlayer->Stop();
1162         },
1163         "ArkUIMovingPhotoStopPlay");
1164 }
1165 
Seek(int32_t position)1166 void MovingPhotoPattern::Seek(int32_t position)
1167 {
1168     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1169         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1170         return;
1171     }
1172     ContainerScope scope(instanceId_);
1173     auto context = PipelineContext::GetCurrentContext();
1174     CHECK_NULL_VOID(context);
1175 
1176     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1177     platformTask.PostTask(
1178         [weak = WeakClaim(RawPtr(mediaPlayer_)), pos = position] {
1179             auto mediaPlayer = weak.Upgrade();
1180             CHECK_NULL_VOID(mediaPlayer);
1181             mediaPlayer->Seek(pos, SeekMode::SEEK_PREVIOUS_SYNC);
1182         },
1183         "ArkUIMovingPhotoSeek");
1184 }
1185 
UpdateMediaPlayerSpeed()1186 void MovingPhotoPattern::UpdateMediaPlayerSpeed()
1187 {
1188     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1189         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1190         return;
1191     }
1192     ContainerScope scope(instanceId_);
1193     auto context = PipelineContext::GetCurrentContext();
1194     CHECK_NULL_VOID(context);
1195     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1196     platformTask.PostTask(
1197         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1198             auto mediaPlayer = weak.Upgrade();
1199             CHECK_NULL_VOID(mediaPlayer);
1200             mediaPlayer->SetPlaybackSpeed(static_cast<float>(NORMAL_PLAY_SPEED));
1201         },
1202         "ArkUIMovingPhotoUpdateSpeed");
1203 }
1204 
UpdateMediaPlayerMuted()1205 void MovingPhotoPattern::UpdateMediaPlayerMuted()
1206 {
1207     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1208         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1209         return;
1210     }
1211     ContainerScope scope(instanceId_);
1212     float volume = isMuted_ ? 0.0f : 1.0f;
1213     auto context = PipelineContext::GetCurrentContext();
1214     CHECK_NULL_VOID(context);
1215     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1216     platformTask.PostTask(
1217         [weak = WeakClaim(RawPtr(mediaPlayer_)), videoVolume = volume] {
1218             auto mediaPlayer = weak.Upgrade();
1219             CHECK_NULL_VOID(mediaPlayer);
1220             mediaPlayer->SetVolume(videoVolume, videoVolume);
1221         },
1222         "ArkUIMovingPhotoUpdateMuted");
1223 }
1224 
OnAreaChangedInner()1225 void MovingPhotoPattern::OnAreaChangedInner()
1226 {
1227     if (!SystemProperties::GetExtSurfaceEnabled()) {
1228         return;
1229     }
1230     auto host = GetHost();
1231     CHECK_NULL_VOID(host);
1232     auto geometryNode = host->GetGeometryNode();
1233     CHECK_NULL_VOID(geometryNode);
1234     auto videoNodeSize = geometryNode->GetContentSize();
1235     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1236     CHECK_NULL_VOID(layoutProperty);
1237     auto videoFrameSize = MeasureContentLayout(videoNodeSize, layoutProperty);
1238     auto transformRelativeOffset = host->GetTransformRelativeOffset();
1239 
1240     Rect rect = Rect(transformRelativeOffset.GetX() + (videoNodeSize.Width() - videoFrameSize.Width()) / HALF,
1241         transformRelativeOffset.GetY() + (videoNodeSize.Height() - videoFrameSize.Height()) / HALF,
1242         videoFrameSize.Width(), videoFrameSize.Height());
1243     if (renderSurface_ && (rect != lastBoundsRect_)) {
1244         renderSurface_->SetExtSurfaceBounds(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1245         lastBoundsRect_ = rect;
1246     }
1247 }
1248 
OnVisibleChange(bool isVisible)1249 void MovingPhotoPattern::OnVisibleChange(bool isVisible)
1250 {
1251     CHECK_NULL_VOID(mediaPlayer_);
1252     if (!isVisible) {
1253         StopPlayback();
1254     }
1255 }
1256 
OnWindowHide()1257 void MovingPhotoPattern::OnWindowHide()
1258 {
1259     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto OnWindowHide.");
1260     if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1261         PausePlayback();
1262     } else if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1263         StopPlayback();
1264         return;
1265     }
1266     auto host = GetHost();
1267     CHECK_NULL_VOID(host);
1268     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
1269     CHECK_NULL_VOID(movingPhoto);
1270     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
1271     CHECK_NULL_VOID(image);
1272     auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1273     CHECK_NULL_VOID(imageLayoutProperty);
1274     imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1275     auto rsContext = image->GetRenderContext();
1276     CHECK_NULL_VOID(rsContext);
1277     rsContext->UpdateOpacity(1.0);
1278     image->MarkModifyDone();
1279 }
1280 
OnWindowShow()1281 void MovingPhotoPattern::OnWindowShow()
1282 {
1283     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto OnWindowShow.");
1284     CHECK_NULL_VOID(mediaPlayer_);
1285     if (autoAndRepeatLevel_ == PlaybackMode::REPEAT && currentPlayStatus_ == PlaybackStatus::STOPPED) {
1286         mediaPlayer_->PrepareAsync();
1287     }
1288 }
1289 
RegisterVisibleAreaChange()1290 void MovingPhotoPattern::RegisterVisibleAreaChange()
1291 {
1292     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto RegisterVisibleAreaChange.");
1293     if (hasVisibleChangeRegistered_) {
1294         return;
1295     }
1296     auto pipeline = PipelineContext::GetCurrentContextSafely();
1297     CHECK_NULL_VOID(pipeline);
1298     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
1299         auto pattern = weak.Upgrade();
1300         CHECK_NULL_VOID(pattern);
1301         pattern->isVisible_ = visible;
1302         pattern->VisibleAreaCallback(visible);
1303     };
1304     auto host = GetHost();
1305     CHECK_NULL_VOID(host);
1306     std::vector<double> ratioList = {1.0};
1307     pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false);
1308     hasVisibleChangeRegistered_ = true;
1309 }
1310 
VisibleAreaCallback(bool visible)1311 void MovingPhotoPattern::VisibleAreaCallback(bool visible)
1312 {
1313     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto VisibleAreaCallback:%{public}d.", visible);
1314     if (visible) {
1315         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1316             SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
1317         }
1318         MediaResetToPlay();
1319     } else {
1320         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1321             PausePlayback();
1322         } else if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1323             StopPlayback();
1324         }
1325     }
1326 }
1327 
~MovingPhotoPattern()1328 MovingPhotoPattern::~MovingPhotoPattern()
1329 {
1330     if (fd_ > 0) {
1331         close(fd_);
1332     }
1333 }
1334 } // namespace OHOS::Ace::NG