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