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