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