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