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