1 /*
2 * Copyright (c) 2022-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 "core/components_ng/pattern/video/video_pattern.h"
17
18 #include "video_node.h"
19
20 #include "base/background_task_helper/background_task_helper.h"
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/i18n/localization.h"
24 #include "base/json/json_util.h"
25 #include "base/thread/task_executor.h"
26 #include "base/utils/string_utils.h"
27 #include "base/utils/system_properties.h"
28 #include "base/utils/utils.h"
29 #include "core/common/ace_engine.h"
30 #include "core/common/ai/image_analyzer_manager.h"
31 #include "core/common/udmf/udmf_client.h"
32 #include "core/components/video/video_theme.h"
33 #include "core/components_ng/pattern/slider/slider_pattern.h"
34 #include "core/components_ng/pattern/text/text_pattern.h"
35 #include "core/components_ng/pattern/video/video_full_screen_node.h"
36 #include "core/components_ng/pattern/video/video_full_screen_pattern.h"
37 #include "core/components_ng/property/gradient_property.h"
38
39 #ifdef RENDER_EXTRACT_SUPPORTED
40 #include "core/common/ace_view.h"
41 #endif
42
43 namespace OHOS::Ace::NG {
44 namespace {
45 using HiddenChangeEvent = std::function<void(bool)>;
46 constexpr uint32_t SECONDS_PER_HOUR = 3600;
47 constexpr uint32_t SECONDS_PER_MINUTE = 60;
48 const std::string FORMAT_HH_MM_SS = "%02d:%02d:%02d";
49 const std::string FORMAT_MM_SS = "%02d:%02d";
50 constexpr int32_t MILLISECONDS_TO_SECONDS = 1000;
51 constexpr uint32_t CURRENT_POS = 1;
52 constexpr uint32_t SLIDER_POS = 2;
53 constexpr uint32_t DURATION_POS = 3;
54 constexpr uint32_t FULL_SCREEN_POS = 4;
55 constexpr int32_t AVERAGE_VALUE = 2;
56 constexpr int32_t ANALYZER_DELAY_TIME = 100;
57 constexpr int32_t ANALYZER_CAPTURE_DELAY_TIME = 1000;
58 const Dimension LIFT_HEIGHT = 28.0_vp;
59 const std::string PNG_FILE_EXTENSION = "png";
60 constexpr int32_t MEDIA_TYPE_AUD = 0;
61 constexpr float VOLUME_STEP = 0.05f;
62
63 // Default error, empty string.
64 const std::string ERROR = "";
65
66 enum SliderChangeMode {
67 BEGIN = 0,
68 MOVING,
69 END,
70 };
71
IntTimeToText(uint32_t time)72 std::string IntTimeToText(uint32_t time)
73 {
74 auto minutes = (time % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE;
75 auto seconds = time % SECONDS_PER_MINUTE;
76 if (time >= SECONDS_PER_HOUR) {
77 auto hours = time / SECONDS_PER_HOUR;
78 return StringUtils::FormatString(FORMAT_HH_MM_SS.c_str(), hours, minutes, seconds);
79 }
80 return StringUtils::FormatString(FORMAT_MM_SS.c_str(), minutes, seconds);
81 }
82
CalculateFitContain(const SizeF & videoSize,const SizeF & layoutSize)83 SizeF CalculateFitContain(const SizeF& videoSize, const SizeF& layoutSize)
84 {
85 double layoutRatio = NearZero(layoutSize.Height()) ? 0.0 : layoutSize.Width() / layoutSize.Height();
86 double sourceRatio = NearZero(videoSize.Height()) ? layoutRatio : videoSize.Width() / videoSize.Height();
87
88 if (NearZero(layoutRatio) || NearZero(sourceRatio)) {
89 return layoutSize;
90 }
91 if (sourceRatio < layoutRatio) {
92 return { static_cast<float>(sourceRatio) * layoutSize.Height(), layoutSize.Height() };
93 }
94 return { layoutSize.Width(), static_cast<float>(layoutSize.Width() / sourceRatio) };
95 }
96
CalculateFitFill(const SizeF & layoutSize)97 SizeF CalculateFitFill(const SizeF& layoutSize)
98 {
99 return layoutSize;
100 }
101
CalculateFitCover(const SizeF & videoSize,const SizeF & layoutSize)102 SizeF CalculateFitCover(const SizeF& videoSize, const SizeF& layoutSize)
103 {
104 double layoutRatio = NearZero(layoutSize.Height()) ? 0.0 : layoutSize.Width() / layoutSize.Height();
105 double sourceRatio = NearZero(videoSize.Height()) ? layoutRatio : videoSize.Width() / videoSize.Height();
106
107 if (NearZero(layoutRatio) || NearZero(sourceRatio)) {
108 return layoutSize;
109 }
110 if (sourceRatio < layoutRatio) {
111 return { layoutSize.Width(), static_cast<float>(layoutSize.Width() / sourceRatio) };
112 }
113 return { static_cast<float>(layoutSize.Height() * sourceRatio), layoutSize.Height() };
114 }
115
CalculateFitNone(const SizeF & videoSize)116 SizeF CalculateFitNone(const SizeF& videoSize)
117 {
118 return videoSize;
119 }
120
CalculateFitScaleDown(const SizeF & videoSize,const SizeF & layoutSize)121 SizeF CalculateFitScaleDown(const SizeF& videoSize, const SizeF& layoutSize)
122 {
123 if (layoutSize.Width() > videoSize.Width()) {
124 return CalculateFitNone(videoSize);
125 }
126 return CalculateFitContain(videoSize, layoutSize);
127 }
128
MeasureVideoContentLayout(const SizeF & layoutSize,const RefPtr<VideoLayoutProperty> & layoutProperty)129 SizeF MeasureVideoContentLayout(const SizeF& layoutSize, const RefPtr<VideoLayoutProperty>& layoutProperty)
130 {
131 if (!layoutProperty || !layoutProperty->HasVideoSize()) {
132 return layoutSize;
133 }
134
135 auto videoSize = layoutProperty->GetVideoSizeValue(SizeF(0, 0));
136 auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
137 SizeF contentSize = { 0.0, 0.0 };
138 switch (imageFit) {
139 case ImageFit::CONTAIN:
140 contentSize = CalculateFitContain(videoSize, layoutSize);
141 break;
142 case ImageFit::FILL:
143 contentSize = CalculateFitFill(layoutSize);
144 break;
145 case ImageFit::COVER:
146 contentSize = CalculateFitCover(videoSize, layoutSize);
147 break;
148 case ImageFit::NONE:
149 contentSize = CalculateFitNone(videoSize);
150 break;
151 case ImageFit::SCALE_DOWN:
152 contentSize = CalculateFitScaleDown(videoSize, layoutSize);
153 break;
154 default:
155 contentSize = CalculateFitContain(videoSize, layoutSize);
156 }
157
158 // Just return contentSize as the video frame area.
159 return contentSize;
160 }
161
RoundValueToPixelGrid(float value,bool isRound,bool forceCeil,bool forceFloor)162 float RoundValueToPixelGrid(float value, bool isRound, bool forceCeil, bool forceFloor)
163 {
164 float fractials = fmod(value, 1.0f);
165 if (fractials < 0.0f) {
166 ++fractials;
167 }
168 if (forceCeil) {
169 return (value - fractials + 1.0f);
170 } else if (forceFloor) {
171 return (value - fractials);
172 } else if (isRound) {
173 if (NearEqual(fractials, 1.0f) || GreatOrEqual(fractials, 0.50f)) {
174 return (value - fractials + 1.0f);
175 } else {
176 return (value - fractials);
177 }
178 }
179 return value;
180 }
181
AdjustPaintRect(float positionX,float positionY,float width,float height,bool isRound)182 RectF AdjustPaintRect(float positionX, float positionY, float width, float height, bool isRound)
183 {
184 RectF rect;
185 float relativeLeft = positionX;
186 float relativeTop = positionY;
187 float nodeWidth = width;
188 float nodeHeight = height;
189 float absoluteRight = relativeLeft + nodeWidth;
190 float absoluteBottom = relativeTop + nodeHeight;
191 float roundToPixelErrorX = 0.0f;
192 float roundToPixelErrorY = 0.0f;
193
194 float nodeLeftI = RoundValueToPixelGrid(relativeLeft, isRound, false, false);
195 float nodeTopI = RoundValueToPixelGrid(relativeTop, isRound, false, false);
196 roundToPixelErrorX += nodeLeftI - relativeLeft;
197 roundToPixelErrorY += nodeTopI - relativeTop;
198 rect.SetLeft(nodeLeftI);
199 rect.SetTop(nodeTopI);
200
201 float nodeWidthI = RoundValueToPixelGrid(absoluteRight, isRound, false, false) - nodeLeftI;
202 float nodeWidthTemp = RoundValueToPixelGrid(nodeWidth, isRound, false, false);
203 roundToPixelErrorX += nodeWidthI - nodeWidth;
204 if (roundToPixelErrorX > 0.5f) {
205 nodeWidthI -= 1.0f;
206 roundToPixelErrorX -= 1.0f;
207 }
208 if (roundToPixelErrorX < -0.5f) {
209 nodeWidthI += 1.0f;
210 roundToPixelErrorX += 1.0f;
211 }
212 if (nodeWidthI < nodeWidthTemp) {
213 roundToPixelErrorX += nodeWidthTemp - nodeWidthI;
214 nodeWidthI = nodeWidthTemp;
215 }
216
217 float nodeHeightI = RoundValueToPixelGrid(absoluteBottom, isRound, false, false) - nodeTopI;
218 float nodeHeightTemp = RoundValueToPixelGrid(nodeHeight, isRound, false, false);
219 roundToPixelErrorY += nodeHeightI - nodeHeight;
220 if (roundToPixelErrorY > 0.5f) {
221 nodeHeightI -= 1.0f;
222 roundToPixelErrorY -= 1.0f;
223 }
224 if (roundToPixelErrorY < -0.5f) {
225 nodeHeightI += 1.0f;
226 roundToPixelErrorY += 1.0f;
227 }
228 if (nodeHeightI < nodeHeightTemp) {
229 roundToPixelErrorY += nodeHeightTemp - nodeHeightI;
230 nodeHeightI = nodeHeightTemp;
231 }
232
233 rect.SetWidth(nodeWidthI);
234 rect.SetHeight(nodeHeightI);
235 return rect;
236 }
237
ConvertToGradient(Color color)238 Gradient ConvertToGradient(Color color)
239 {
240 Gradient gradient;
241 GradientColor gradientColorBegin;
242 gradientColorBegin.SetLinearColor(LinearColor(color));
243 gradientColorBegin.SetDimension(Dimension(0.0f));
244 gradient.AddColor(gradientColorBegin);
245 OHOS::Ace::NG::GradientColor gradientColorEnd;
246 gradientColorEnd.SetLinearColor(LinearColor(color));
247 gradientColorEnd.SetDimension(Dimension(1.0f));
248 gradient.AddColor(gradientColorEnd);
249
250 return gradient;
251 }
252
RegisterMediaPlayerEventImpl(const WeakPtr<VideoPattern> & weak,const RefPtr<MediaPlayer> & mediaPlayer,int32_t instanceId,const SingleTaskExecutor & uiTaskExecutor)253 void RegisterMediaPlayerEventImpl(const WeakPtr<VideoPattern>& weak, const RefPtr<MediaPlayer>& mediaPlayer,
254 int32_t instanceId, const SingleTaskExecutor& uiTaskExecutor)
255 {
256 auto&& positionUpdatedEvent = [weak, uiTaskExecutor, instanceId](uint32_t currentPos) {
257 uiTaskExecutor.PostSyncTask([weak, currentPos, instanceId] {
258 auto video = weak.Upgrade();
259 CHECK_NULL_VOID(video);
260 ContainerScope scope(instanceId);
261 video->OnCurrentTimeChange(currentPos);
262 video->StartUpdateImageAnalyzer();
263 }, "ArkUIVideoCurrentTimeChange");
264 };
265
266 auto&& stateChangedEvent = [weak, uiTaskExecutor, instanceId](PlaybackStatus status) {
267 uiTaskExecutor.PostTask([weak, status, instanceId] {
268 auto video = weak.Upgrade();
269 CHECK_NULL_VOID(video);
270 ContainerScope scope(instanceId);
271 video->OnPlayerStatus(status);
272 }, "ArkUIVideoPlayerStatusChange");
273 };
274
275 auto&& errorEvent = [weak, uiTaskExecutor, instanceId]() {
276 uiTaskExecutor.PostTask([weak, instanceId] {
277 auto video = weak.Upgrade();
278 CHECK_NULL_VOID(video);
279 ContainerScope scope(instanceId);
280 video->OnError("");
281 }, "ArkUIVideoError");
282 };
283
284 auto&& resolutionChangeEvent = [weak, uiTaskExecutor, instanceId]() {
285 uiTaskExecutor.PostSyncTask([weak, instanceId] {
286 auto video = weak.Upgrade();
287 CHECK_NULL_VOID(video);
288 ContainerScope scope(instanceId);
289 video->OnResolutionChange();
290 }, "ArkUIVideoResolutionChange");
291 };
292
293 auto&& startRenderFrameEvent = [weak, uiTaskExecutor, instanceId]() {
294 uiTaskExecutor.PostSyncTask([weak, instanceId] {
295 auto video = weak.Upgrade();
296 CHECK_NULL_VOID(video);
297 ContainerScope scope(instanceId);
298 video->OnStartRenderFrameCb();
299 }, "ArkUIVideoStartRenderFrame");
300 };
301
302 mediaPlayer->RegisterMediaPlayerEvent(
303 positionUpdatedEvent, stateChangedEvent, errorEvent, resolutionChangeEvent, startRenderFrameEvent);
304 }
305 } // namespace
306
VideoPattern(const RefPtr<VideoControllerV2> & videoController)307 VideoPattern::VideoPattern(const RefPtr<VideoControllerV2>& videoController)
308 : instanceId_(Container::CurrentId()), videoControllerV2_(videoController)
309 {}
310
ResetMediaPlayerOnBg()311 void VideoPattern::ResetMediaPlayerOnBg()
312 {
313 CHECK_NULL_VOID(mediaPlayer_);
314 SetIsPrepared(false);
315 ContainerScope scope(instanceId_);
316 auto host = GetHost();
317 CHECK_NULL_VOID(host);
318 auto context = host->GetContext();
319 CHECK_NULL_VOID(context);
320 VideoSourceInfo videoSrc = {videoSrcInfo_.src_, videoSrcInfo_.bundleName_, videoSrcInfo_.moduleName_};
321
322 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
323 auto bgTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
324 bgTaskExecutor.PostTask(
325 [weak = WeakClaim(this), mediaPlayerWeak = WeakClaim(AceType::RawPtr(mediaPlayer_)),
326 videoSrc, id = instanceId_, showFirstFrame = showFirstFrame_, uiTaskExecutor] {
327 auto mediaPlayer = mediaPlayerWeak.Upgrade();
328 CHECK_NULL_VOID(mediaPlayer);
329 mediaPlayer->ResetMediaPlayer();
330
331 RegisterMediaPlayerEvent(weak, mediaPlayer, videoSrc.src_, id);
332
333 if (!mediaPlayer->SetSource(videoSrc.src_, videoSrc.bundleName_, videoSrc.moduleName_)) {
334 uiTaskExecutor.PostTask([weak]() {
335 auto videoPattern = weak.Upgrade();
336 CHECK_NULL_VOID(videoPattern);
337 videoPattern->FireError();
338 }, "ArkUIVideoFireError");
339 return;
340 }
341
342 uiTaskExecutor.PostSyncTask([weak, id] {
343 auto videoPattern = weak.Upgrade();
344 CHECK_NULL_VOID(videoPattern);
345 videoPattern->PrepareSurface();
346 }, "ArkUIVideoPrepareSurface");
347 mediaPlayer->SetRenderFirstFrame(showFirstFrame);
348 if (mediaPlayer->PrepareAsync() != 0) {
349 TAG_LOGE(AceLogTag::ACE_VIDEO, "Player prepare failed");
350 }
351 }, "ArkUIVideoMediaPlayerReset");
352 }
353
ResetStatus()354 void VideoPattern::ResetStatus()
355 {
356 isInitialState_ = true;
357 isPlaying_ = false;
358 #ifndef OHOS_PLATFORM
359 isStop_ = false;
360 #endif
361 }
362
ResetMediaPlayer()363 void VideoPattern::ResetMediaPlayer()
364 {
365 CHECK_NULL_VOID(mediaPlayer_);
366 mediaPlayer_->ResetMediaPlayer();
367 SetIsPrepared(false);
368 if (!SetSourceForMediaPlayer()) {
369 TAG_LOGW(AceLogTag::ACE_VIDEO, "Video set source for mediaPlayer failed.");
370
371 // It need post on ui thread.
372 FireError();
373 return;
374 }
375
376 mediaPlayer_->SetRenderFirstFrame(showFirstFrame_);
377 RegisterMediaPlayerEvent(WeakClaim(this), mediaPlayer_, videoSrcInfo_.src_, instanceId_);
378 PrepareSurface();
379 if (mediaPlayer_ && mediaPlayer_->PrepareAsync() != 0) {
380 TAG_LOGE(AceLogTag::ACE_VIDEO, "Player prepare failed");
381 }
382 }
383
UpdateMediaPlayerOnBg()384 void VideoPattern::UpdateMediaPlayerOnBg()
385 {
386 PrepareMediaPlayer();
387 UpdateSpeed();
388 UpdateLooping();
389 UpdateMuted();
390 if (isInitialState_ && autoPlay_) {
391 // When video is autoPlay, start playing the video when it is initial state.
392 Start();
393 }
394 }
395
PrepareMediaPlayer()396 void VideoPattern::PrepareMediaPlayer()
397 {
398 auto videoLayoutProperty = GetLayoutProperty<VideoLayoutProperty>();
399 CHECK_NULL_VOID(videoLayoutProperty);
400 // src has not set/changed
401 if (!videoLayoutProperty->HasVideoSource() || videoLayoutProperty->GetVideoSource() == videoSrcInfo_) {
402 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] source is null or the source has not changed.", hostId_);
403 return;
404 }
405 auto videoSrcInfo = videoLayoutProperty->GetVideoSourceValue(VideoSourceInfo());
406 videoSrcInfo_.src_ = videoSrcInfo.src_;
407 videoSrcInfo_.bundleName_ = videoSrcInfo.bundleName_;
408 videoSrcInfo_.moduleName_ = videoSrcInfo.moduleName_;
409 if (mediaPlayer_ && !mediaPlayer_->IsMediaPlayerValid()) {
410 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] create MediaPlayer.", hostId_);
411 mediaPlayer_->CreateMediaPlayer();
412 }
413
414 if (mediaPlayer_ && !mediaPlayer_->IsMediaPlayerValid()) {
415 // It need post on ui thread.
416 FireError();
417 return;
418 }
419
420 ResetStatus();
421 ResetMediaPlayerOnBg();
422 }
423
SetSourceForMediaPlayer()424 bool VideoPattern::SetSourceForMediaPlayer()
425 {
426 CHECK_NULL_RETURN(mediaPlayer_, false);
427 return mediaPlayer_->SetSource(videoSrcInfo_.src_, videoSrcInfo_.bundleName_, videoSrcInfo_.moduleName_);
428 }
429
RegisterMediaPlayerEvent(const WeakPtr<VideoPattern> & weak,const RefPtr<MediaPlayer> & mediaPlayer,const std::string & videoSrc,int32_t instanceId)430 void VideoPattern::RegisterMediaPlayerEvent(const WeakPtr<VideoPattern>& weak, const RefPtr<MediaPlayer>& mediaPlayer,
431 const std::string& videoSrc, int32_t instanceId)
432 {
433 if (videoSrc.empty() || !mediaPlayer) {
434 TAG_LOGW(AceLogTag::ACE_VIDEO, "Video src is empty or mediaPlayer is null, register mediaPlayerEvent fail");
435 return;
436 }
437
438 auto context = PipelineContext::GetCurrentContext();
439 CHECK_NULL_VOID(context);
440 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
441 RegisterMediaPlayerEventImpl(weak, mediaPlayer, instanceId, uiTaskExecutor);
442
443 auto&& seekDoneEvent = [weak, uiTaskExecutor, instanceId](uint32_t currentPos) {
444 uiTaskExecutor.PostSyncTask(
445 [&weak, currentPos, instanceId] {
446 auto video = weak.Upgrade();
447 CHECK_NULL_VOID(video);
448 ContainerScope scope(instanceId);
449 video->SetIsSeeking(false);
450 video->OnCurrentTimeChange(currentPos);
451 }, "ArkUIVideoSeekDone");
452 };
453 mediaPlayer->RegisterMediaPlayerSeekDoneEvent(std::move(seekDoneEvent));
454
455 #ifdef RENDER_EXTRACT_SUPPORTED
456 auto&& textureRefreshEvent = [weak, uiTaskExecutor](int32_t instanceId, int64_t textureId) {
457 uiTaskExecutor.PostSyncTask(
458 [&weak, instanceId, textureId] {
459 auto video = weak.Upgrade();
460 CHECK_NULL_VOID(video);
461 void* nativeWindow = video->GetNativeWindow(instanceId, textureId);
462 if (!nativeWindow) {
463 LOGE("the native window is nullptr.");
464 return;
465 }
466 video->OnTextureRefresh(nativeWindow);
467 }, "ArkUIVideoTextureRefresh");
468 };
469 mediaPlayer->RegisterTextureEvent(textureRefreshEvent);
470 #endif
471 }
472
473 #ifdef RENDER_EXTRACT_SUPPORTED
GetNativeWindow(int32_t instanceId,int64_t textureId)474 void* VideoPattern::GetNativeWindow(int32_t instanceId, int64_t textureId)
475 {
476 auto container = AceEngine::Get().GetContainer(instanceId);
477 CHECK_NULL_RETURN(container, nullptr);
478 auto nativeView = container->GetAceView();
479 CHECK_NULL_RETURN(nativeView, nullptr);
480 return const_cast<void*>(nativeView->GetNativeWindowById(textureId));
481 }
482
OnTextureRefresh(void * surface)483 void VideoPattern::OnTextureRefresh(void* surface)
484 {
485 CHECK_NULL_VOID(surface);
486 auto renderContextForMediaPlayer = renderContextForMediaPlayerWeakPtr_.Upgrade();
487 CHECK_NULL_VOID(renderContextForMediaPlayer);
488 renderContextForMediaPlayer->MarkNewFrameAvailable(surface);
489 }
490 #endif
491
PrintPlayerStatus(PlaybackStatus status)492 void VideoPattern::PrintPlayerStatus(PlaybackStatus status)
493 {
494 switch (status) {
495 case PlaybackStatus::ERROR:
496 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is ERROR.", hostId_);
497 break;
498 case PlaybackStatus::IDLE:
499 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is IDLE.", hostId_);
500 break;
501 case PlaybackStatus::PREPARED:
502 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is PREPARED.", hostId_);
503 break;
504 case PlaybackStatus::STARTED:
505 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is STARTED.", hostId_);
506 break;
507 case PlaybackStatus::PAUSED:
508 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is PAUSED.", hostId_);
509 break;
510 case PlaybackStatus::STOPPED:
511 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is STOPPED.", hostId_);
512 break;
513 case PlaybackStatus::PLAYBACK_COMPLETE:
514 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is PLAYBACK_COMPLETE.", hostId_);
515 break;
516 case PlaybackStatus::NONE:
517 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] Player current status is NONE.", hostId_);
518 break;
519 default:
520 TAG_LOGW(AceLogTag::ACE_VIDEO, "Video[%{public}d] Invalid player status.", hostId_);
521 break;
522 }
523 }
524
OnCurrentTimeChange(uint32_t currentPos)525 void VideoPattern::OnCurrentTimeChange(uint32_t currentPos)
526 {
527 isInitialState_ = isInitialState_ ? currentPos == 0 : false;
528 if (currentPos == currentPos_ || isStop_) {
529 return;
530 }
531
532 if (duration_ == 0) {
533 int32_t duration = 0;
534 if (mediaPlayer_ && mediaPlayer_->GetDuration(duration) == 0) {
535 duration_ = static_cast<uint32_t>(duration / MILLISECONDS_TO_SECONDS);
536 OnUpdateTime(duration_, DURATION_POS);
537 }
538 }
539
540 OnUpdateTime(currentPos, CURRENT_POS);
541 currentPos_ = isSeeking_ ? currentPos_ : currentPos;
542 auto eventHub = GetEventHub<VideoEventHub>();
543 CHECK_NULL_VOID(eventHub);
544 auto json = JsonUtil::Create(true);
545 json->Put("time", static_cast<double>(currentPos));
546 auto param = json->ToString();
547 eventHub->FireUpdateEvent(param);
548 }
549
ChangePlayerStatus(bool isPlaying,const PlaybackStatus & status)550 void VideoPattern::ChangePlayerStatus(bool isPlaying, const PlaybackStatus& status)
551 {
552 if (isPlaying) {
553 auto json = JsonUtil::Create(true);
554 json->Put("start", "");
555 auto param = json->ToString();
556 auto eventHub = GetEventHub<VideoEventHub>();
557 CHECK_NULL_VOID(eventHub);
558 eventHub->FireStartEvent(param);
559 }
560
561 if (status == PlaybackStatus::PAUSED) {
562 auto json = JsonUtil::Create(true);
563 json->Put("pause", "");
564 auto param = json->ToString();
565 auto eventHub = GetEventHub<VideoEventHub>();
566 CHECK_NULL_VOID(eventHub);
567 eventHub->FirePauseEvent(param);
568 }
569
570 if (status == PlaybackStatus::STOPPED) {
571 auto json = JsonUtil::Create(true);
572 json->Put("stop", "");
573 auto param = json->ToString();
574 auto eventHub = GetEventHub<VideoEventHub>();
575 CHECK_NULL_VOID(eventHub);
576 eventHub->FireStopEvent(param);
577 }
578
579 if (status == PlaybackStatus::PREPARED) {
580 ContainerScope scope(instanceId_);
581 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
582 return;
583 }
584 int32_t milliSecondDuration = 0;
585 mediaPlayer_->GetDuration(milliSecondDuration);
586 OnPrepared(milliSecondDuration / MILLISECONDS_TO_SECONDS, 0, true);
587 return;
588 }
589
590 if (status == PlaybackStatus::PLAYBACK_COMPLETE) {
591 OnCompletion();
592 }
593 }
594
OnPlayerStatus(PlaybackStatus status)595 void VideoPattern::OnPlayerStatus(PlaybackStatus status)
596 {
597 PrintPlayerStatus(status);
598 bool isPlaying = (status == PlaybackStatus::STARTED);
599 if (isPlaying_ != isPlaying) {
600 isPlaying_ = isPlaying;
601 ChangePlayButtonTag();
602 }
603
604 if (isInitialState_) {
605 isInitialState_ = !isPlaying;
606 }
607
608 ChangePlayerStatus(isPlaying, status);
609 }
610
OnError(const std::string & errorId)611 void VideoPattern::OnError(const std::string& errorId)
612 {
613 auto host = GetHost();
614 CHECK_NULL_VOID(host);
615 auto video = AceType::DynamicCast<VideoNode>(host);
616 CHECK_NULL_VOID(video);
617 auto column = AceType::DynamicCast<FrameNode>(video->GetMediaColumn());
618 CHECK_NULL_VOID(column);
619 auto renderContext = column->GetRenderContext();
620 renderContext->AddChild(renderContextForMediaPlayer_, 0);
621 auto pipeline = host->GetContext();
622 CHECK_NULL_VOID(pipeline);
623 pipeline->RequestFrame();
624
625 std::string errorcode = Localization::GetInstance()->GetErrorDescription(errorId);
626 auto json = JsonUtil::Create(true);
627 json->Put("error", "");
628 auto param = json->ToString();
629 auto eventHub = GetEventHub<VideoEventHub>();
630 CHECK_NULL_VOID(eventHub);
631 eventHub->FireErrorEvent(param);
632 }
633
OnResolutionChange() const634 void VideoPattern::OnResolutionChange() const
635 {
636 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
637 return;
638 }
639 auto host = GetHost();
640 CHECK_NULL_VOID(host);
641 auto videoLayoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
642 CHECK_NULL_VOID(videoLayoutProperty);
643 auto preVideoSize = videoLayoutProperty->GetVideoSize();
644 if (!preVideoSize.has_value()) {
645 SizeF videoSize = SizeF(
646 static_cast<float>(mediaPlayer_->GetVideoWidth()),
647 static_cast<float>(mediaPlayer_->GetVideoHeight()));
648 videoLayoutProperty->UpdateVideoSize(videoSize);
649 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
650 }
651 }
652
OnStartRenderFrameCb()653 void VideoPattern::OnStartRenderFrameCb()
654 {
655 isInitialState_ = false;
656 auto host = GetHost();
657 CHECK_NULL_VOID(host);
658 auto video = AceType::DynamicCast<VideoNode>(host);
659 CHECK_NULL_VOID(video);
660 auto image = AceType::DynamicCast<FrameNode>(video->GetPreviewImage());
661 CHECK_NULL_VOID(image);
662 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
663 CHECK_NULL_VOID(posterLayoutProperty);
664 posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
665 image->MarkModifyDone();
666 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
667 return;
668 }
669 auto videoLayoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
670 CHECK_NULL_VOID(videoLayoutProperty);
671 SizeF videoSize =
672 SizeF(static_cast<float>(mediaPlayer_->GetVideoWidth()), static_cast<float>(mediaPlayer_->GetVideoHeight()));
673 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] start render frame size:%{public}s", hostId_,
674 videoSize.ToString().c_str());
675 videoLayoutProperty->UpdateVideoSize(videoSize);
676 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
677 }
678
OnPrepared(uint32_t duration,uint32_t currentPos,bool needFireEvent)679 void VideoPattern::OnPrepared(uint32_t duration, uint32_t currentPos, bool needFireEvent)
680 {
681 auto host = GetHost();
682 CHECK_NULL_VOID(host);
683 CHECK_NULL_VOID(mediaPlayer_);
684
685 duration_ = duration;
686 currentPos_ = currentPos;
687 isInitialState_ = currentPos != 0 ? false : isInitialState_;
688 isPlaying_ = mediaPlayer_->IsPlaying();
689 SetIsSeeking(false);
690 SetIsPrepared(true);
691 OnUpdateTime(duration_, DURATION_POS);
692 OnUpdateTime(currentPos_, CURRENT_POS);
693
694 RefPtr<UINode> controlBar = nullptr;
695 auto children = host->GetChildren();
696 for (const auto& child : children) {
697 if (child->GetTag() == V2::ROW_ETS_TAG) {
698 controlBar = child;
699 break;
700 }
701 }
702 CHECK_NULL_VOID(controlBar);
703 auto sliderNode = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(SLIDER_POS));
704 auto sliderPaintProperty = sliderNode->GetPaintProperty<SliderPaintProperty>();
705 CHECK_NULL_VOID(sliderPaintProperty);
706 sliderPaintProperty->UpdateMin(0.0f);
707 sliderPaintProperty->UpdateMax(static_cast<float>(duration_));
708 sliderNode->MarkModifyDone();
709 auto playBtn = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(0));
710 ChangePlayButtonTag(playBtn);
711
712 if (needFireEvent) {
713 auto json = JsonUtil::Create(true);
714 json->Put("duration", static_cast<double>(duration_));
715 auto param = json->ToString();
716 auto eventHub = GetEventHub<VideoEventHub>();
717 CHECK_NULL_VOID(eventHub);
718 eventHub->FirePreparedEvent(param);
719 }
720 TAG_LOGI(AceLogTag::ACE_VIDEO,
721 "Video[%{public}d] duration: %{public}u, loop: %{public}d, muted: %{public}d, Speed: %{public}f", hostId_,
722 duration_, loop_, muted_, progressRate_);
723 UpdateLooping();
724 UpdateSpeed();
725 UpdateMuted();
726
727 checkNeedAutoPlay();
728 }
729
checkNeedAutoPlay()730 void VideoPattern::checkNeedAutoPlay()
731 {
732 if (isStop_) {
733 isStop_ = false;
734 }
735 if (autoPlay_) {
736 Start();
737 }
738 }
739
OnCompletion()740 void VideoPattern::OnCompletion()
741 {
742 isPlaying_ = false;
743 currentPos_ = duration_;
744 OnUpdateTime(currentPos_, CURRENT_POS);
745 auto json = JsonUtil::Create(true);
746 json->Put("finish", "");
747 auto param = json->ToString();
748 auto eventHub = GetEventHub<VideoEventHub>();
749 CHECK_NULL_VOID(eventHub);
750 eventHub->FireFinishEvent(param);
751 }
752
HasPlayer() const753 bool VideoPattern::HasPlayer() const
754 {
755 return mediaPlayer_ != nullptr;
756 }
757
HiddenChange(bool hidden)758 void VideoPattern::HiddenChange(bool hidden)
759 {
760 if (isPlaying_ && hidden && HasPlayer()) {
761 pastPlayingStatus_ = isPlaying_;
762 Pause();
763 return;
764 }
765
766 if (!hidden && pastPlayingStatus_) {
767 pastPlayingStatus_ = false;
768 Start();
769 }
770 }
771
OnVisibleChange(bool isVisible)772 void VideoPattern::OnVisibleChange(bool isVisible)
773 {
774 if (hiddenChangeEvent_) {
775 hiddenChangeEvent_(!isVisible);
776 }
777 }
778
UpdateLooping()779 void VideoPattern::UpdateLooping()
780 {
781 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid()) {
782 ContainerScope scope(instanceId_);
783 auto host = GetHost();
784 CHECK_NULL_VOID(host);
785 auto context = host->GetContext();
786 CHECK_NULL_VOID(context);
787 auto bgTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
788 bgTaskExecutor.PostTask([weak = WeakClaim(RawPtr(mediaPlayer_)), loop = loop_] {
789 auto mediaPlayer = weak.Upgrade();
790 CHECK_NULL_VOID(mediaPlayer);
791 mediaPlayer->SetLooping(loop);
792 }, "ArkUIVideoUpdateLooping");
793 }
794 }
795
SetSurfaceBackgroundColor(Color color)796 void VideoPattern::SetSurfaceBackgroundColor(Color color)
797 {
798 CHECK_NULL_VOID(renderContextForMediaPlayer_);
799 renderContextForMediaPlayer_->UpdateBackgroundColor(color);
800 }
801
UpdateSpeed()802 void VideoPattern::UpdateSpeed()
803 {
804 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid()) {
805 ContainerScope scope(instanceId_);
806 auto host = GetHost();
807 CHECK_NULL_VOID(host);
808 auto context = host->GetContext();
809 CHECK_NULL_VOID(context);
810 auto bgTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
811 bgTaskExecutor.PostTask([weak = WeakClaim(RawPtr(mediaPlayer_)), progress = progressRate_] {
812 auto mediaPlayer = weak.Upgrade();
813 CHECK_NULL_VOID(mediaPlayer);
814 mediaPlayer->SetPlaybackSpeed(static_cast<float>(progress));
815 }, "ArkUIVideoUpdateSpeed");
816 }
817 }
818
UpdateMuted()819 void VideoPattern::UpdateMuted()
820 {
821 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid()) {
822 ContainerScope scope(instanceId_);
823 auto host = GetHost();
824 CHECK_NULL_VOID(host);
825 auto context = host->GetContext();
826 CHECK_NULL_VOID(context);
827 auto bgTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
828 bgTaskExecutor.PostTask(
829 [weak = WeakClaim(RawPtr(mediaPlayer_)), isMuted = muted_, currentVolume = currentVolume_] {
830 auto mediaPlayer = weak.Upgrade();
831 CHECK_NULL_VOID(mediaPlayer);
832 if (isMuted || NearZero(currentVolume)) {
833 mediaPlayer->SetMediaMuted(MEDIA_TYPE_AUD, true);
834 mediaPlayer->SetVolume(0.0f, 0.0f);
835 } else {
836 mediaPlayer->SetMediaMuted(MEDIA_TYPE_AUD, false);
837 mediaPlayer->SetVolume(currentVolume, currentVolume);
838 }
839 },
840 "ArkUIVideoUpdateMuted");
841 }
842 }
843
OnUpdateTime(uint32_t time,int pos) const844 void VideoPattern::OnUpdateTime(uint32_t time, int pos) const
845 {
846 auto host = GetHost();
847 CHECK_NULL_VOID(host);
848 auto layoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
849 CHECK_NULL_VOID(layoutProperty);
850 bool needControlBar = layoutProperty->GetControlsValue(true);
851 if (!needControlBar) {
852 return;
853 }
854
855 RefPtr<UINode> controlBar = nullptr;
856 auto children = host->GetChildren();
857 for (const auto& child : children) {
858 if (child->GetTag() == V2::ROW_ETS_TAG) {
859 controlBar = child;
860 break;
861 }
862 }
863
864 CHECK_NULL_VOID(controlBar);
865 auto durationNode = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(pos));
866 CHECK_NULL_VOID(durationNode);
867 auto textLayoutProperty = durationNode->GetLayoutProperty<TextLayoutProperty>();
868 CHECK_NULL_VOID(textLayoutProperty);
869 std::string timeText = IntTimeToText(time);
870 textLayoutProperty->UpdateContent(timeText);
871 durationNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
872 durationNode->MarkModifyDone();
873 // if current status is seeking, no need to update slider's value
874 if (pos == CURRENT_POS && !isSeeking_) {
875 auto sliderNode = DynamicCast<FrameNode>(controlBar->GetChildAtIndex(SLIDER_POS));
876 CHECK_NULL_VOID(sliderNode);
877 auto sliderPattern = sliderNode->GetPattern<SliderPattern>();
878 CHECK_NULL_VOID(sliderPattern);
879 sliderPattern->UpdateValue(static_cast<float>(time));
880 sliderNode->MarkModifyDone();
881 }
882 }
883
PrepareSurface()884 void VideoPattern::PrepareSurface()
885 {
886 if (!mediaPlayer_ || renderSurface_->IsSurfaceValid()) {
887 return;
888 }
889 if (!SystemProperties::GetExtSurfaceEnabled()) {
890 renderSurface_->SetRenderContext(renderContextForMediaPlayer_);
891 }
892 renderSurface_->InitSurface();
893 mediaPlayer_->SetRenderSurface(renderSurface_);
894 if (mediaPlayer_->SetSurface() != 0) {
895 TAG_LOGW(AceLogTag::ACE_VIDEO, "mediaPlayer renderSurface set failed");
896 }
897 }
898
OnAttachToFrameNode()899 void VideoPattern::OnAttachToFrameNode()
900 {
901 // full screen node is not supposed to register js controller event
902 if (!InstanceOf<VideoFullScreenPattern>(this)) {
903 SetMethodCall();
904 }
905 auto host = GetHost();
906 CHECK_NULL_VOID(host);
907 hostId_ = host->GetId();
908 auto pipeline = host->GetContext();
909 CHECK_NULL_VOID(pipeline);
910 pipeline->AddWindowStateChangedCallback(host->GetId());
911 auto renderContext = host->GetRenderContext();
912 CHECK_NULL_VOID(renderContext);
913
914 #ifdef RENDER_EXTRACT_SUPPORTED
915 CHECK_NULL_VOID(renderSurface_);
916 auto contextType = renderSurface_->IsTexture() ?
917 RenderContext::ContextType::HARDWARE_TEXTURE : RenderContext::ContextType::HARDWARE_SURFACE;
918 static RenderContext::ContextParam param = { contextType, "MediaPlayerSurface",
919 RenderContext::PatternType::VIDEO };
920 #else
921 static RenderContext::ContextParam param = { RenderContext::ContextType::HARDWARE_SURFACE, "MediaPlayerSurface",
922 RenderContext::PatternType::VIDEO };
923 #endif
924 renderContextForMediaPlayer_->InitContext(false, param);
925
926 if (SystemProperties::GetExtSurfaceEnabled()) {
927 RegisterRenderContextCallBack();
928 }
929
930 renderContext->UpdateBackgroundColor(Color::BLACK);
931 renderContextForMediaPlayer_->UpdateBackgroundColor(Color::BLACK);
932 renderContext->SetClipToBounds(true);
933 }
934
OnDetachFromFrameNode(FrameNode * frameNode)935 void VideoPattern::OnDetachFromFrameNode(FrameNode* frameNode)
936 {
937 CHECK_NULL_VOID(frameNode);
938 auto id = frameNode->GetId();
939 auto pipeline = frameNode->GetContext();
940 CHECK_NULL_VOID(pipeline);
941 pipeline->RemoveWindowStateChangedCallback(id);
942 }
943
OnDetachFromMainTree()944 void VideoPattern::OnDetachFromMainTree()
945 {
946 auto host = GetHost();
947 if (host && host->GetNodeStatus() == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
948 Pause();
949 }
950 }
951
RegisterRenderContextCallBack()952 void VideoPattern::RegisterRenderContextCallBack()
953 {
954 #ifdef RENDER_EXTRACT_SUPPORTED
955 renderSurfaceWeakPtr_ = renderSurface_;
956 renderContextForMediaPlayerWeakPtr_ = renderContextForMediaPlayer_;
957 auto OnAttachCallBack = [weak = WeakClaim(this)](int64_t textureId, bool isAttach) mutable {
958 auto videoPattern = weak.Upgrade();
959 CHECK_NULL_VOID(videoPattern);
960 if (auto renderSurface = videoPattern->renderSurfaceWeakPtr_.Upgrade(); renderSurface) {
961 renderSurface->AttachToGLContext(textureId, isAttach);
962 }
963 };
964 renderContextForMediaPlayer_->AddAttachCallBack(OnAttachCallBack);
965 auto OnUpdateCallBack = [weak = WeakClaim(this)](std::vector<float>& matrix) mutable {
966 auto videoPattern = weak.Upgrade();
967 CHECK_NULL_VOID(videoPattern);
968 if (auto renderSurface = videoPattern->renderSurfaceWeakPtr_.Upgrade(); renderSurface) {
969 renderSurface->UpdateTextureImage(matrix);
970 }
971 };
972 renderContextForMediaPlayer_->AddUpdateCallBack(OnUpdateCallBack);
973 #endif
974 }
975
OnModifyDone()976 void VideoPattern::OnModifyDone()
977 {
978 Pattern::OnModifyDone();
979
980 if (!hiddenChangeEvent_) {
981 SetHiddenChangeEvent(CreateHiddenChangeEvent());
982 }
983
984 // src has changed
985 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
986 #ifdef RENDER_EXTRACT_SUPPORTED
987 if ((layoutProperty && layoutProperty->HasVideoSource() && layoutProperty->GetVideoSource() != videoSrcInfo_)) {
988 #else
989 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
990 (layoutProperty && layoutProperty->HasVideoSource() && layoutProperty->GetVideoSource() != videoSrcInfo_)) {
991 #endif
992 ResetStatus();
993 }
994
995 // update full screen pattern state
996 UpdateFsState();
997
998 // Update the control bar and preview image.
999 UpdatePreviewImage();
1000 UpdateControllerBar();
1001 auto host = GetHost();
1002 CHECK_NULL_VOID(host);
1003 // Update the media player when video node is not in full screen or current node is full screen node
1004 if (!fullScreenNodeId_.has_value() || InstanceOf<VideoFullScreenNode>(this)) {
1005 ContainerScope scope(instanceId_);
1006 auto pipelineContext = host->GetContext();
1007 CHECK_NULL_VOID(pipelineContext);
1008 auto uiTaskExecutor = SingleTaskExecutor::Make(pipelineContext->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1009 uiTaskExecutor.PostTask([weak = WeakClaim(this)]() {
1010 auto videoPattern = weak.Upgrade();
1011 CHECK_NULL_VOID(videoPattern);
1012 ContainerScope scope(videoPattern->instanceId_);
1013 videoPattern->UpdateMediaPlayerOnBg();
1014 }, "ArkUIVideoUpdateMediaPlayer");
1015 }
1016
1017 if (SystemProperties::GetExtSurfaceEnabled()) {
1018 auto pipelineContext = host->GetContext();
1019 CHECK_NULL_VOID(pipelineContext);
1020 pipelineContext->AddOnAreaChangeNode(host->GetId());
1021 }
1022 auto eventHub = GetEventHub<VideoEventHub>();
1023 if (!AceType::InstanceOf<VideoFullScreenPattern>(this)) {
1024 auto host = GetHost();
1025 CHECK_NULL_VOID(host);
1026 eventHub->SetInspectorId(host->GetInspectorIdValue(""));
1027 }
1028 if (!IsSupportImageAnalyzer()) {
1029 DestroyAnalyzerOverlay();
1030 } else if (isPaused_ && !isPlaying_ && !GetAnalyzerState()) {
1031 StartImageAnalyzer();
1032 }
1033 InitKeyEvent();
1034 }
1035
1036 void VideoPattern::InitKeyEvent()
1037 {
1038 auto host = GetHost();
1039 CHECK_NULL_VOID(host);
1040 auto focusHub = host->GetOrCreateFocusHub();
1041 CHECK_NULL_VOID(focusHub);
1042 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1043 auto pattern = wp.Upgrade();
1044 CHECK_NULL_RETURN(pattern, false);
1045 return pattern->OnKeyEvent(event);
1046 };
1047 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1048 }
1049
1050 bool VideoPattern::OnKeyEvent(const KeyEvent& event)
1051 {
1052 if (isEnableShortcutKey_ && event.action == KeyAction::DOWN) {
1053 TAG_LOGD(AceLogTag::ACE_VIDEO, "video on key event %{public}d", event.code);
1054 if (event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT) {
1055 MoveByStep(event.code == KeyCode::KEY_DPAD_LEFT ? -1 : 1);
1056 return true;
1057 }
1058 if (event.code == KeyCode::KEY_DPAD_DOWN || event.code == KeyCode::KEY_DPAD_UP) {
1059 AdjustVolume(event.code == KeyCode::KEY_DPAD_DOWN ? -1 : 1);
1060 return true;
1061 }
1062 if (event.code == KeyCode::KEY_SPACE) {
1063 OnKeySpaceEvent();
1064 return true;
1065 }
1066 }
1067 return false;
1068 }
1069
1070 bool VideoPattern::HandleSliderKeyEvent(const KeyEventInfo& event)
1071 {
1072 if (isEnableShortcutKey_ && event.GetKeyType() == KeyAction::DOWN) {
1073 TAG_LOGD(AceLogTag::ACE_VIDEO, "slider on key event %{public}d", event.GetKeyCode());
1074 if (event.GetKeyCode() == KeyCode::KEY_SPACE) {
1075 OnKeySpaceEvent();
1076 return true;
1077 }
1078 }
1079 return false;
1080 }
1081
1082 void VideoPattern::OnKeySpaceEvent()
1083 {
1084 if (isPlaying_) {
1085 Pause();
1086 } else {
1087 Start();
1088 }
1089 }
1090
1091 void VideoPattern::MoveByStep(int32_t step)
1092 {
1093 auto targetTime = static_cast<int32_t>(currentPos_) + step;
1094 if (0 <= targetTime && targetTime <= static_cast<int32_t>(duration_)) {
1095 SetCurrentTime(static_cast<float>(targetTime), OHOS::Ace::SeekMode::SEEK_CLOSEST);
1096 }
1097 }
1098
1099 void VideoPattern::AdjustVolume(int32_t step)
1100 {
1101 // the volume ranges from 0 to 1. each step is VOLUME_STEP(0.05).
1102 float targetVolume = currentVolume_ + step * VOLUME_STEP;
1103 if (LessNotEqual(targetVolume, 0.0f) || GreatNotEqual(targetVolume, 1.0f)) {
1104 return;
1105 }
1106 CHECK_NULL_VOID(mediaPlayer_);
1107 if (NearZero(targetVolume)) {
1108 mediaPlayer_->SetMediaMuted(MEDIA_TYPE_AUD, true);
1109 } else {
1110 mediaPlayer_->SetMediaMuted(MEDIA_TYPE_AUD, false);
1111 }
1112 mediaPlayer_->SetVolume(targetVolume, targetVolume);
1113 currentVolume_ = targetVolume;
1114 }
1115
1116 HiddenChangeEvent VideoPattern::CreateHiddenChangeEvent()
1117 {
1118 return [weak = WeakClaim(this)](bool hidden) {
1119 auto videoPattern = weak.Upgrade();
1120 CHECK_NULL_VOID(videoPattern);
1121 auto fullScreenNode = videoPattern->GetFullScreenNode();
1122 if (fullScreenNode) {
1123 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(fullScreenNode->GetPattern());
1124 CHECK_NULL_VOID(fullScreenPattern);
1125 fullScreenPattern->HiddenChange(hidden);
1126 return;
1127 }
1128 videoPattern->HiddenChange(hidden);
1129 };
1130 }
1131
1132 void VideoPattern::UpdatePreviewImage()
1133 {
1134 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1135 CHECK_NULL_VOID(layoutProperty);
1136 if (!layoutProperty->HasPosterImageInfo()) {
1137 return;
1138 }
1139 auto posterSourceInfo = layoutProperty->GetPosterImageInfo().value();
1140 auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
1141 auto host = GetHost();
1142 CHECK_NULL_VOID(host);
1143
1144 auto video = AceType::DynamicCast<VideoNode>(host);
1145 CHECK_NULL_VOID(video);
1146 auto image = AceType::DynamicCast<FrameNode>(video->GetPreviewImage());
1147 CHECK_NULL_VOID(image);
1148
1149 if (showFirstFrame_) {
1150 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1151 CHECK_NULL_VOID(posterLayoutProperty);
1152 posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1153 image->MarkModifyDone();
1154 return;
1155 }
1156
1157 if (!isInitialState_) {
1158 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1159 CHECK_NULL_VOID(posterLayoutProperty);
1160 posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1161 image->MarkModifyDone();
1162 return;
1163 }
1164
1165 if (!posterSourceInfo.IsValid()) {
1166 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1167 CHECK_NULL_VOID(posterLayoutProperty);
1168 posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1169 image->MarkModifyDone();
1170 TAG_LOGI(AceLogTag::ACE_VIDEO, "Src image is not valid.");
1171 return;
1172 }
1173
1174 if (image) {
1175 image->SetDraggable(false);
1176 auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1177 CHECK_NULL_VOID(posterLayoutProperty);
1178 posterLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1179 posterLayoutProperty->UpdateImageSourceInfo(posterSourceInfo);
1180 posterLayoutProperty->UpdateImageFit(imageFit);
1181 image->MarkModifyDone();
1182 }
1183 }
1184
1185 void VideoPattern::UpdateControllerBar()
1186 {
1187 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1188 CHECK_NULL_VOID(layoutProperty);
1189 auto host = GetHost();
1190 CHECK_NULL_VOID(host);
1191 auto focusHub = host->GetOrCreateFocusHub();
1192 CHECK_NULL_VOID(focusHub);
1193 auto needControlBar = layoutProperty->GetControlsValue(true);
1194 focusHub->SetFocusType(needControlBar ? FocusType::SCOPE : FocusType::NODE);
1195 auto video = AceType::DynamicCast<VideoNode>(host);
1196 CHECK_NULL_VOID(video);
1197 auto controller = AceType::DynamicCast<FrameNode>(video->GetControllerRow());
1198 CHECK_NULL_VOID(controller);
1199 if (needControlBar) {
1200 auto sliderNode = DynamicCast<FrameNode>(controller->GetChildAtIndex(SLIDER_POS));
1201 CHECK_NULL_VOID(sliderNode);
1202 auto sliderPattern = sliderNode->GetPattern<SliderPattern>();
1203 CHECK_NULL_VOID(sliderPattern);
1204 sliderPattern->UpdateValue(static_cast<float>(currentPos_));
1205 sliderNode->MarkModifyDone();
1206
1207 auto textNode = DynamicCast<FrameNode>(controller->GetChildAtIndex(CURRENT_POS));
1208 CHECK_NULL_VOID(textNode);
1209 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1210 CHECK_NULL_VOID(textLayoutProperty);
1211 std::string label = IntTimeToText(currentPos_);
1212 textLayoutProperty->UpdateContent(label);
1213
1214 auto durationNode = DynamicCast<FrameNode>(controller->GetChildAtIndex(DURATION_POS));
1215 CHECK_NULL_VOID(durationNode);
1216 auto durationTextLayoutProperty = durationNode->GetLayoutProperty<TextLayoutProperty>();
1217 CHECK_NULL_VOID(durationTextLayoutProperty);
1218 std::string durationText = IntTimeToText(duration_);
1219 durationTextLayoutProperty->UpdateContent(durationText);
1220
1221 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1222 textNode->MarkModifyDone();
1223 durationNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1224 durationNode->MarkModifyDone();
1225 auto controllerLayoutProperty = controller->GetLayoutProperty<LinearLayoutProperty>();
1226 controllerLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1227 controller->MarkModifyDone();
1228 } else {
1229 auto controllerLayoutProperty = controller->GetLayoutProperty<LinearLayoutProperty>();
1230 controllerLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1231 controller->MarkModifyDone();
1232 }
1233 }
1234
1235 void VideoPattern::UpdateVideoProperty()
1236 {
1237 if (isInitialState_ && autoPlay_) {
1238 Start();
1239 }
1240
1241 UpdateSpeed();
1242 UpdateLooping();
1243 UpdateMuted();
1244 }
1245
1246 void VideoPattern::OnRebuildFrame()
1247 {
1248 if (!renderSurface_ || !renderSurface_->IsSurfaceValid()) {
1249 TAG_LOGW(AceLogTag::ACE_VIDEO, "MediaPlayer surface is not valid");
1250 return;
1251 }
1252 auto host = GetHost();
1253 CHECK_NULL_VOID(host);
1254 auto video = AceType::DynamicCast<VideoNode>(host);
1255 CHECK_NULL_VOID(video);
1256 auto column = AceType::DynamicCast<FrameNode>(video->GetMediaColumn());
1257 CHECK_NULL_VOID(column);
1258 auto renderContext = column->GetRenderContext();
1259 renderContext->AddChild(renderContextForMediaPlayer_, 0);
1260 }
1261
1262 void VideoPattern::RemoveMediaPlayerSurfaceNode()
1263 {
1264 auto host = GetHost();
1265 CHECK_NULL_VOID(host);
1266 auto video = AceType::DynamicCast<VideoNode>(host);
1267 CHECK_NULL_VOID(video);
1268 auto column = AceType::DynamicCast<FrameNode>(video->GetMediaColumn());
1269 CHECK_NULL_VOID(column);
1270 auto renderContext = column->GetRenderContext();
1271 renderContext->RemoveChild(renderContextForMediaPlayer_);
1272 }
1273
1274 bool VideoPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1275 {
1276 if (config.skipMeasure || dirty->SkipMeasureContent()) {
1277 return false;
1278 }
1279 auto geometryNode = dirty->GetGeometryNode();
1280 CHECK_NULL_RETURN(geometryNode, false);
1281 auto videoNodeSize = geometryNode->GetContentSize();
1282 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1283 CHECK_NULL_RETURN(layoutProperty, false);
1284 auto videoFrameSize = MeasureVideoContentLayout(videoNodeSize, layoutProperty);
1285 // Change the surface layout for drawing video frames
1286 if (renderContextForMediaPlayer_) {
1287 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1288 auto rect = AdjustPaintRect((videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE,
1289 (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE, videoFrameSize.Width(),
1290 videoFrameSize.Height(), true);
1291 renderContextForMediaPlayer_->SetBounds(rect.GetX(), rect.GetY(), rect.Width(), rect.Height());
1292 } else {
1293 renderContextForMediaPlayer_->SetBounds((videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE,
1294 (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE, videoFrameSize.Width(),
1295 videoFrameSize.Height());
1296 }
1297 }
1298
1299 if (IsSupportImageAnalyzer()) {
1300 Rect tmpRect;
1301 auto padding = layoutProperty->CreatePaddingAndBorder();
1302 auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
1303 if (imageFit == ImageFit::COVER || imageFit == ImageFit::NONE) {
1304 tmpRect = Rect(padding.left.value_or(0), padding.top.value_or(0),
1305 videoNodeSize.Width(), videoNodeSize.Height());
1306 } else {
1307 tmpRect = Rect((videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE + padding.left.value_or(0),
1308 (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE + padding.top.value_or(0),
1309 videoFrameSize.Width(), videoFrameSize.Height());
1310 }
1311 if (contentRect_ != tmpRect && ShouldUpdateImageAnalyzer()) {
1312 StartUpdateImageAnalyzer();
1313 }
1314 contentRect_ = tmpRect;
1315 UpdateAnalyzerUIConfig(geometryNode);
1316 }
1317
1318 auto host = GetHost();
1319 CHECK_NULL_RETURN(host, false);
1320 host->MarkNeedSyncRenderTree();
1321 auto video = AceType::DynamicCast<VideoNode>(host);
1322 CHECK_NULL_RETURN(video, false);
1323 auto column = AceType::DynamicCast<FrameNode>(video->GetMediaColumn());
1324 CHECK_NULL_RETURN(column, false);
1325 column->GetRenderContext()->SetClipToBounds(true);
1326 return false;
1327 }
1328
1329 void VideoPattern::OnAreaChangedInner()
1330 {
1331 if (SystemProperties::GetExtSurfaceEnabled()) {
1332 auto host = GetHost();
1333 CHECK_NULL_VOID(host);
1334 auto geometryNode = host->GetGeometryNode();
1335 CHECK_NULL_VOID(geometryNode);
1336 auto videoNodeSize = geometryNode->GetContentSize();
1337 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1338 CHECK_NULL_VOID(layoutProperty);
1339 auto videoFrameSize = MeasureVideoContentLayout(videoNodeSize, layoutProperty);
1340 auto transformRelativeOffset = host->GetTransformRelativeOffset();
1341
1342 Rect rect =
1343 Rect(transformRelativeOffset.GetX() + (videoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE,
1344 transformRelativeOffset.GetY() + (videoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE,
1345 videoFrameSize.Width(), videoFrameSize.Height());
1346 if (renderSurface_ && (rect != lastBoundsRect_)) {
1347 renderSurface_->SetExtSurfaceBounds(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1348 lastBoundsRect_ = rect;
1349 }
1350 }
1351 }
1352
1353 void VideoPattern::OnColorConfigurationUpdate()
1354 {
1355 ContainerScope scope(instanceId_);
1356 auto host = GetHost();
1357 CHECK_NULL_VOID(host);
1358 auto pipelineContext = PipelineBase::GetCurrentContext();
1359 CHECK_NULL_VOID(pipelineContext);
1360 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1361 CHECK_NULL_VOID(videoTheme);
1362 auto renderContext = controlBar_->GetRenderContext();
1363 CHECK_NULL_VOID(renderContext);
1364 renderContext->UpdateBackgroundColor(videoTheme->GetBkgColor());
1365 for (const auto& child : controlBar_->GetChildren()) {
1366 if (child->GetTag() == V2::TEXT_ETS_TAG) {
1367 auto frameNode = AceType::DynamicCast<FrameNode>(child);
1368 if (frameNode) {
1369 auto textLayoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
1370 if (textLayoutProperty) {
1371 auto textStyle = videoTheme->GetTimeTextStyle();
1372 textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
1373 }
1374 }
1375 }
1376 }
1377 host->SetNeedCallChildrenUpdate(false);
1378 host->MarkModifyDone();
1379 host->MarkDirtyNode();
1380 }
1381
1382 bool VideoPattern::NeedLift() const
1383 {
1384 auto host = GetHost();
1385 CHECK_NULL_RETURN(host, false);
1386 auto renderContext = host->GetRenderContext();
1387 CHECK_NULL_RETURN(renderContext, false);
1388 return IsFullScreen() && renderContext->IsUniRenderEnabled();
1389 }
1390
1391 RefPtr<FrameNode> VideoPattern::CreateControlBar(int32_t nodeId)
1392 {
1393 ContainerScope scope(instanceId_);
1394 auto pipelineContext = PipelineBase::GetCurrentContext();
1395 CHECK_NULL_RETURN(pipelineContext, nullptr);
1396 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1397 CHECK_NULL_RETURN(videoTheme, nullptr);
1398 auto controlBar = FrameNode::GetOrCreateFrameNode(
1399 V2::ROW_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
1400 CHECK_NULL_RETURN(controlBar, nullptr);
1401 controlBar_ = controlBar;
1402
1403 auto playButton = CreateSVG();
1404 CHECK_NULL_RETURN(playButton, nullptr);
1405 ChangePlayButtonTag(playButton);
1406 controlBar->AddChild(playButton);
1407
1408 auto currentPosText = CreateText(currentPos_);
1409 CHECK_NULL_RETURN(currentPosText, nullptr);
1410 controlBar->AddChild(currentPosText);
1411
1412 auto slider = CreateSlider();
1413 CHECK_NULL_RETURN(currentPosText, nullptr);
1414 controlBar->AddChild(slider);
1415
1416 auto durationText = CreateText(duration_);
1417 CHECK_NULL_RETURN(durationText, nullptr);
1418 controlBar->AddChild(durationText);
1419
1420 auto fullScreenButton = CreateSVG();
1421 CHECK_NULL_RETURN(fullScreenButton, nullptr);
1422 SetFullScreenButtonCallBack(fullScreenButton);
1423 ChangeFullScreenButtonTag(InstanceOf<VideoFullScreenNode>(this), fullScreenButton);
1424 controlBar->AddChild(fullScreenButton);
1425
1426 auto renderContext = controlBar->GetRenderContext();
1427 renderContext->UpdateBackgroundColor(videoTheme->GetBkgColor());
1428 auto controlBarLayoutProperty = controlBar->GetLayoutProperty<LinearLayoutProperty>();
1429 controlBarLayoutProperty->UpdateMainAxisAlign(FlexAlign::SPACE_BETWEEN);
1430 if (NeedLift()) {
1431 PaddingProperty padding;
1432 padding.bottom = CalcLength(LIFT_HEIGHT);
1433 controlBarLayoutProperty->UpdatePadding(padding);
1434 }
1435 return controlBar;
1436 }
1437
1438 RefPtr<FrameNode> VideoPattern::CreateSlider()
1439 {
1440 auto pipelineContext = PipelineBase::GetCurrentContext();
1441 CHECK_NULL_RETURN(pipelineContext, nullptr);
1442 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1443 CHECK_NULL_RETURN(videoTheme, nullptr);
1444
1445 auto sliderNode = FrameNode::CreateFrameNode(V2::SLIDER_ETS_TAG, -1, AceType::MakeRefPtr<SliderPattern>());
1446 CHECK_NULL_RETURN(sliderNode, nullptr);
1447 auto sliderLayoutProperty = sliderNode->GetLayoutProperty<SliderLayoutProperty>();
1448 CHECK_NULL_RETURN(sliderLayoutProperty, nullptr);
1449
1450 auto sliderEdge = videoTheme->GetSliderEdge();
1451 PaddingProperty padding;
1452 padding.left = CalcLength(sliderEdge.Left());
1453 padding.right = CalcLength(sliderEdge.Right());
1454 padding.top = CalcLength(sliderEdge.Top());
1455 padding.bottom = CalcLength(sliderEdge.Bottom());
1456 sliderLayoutProperty->UpdatePadding(padding);
1457 sliderLayoutProperty->UpdateLayoutWeight(1.0);
1458
1459 SliderOnChangeEvent sliderOnChangeEvent = [weak = WeakClaim(this)](float value, int32_t mode) {
1460 auto videoPattern = weak.Upgrade();
1461 CHECK_NULL_VOID(videoPattern);
1462 videoPattern->OnSliderChange(value, mode);
1463 };
1464 auto sliderEventHub = sliderNode->GetEventHub<SliderEventHub>();
1465 sliderEventHub->SetOnChange(std::move(sliderOnChangeEvent));
1466 auto focusHub = sliderNode->GetOrCreateFocusHub();
1467 CHECK_NULL_RETURN(focusHub, nullptr);
1468 if (InstanceOf<VideoFullScreenPattern>(this)) {
1469 focusHub->SetIsDefaultFocus(true);
1470 }
1471 // slider has registered click event, so it will consume KEY_SPACE event
1472 // video needs register OnKeySpaceEvent extra
1473 focusHub->SetOnKeyCallback([weak = WeakClaim(this)](const KeyEventInfo& keyEvent) -> bool {
1474 auto videoPattern = weak.Upgrade();
1475 CHECK_NULL_RETURN(videoPattern, false);
1476 return videoPattern->HandleSliderKeyEvent(keyEvent);
1477 });
1478
1479 auto sliderPaintProperty = sliderNode->GetPaintProperty<SliderPaintProperty>();
1480 CHECK_NULL_RETURN(sliderPaintProperty, nullptr);
1481 sliderPaintProperty->UpdateMax(static_cast<float>(duration_));
1482 sliderPaintProperty->UpdateSelectGradientColor(ConvertToGradient(videoTheme->GetSelectColor()));
1483 sliderPaintProperty->UpdateSelectIsResourceColor(true);
1484 sliderPaintProperty->UpdateTrackBackgroundColor(ConvertToGradient(videoTheme->GetTrackBgColor()));
1485 sliderPaintProperty->UpdateTrackBackgroundIsResourceColor(true);
1486 sliderPaintProperty->UpdateValue(static_cast<float>(currentPos_));
1487 sliderNode->MarkModifyDone();
1488 return sliderNode;
1489 }
1490
1491 RefPtr<FrameNode> VideoPattern::CreateText(uint32_t time)
1492 {
1493 auto pipelineContext = PipelineBase::GetCurrentContext();
1494 CHECK_NULL_RETURN(pipelineContext, nullptr);
1495 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1496 CHECK_NULL_RETURN(videoTheme, nullptr);
1497
1498 auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, -1, AceType::MakeRefPtr<TextPattern>());
1499 CHECK_NULL_RETURN(textNode, nullptr);
1500 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1501 CHECK_NULL_RETURN(textLayoutProperty, nullptr);
1502 auto videoLayoutProperty = GetLayoutProperty<VideoLayoutProperty>();
1503 CHECK_NULL_RETURN(videoLayoutProperty, nullptr);
1504 std::string label = "";
1505 if (videoLayoutProperty->GetControlsValue(true)) {
1506 label = IntTimeToText(time);
1507 }
1508 textLayoutProperty->UpdateContent(label);
1509 auto textEdge = videoTheme->GetTextEdge();
1510 PaddingProperty padding;
1511 padding.left = CalcLength(textEdge.Left());
1512 padding.right = CalcLength(textEdge.Right());
1513 padding.top = CalcLength(textEdge.Top());
1514 padding.bottom = CalcLength(textEdge.Bottom());
1515 textLayoutProperty->UpdatePadding(padding);
1516 auto textStyle = videoTheme->GetTimeTextStyle();
1517 textLayoutProperty->UpdateFontSize(textStyle.GetFontSize());
1518 textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
1519 return textNode;
1520 }
1521
1522 RefPtr<FrameNode> VideoPattern::CreateSVG()
1523 {
1524 auto pipelineContext = GetHost()->GetContext();
1525 CHECK_NULL_RETURN(pipelineContext, nullptr);
1526 auto videoTheme = pipelineContext->GetTheme<VideoTheme>();
1527 CHECK_NULL_RETURN(videoTheme, nullptr);
1528
1529 auto svgNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
1530 CHECK_NULL_RETURN(svgNode, nullptr);
1531
1532 auto imageRenderProperty = svgNode->GetPaintPropertyPtr<ImageRenderProperty>();
1533 imageRenderProperty->UpdateSvgFillColor(videoTheme->GetIconColor());
1534 auto renderContext = svgNode->GetRenderContext();
1535 renderContext->UpdateForegroundColor(videoTheme->GetIconColor());
1536
1537 auto svgLayoutProperty = svgNode->GetLayoutProperty<ImageLayoutProperty>();
1538
1539 auto btnEdge = videoTheme->GetBtnEdge();
1540 PaddingProperty padding;
1541 padding.left = CalcLength(btnEdge.Left());
1542 padding.right = CalcLength(btnEdge.Right());
1543 padding.top = CalcLength(btnEdge.Top());
1544 padding.bottom = CalcLength(btnEdge.Bottom());
1545 svgLayoutProperty->UpdatePadding(padding);
1546
1547 auto btnSize = videoTheme->GetBtnSize();
1548 SizeF size { static_cast<float>(btnSize.Width()), static_cast<float>(btnSize.Height()) };
1549 svgLayoutProperty->UpdateMarginSelfIdealSize(size);
1550 auto width = Dimension(btnSize.Width(), DimensionUnit::VP).ConvertToPx();
1551 auto height = Dimension(btnSize.Height(), DimensionUnit::VP).ConvertToPx();
1552 CalcSize idealSize = { CalcLength(width), CalcLength(height) };
1553 MeasureProperty layoutConstraint;
1554 layoutConstraint.selfIdealSize = idealSize;
1555 layoutConstraint.maxSize = idealSize;
1556 svgNode->UpdateLayoutConstraint(layoutConstraint);
1557 return svgNode;
1558 }
1559
1560 void VideoPattern::SetStartImpl(
1561 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1562 {
1563 videoController->SetStartImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1564 uiTaskExecutor.PostTask([weak]() {
1565 auto pattern = weak.Upgrade();
1566 CHECK_NULL_VOID(pattern);
1567 ContainerScope scope(pattern->instanceId_);
1568 auto targetPattern = pattern->GetTargetVideoPattern();
1569 CHECK_NULL_VOID(targetPattern);
1570 targetPattern->Start();
1571 }, "ArkUIVideoStart");
1572 });
1573 }
1574
1575 void VideoPattern::SetPausetImpl(
1576 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1577 {
1578 videoController->SetPausetImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1579 uiTaskExecutor.PostTask([weak]() {
1580 auto pattern = weak.Upgrade();
1581 CHECK_NULL_VOID(pattern);
1582 ContainerScope scope(pattern->instanceId_);
1583 auto targetPattern = pattern->GetTargetVideoPattern();
1584 CHECK_NULL_VOID(targetPattern);
1585 targetPattern->Pause();
1586 }, "ArkUIVideoPause");
1587 });
1588 }
1589
1590 void VideoPattern::SetStopImpl(
1591 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1592 {
1593 videoController->SetStopImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1594 uiTaskExecutor.PostTask([weak]() {
1595 auto pattern = weak.Upgrade();
1596 CHECK_NULL_VOID(pattern);
1597 ContainerScope scope(pattern->instanceId_);
1598 auto targetPattern = pattern->GetTargetVideoPattern();
1599 CHECK_NULL_VOID(targetPattern);
1600 targetPattern->Stop();
1601 }, "ArkUIVideoStop");
1602 });
1603 }
1604
1605 void VideoPattern::SetSeekToImpl(
1606 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1607 {
1608 videoController->SetSeekToImpl([weak = WeakClaim(this), uiTaskExecutor](float pos, SeekMode seekMode) {
1609 uiTaskExecutor.PostTask([weak, pos, seekMode]() {
1610 auto pattern = weak.Upgrade();
1611 CHECK_NULL_VOID(pattern);
1612 ContainerScope scope(pattern->instanceId_);
1613 auto targetPattern = pattern->GetTargetVideoPattern();
1614 CHECK_NULL_VOID(targetPattern);
1615 targetPattern->SetCurrentTime(pos, seekMode);
1616 }, "ArkUIVideoSetCurrentTime");
1617 });
1618 }
1619
1620 void VideoPattern::SetRequestFullscreenImpl(
1621 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1622 {
1623 videoController->SetRequestFullscreenImpl([weak = WeakClaim(this), uiTaskExecutor](bool isFullScreen) {
1624 uiTaskExecutor.PostTask([weak, isFullScreen]() {
1625 auto videoPattern = weak.Upgrade();
1626 CHECK_NULL_VOID(videoPattern);
1627 ContainerScope scope(videoPattern->instanceId_);
1628 if (isFullScreen) {
1629 videoPattern->FullScreen();
1630 } else {
1631 videoPattern->ResetLastBoundsRect();
1632 auto targetPattern = videoPattern->GetTargetVideoPattern();
1633 CHECK_NULL_VOID(targetPattern);
1634 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(targetPattern);
1635 CHECK_NULL_VOID(fullScreenPattern);
1636 fullScreenPattern->ExitFullScreen();
1637 }
1638 }, "ArkUIVideoFullScreen");
1639 });
1640 }
1641
1642 void VideoPattern::SetExitFullscreenImpl(
1643 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1644 {
1645 videoController->SetExitFullscreenImpl([weak = WeakClaim(this), uiTaskExecutor](bool isSync) {
1646 if (isSync) {
1647 auto pattern = weak.Upgrade();
1648 CHECK_NULL_VOID(pattern);
1649 auto targetPattern = pattern->GetTargetVideoPattern();
1650 CHECK_NULL_VOID(targetPattern);
1651 pattern->ResetLastBoundsRect();
1652 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(targetPattern);
1653 fullScreenPattern->ExitFullScreen();
1654 return;
1655 }
1656 uiTaskExecutor.PostTask([weak]() {
1657 auto pattern = weak.Upgrade();
1658 CHECK_NULL_VOID(pattern);
1659 ContainerScope scope(pattern->instanceId_);
1660 pattern->ResetLastBoundsRect();
1661 auto targetPattern = pattern->GetTargetVideoPattern();
1662 CHECK_NULL_VOID(targetPattern);
1663 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(targetPattern);
1664 CHECK_NULL_VOID(fullScreenPattern);
1665 fullScreenPattern->ExitFullScreen();
1666 }, "ArkUIVideoExitFullScreen");
1667 });
1668 }
1669
1670 void VideoPattern::SetResetImpl(
1671 const RefPtr<VideoController>& videoController, const SingleTaskExecutor& uiTaskExecutor)
1672 {
1673 videoController->SetResetImpl([weak = WeakClaim(this), uiTaskExecutor]() {
1674 uiTaskExecutor.PostTask([weak]() {
1675 auto pattern = weak.Upgrade();
1676 CHECK_NULL_VOID(pattern);
1677 auto targetPattern = pattern->GetTargetVideoPattern();
1678 CHECK_NULL_VOID(targetPattern);
1679 targetPattern->ResetMediaPlayer();
1680 }, "ArkUIVideoReset");
1681 });
1682 }
1683
1684 void VideoPattern::SetMethodCall()
1685 {
1686 ContainerScope scope(instanceId_);
1687 auto videoController = AceType::MakeRefPtr<VideoController>();
1688 auto host = GetHost();
1689 CHECK_NULL_VOID(host);
1690 auto context = host->GetContext();
1691 CHECK_NULL_VOID(context);
1692 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1693
1694 SetStartImpl(videoController, uiTaskExecutor);
1695 SetPausetImpl(videoController, uiTaskExecutor);
1696 SetStopImpl(videoController, uiTaskExecutor);
1697 SetSeekToImpl(videoController, uiTaskExecutor);
1698 SetRequestFullscreenImpl(videoController, uiTaskExecutor);
1699 SetExitFullscreenImpl(videoController, uiTaskExecutor);
1700 SetResetImpl(videoController, uiTaskExecutor);
1701
1702 CHECK_NULL_VOID(videoControllerV2_);
1703 videoControllerV2_->AddVideoController(videoController);
1704 }
1705
1706 void VideoPattern::Start()
1707 {
1708 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1709 return;
1710 }
1711
1712 if (isStop_ && mediaPlayer_->PrepareAsync() != 0) {
1713 TAG_LOGW(AceLogTag::ACE_VIDEO, "Player has not prepared");
1714 return;
1715 }
1716 ContainerScope scope(instanceId_);
1717 auto host = GetHost();
1718 CHECK_NULL_VOID(host);
1719 auto context = host->GetContext();
1720 CHECK_NULL_VOID(context);
1721
1722 DestroyAnalyzerOverlay();
1723 isPaused_ = false;
1724
1725 auto bgTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1726 bgTaskExecutor.PostTask(
1727 [weak = WeakClaim(RawPtr(mediaPlayer_)), hostId = hostId_] {
1728 auto mediaPlayer = weak.Upgrade();
1729 CHECK_NULL_VOID(mediaPlayer);
1730 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] trigger mediaPlayer play", hostId);
1731 mediaPlayer->Play();
1732 },
1733 "ArkUIVideoPlay");
1734 }
1735
1736 void VideoPattern::Pause()
1737 {
1738 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1739 return;
1740 }
1741 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] trigger mediaPlayer pause", hostId_);
1742 auto ret = mediaPlayer_->Pause();
1743 if (ret != -1 && !isPaused_) {
1744 isPaused_ = true;
1745 StartImageAnalyzer();
1746 }
1747 }
1748
1749 void VideoPattern::Stop()
1750 {
1751 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1752 return;
1753 }
1754 TAG_LOGI(AceLogTag::ACE_VIDEO, "Video[%{public}d] trigger mediaPlayer stop", hostId_);
1755 OnCurrentTimeChange(0);
1756 mediaPlayer_->Stop();
1757 isStop_ = true;
1758 SetIsSeeking(false);
1759 }
1760
1761 void VideoPattern::FireError()
1762 {
1763 ContainerScope scope(instanceId_);
1764 auto host = GetHost();
1765 CHECK_NULL_VOID(host);
1766 auto context = host->GetContext();
1767 CHECK_NULL_VOID(context);
1768
1769 // OnError function must be excuted on ui, so get the uiTaskExecutor.
1770 auto task = [weak = WeakClaim(this)] {
1771 auto videoPattern = weak.Upgrade();
1772 CHECK_NULL_VOID(videoPattern);
1773 ContainerScope scope(videoPattern->instanceId_);
1774 videoPattern->OnError("");
1775 };
1776 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1777 if (uiTaskExecutor.IsRunOnCurrentThread()) {
1778 task();
1779 } else {
1780 uiTaskExecutor.PostTask(task, "ArkUIVideoError");
1781 }
1782 }
1783
1784 void VideoPattern::ChangePlayButtonTag()
1785 {
1786 ContainerScope scope(instanceId_);
1787 auto host = GetHost();
1788 CHECK_NULL_VOID(host);
1789 auto context = host->GetContext();
1790 CHECK_NULL_VOID(context);
1791 const auto& children = host->GetChildren();
1792 for (const auto& child : children) {
1793 if (child->GetTag() == V2::ROW_ETS_TAG) {
1794 auto playBtn = DynamicCast<FrameNode>(child->GetChildAtIndex(0));
1795 ChangePlayButtonTag(playBtn);
1796 break;
1797 }
1798 }
1799 }
1800
1801 void VideoPattern::ChangePlayButtonTag(RefPtr<FrameNode>& playBtn)
1802 {
1803 CHECK_NULL_VOID(playBtn);
1804 auto playClickCallback = [weak = WeakClaim(this), playing = isPlaying_](GestureEvent& /* info */) {
1805 auto videoPattern = weak.Upgrade();
1806 CHECK_NULL_VOID(videoPattern);
1807 if (playing) {
1808 videoPattern->Pause();
1809 } else {
1810 videoPattern->Start();
1811 }
1812 };
1813 auto playBtnEvent = playBtn->GetOrCreateGestureEventHub();
1814 playBtnEvent->SetUserOnClick(std::move(playClickCallback));
1815 auto svgLayoutProperty = playBtn->GetLayoutProperty<ImageLayoutProperty>();
1816 auto resourceId = isPlaying_ ? InternalResource::ResourceId::PAUSE_SVG : InternalResource::ResourceId::PLAY_SVG;
1817 auto svgSourceInfo = ImageSourceInfo("");
1818 svgSourceInfo.SetResourceId(resourceId);
1819 svgLayoutProperty->UpdateImageSourceInfo(svgSourceInfo);
1820 playBtn->MarkModifyDone();
1821 playBtn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1822 }
1823
1824 void VideoPattern::SetFullScreenButtonCallBack(RefPtr<FrameNode>& fullScreenBtn)
1825 {
1826 CHECK_NULL_VOID(fullScreenBtn);
1827 auto fsClickCallback = [weak = WeakClaim(this)](GestureEvent& /* info */) {
1828 auto videoPattern = weak.Upgrade();
1829 CHECK_NULL_VOID(videoPattern);
1830 if (InstanceOf<VideoFullScreenPattern>(videoPattern)) {
1831 auto pattern = AceType::DynamicCast<VideoFullScreenPattern>(videoPattern);
1832 CHECK_NULL_VOID(pattern);
1833 videoPattern->ResetLastBoundsRect();
1834 pattern->ExitFullScreen();
1835 } else {
1836 videoPattern->FullScreen();
1837 }
1838 };
1839 auto fullScreenBtnEvent = fullScreenBtn->GetOrCreateGestureEventHub();
1840 fullScreenBtnEvent->SetUserOnClick(std::move(fsClickCallback));
1841 }
1842
1843 void VideoPattern::ChangeFullScreenButtonTag(bool isFullScreen, RefPtr<FrameNode>& fullScreenBtn)
1844 {
1845 CHECK_NULL_VOID(fullScreenBtn);
1846 auto svgLayoutProperty = fullScreenBtn->GetLayoutProperty<ImageLayoutProperty>();
1847 auto resourceId =
1848 isFullScreen ? InternalResource::ResourceId::QUIT_FULLSCREEN_SVG : InternalResource::ResourceId::FULLSCREEN_SVG;
1849 auto svgSourceInfo = ImageSourceInfo("");
1850 svgSourceInfo.SetResourceId(resourceId);
1851 svgLayoutProperty->UpdateImageSourceInfo(svgSourceInfo);
1852 fullScreenBtn->MarkModifyDone();
1853 fullScreenBtn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1854 }
1855
1856 void VideoPattern::SetCurrentTime(float currentPos, OHOS::Ace::SeekMode seekMode)
1857 {
1858 if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid() || !isPrepared_) {
1859 return;
1860 }
1861 if (GreatOrEqual(currentPos, 0.0)) {
1862 SetIsSeeking(true);
1863 mediaPlayer_->Seek(static_cast<int32_t>(currentPos * MILLISECONDS_TO_SECONDS), seekMode);
1864 }
1865 }
1866
1867 void VideoPattern::OnSliderChange(float posTime, int32_t mode)
1868 {
1869 SetCurrentTime(posTime, OHOS::Ace::SeekMode::SEEK_CLOSEST);
1870 auto eventHub = GetEventHub<VideoEventHub>();
1871 CHECK_NULL_VOID(eventHub);
1872 auto json = JsonUtil::Create(true);
1873 json->Put("time", static_cast<double>(posTime));
1874 auto param = json->ToString();
1875 CHECK_NULL_VOID(eventHub);
1876 if (mode == SliderChangeMode::BEGIN || mode == SliderChangeMode::MOVING) {
1877 eventHub->FireSeekingEvent(param);
1878 } else if (mode == SliderChangeMode::END) {
1879 eventHub->FireSeekedEvent(param);
1880 }
1881 }
1882
1883 void VideoPattern::OnFullScreenChange(bool isFullScreen)
1884 {
1885 auto json = JsonUtil::Create(true);
1886 json->Put("fullscreen", isFullScreen);
1887 auto param = json->ToString();
1888 auto eventHub = GetEventHub<VideoEventHub>();
1889 CHECK_NULL_VOID(eventHub);
1890 eventHub->FireFullScreenChangeEvent(param);
1891 auto host = GetHost();
1892 CHECK_NULL_VOID(host);
1893 const auto& children = host->GetChildren();
1894 for (const auto& child : children) {
1895 if (child->GetTag() == V2::ROW_ETS_TAG) {
1896 auto fsBtn = DynamicCast<FrameNode>(child->GetChildAtIndex(FULL_SCREEN_POS));
1897 ChangeFullScreenButtonTag(isFullScreen, fsBtn);
1898 break;
1899 }
1900 }
1901
1902 if (!isFullScreen && mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid()) {
1903 auto videoLayoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
1904 CHECK_NULL_VOID(videoLayoutProperty);
1905 SizeF videoSize = SizeF(
1906 static_cast<float>(mediaPlayer_->GetVideoWidth()),
1907 static_cast<float>(mediaPlayer_->GetVideoHeight()));
1908 videoLayoutProperty->UpdateVideoSize(videoSize);
1909 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1910 }
1911
1912 if (isEnableAnalyzer_) {
1913 if (!imageAnalyzerManager_) {
1914 EnableAnalyzer(isEnableAnalyzer_);
1915 }
1916 if (imageAnalyzerManager_ && isAnalyzerCreated_) {
1917 StartImageAnalyzer();
1918 }
1919 }
1920
1921 if (!SystemProperties::GetExtSurfaceEnabled()) {
1922 return;
1923 }
1924 if (!fullScreenNodeId_.has_value()) {
1925 SetMediaFullScreen(isFullScreen);
1926 return;
1927 }
1928 auto fullScreenNode = FrameNode::GetFrameNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value());
1929 CHECK_NULL_VOID(fullScreenNode);
1930 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(fullScreenNode->GetPattern());
1931 CHECK_NULL_VOID(fullScreenPattern);
1932 fullScreenPattern->SetMediaFullScreen(isFullScreen);
1933 }
1934
1935 void VideoPattern::FullScreen()
1936 {
1937 if (fullScreenNodeId_.has_value()) {
1938 return;
1939 }
1940 ResetLastBoundsRect();
1941 auto host = GetHost();
1942 CHECK_NULL_VOID(host);
1943 auto videoNode = AceType::DynamicCast<VideoNode>(host);
1944 CHECK_NULL_VOID(videoNode);
1945 auto fullScreenPattern = AceType::MakeRefPtr<VideoFullScreenPattern>(videoControllerV2_);
1946 fullScreenPattern->InitFullScreenParam(
1947 AceType::Claim(this), renderSurface_, mediaPlayer_, renderContextForMediaPlayer_);
1948 fullScreenNodeId_ = ElementRegister::GetInstance()->MakeUniqueId();
1949 auto fullScreenNode =
1950 VideoFullScreenNode::CreateFullScreenNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value(), fullScreenPattern);
1951 CHECK_NULL_VOID(fullScreenNode);
1952 fullScreenPattern->RequestFullScreen(videoNode);
1953 }
1954
1955 VideoPattern::~VideoPattern()
1956 {
1957 #ifdef RENDER_EXTRACT_SUPPORTED
1958 if (renderContextForMediaPlayer_) {
1959 renderContextForMediaPlayer_->RemoveSurfaceChangedCallBack();
1960 }
1961 #endif
1962 if (IsSupportImageAnalyzer()) {
1963 DestroyAnalyzerOverlay();
1964 }
1965 if (!fullScreenNodeId_.has_value()) {
1966 return;
1967 }
1968 auto fullScreenNode = FrameNode::GetFrameNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value());
1969 CHECK_NULL_VOID(fullScreenNode);
1970 auto parent = fullScreenNode->GetParent();
1971 CHECK_NULL_VOID(parent);
1972 parent->RemoveChild(fullScreenNode);
1973 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1974 }
1975
1976 void VideoPattern::RecoverState(const RefPtr<VideoPattern>& videoPattern)
1977 {
1978 CHECK_NULL_VOID(videoPattern);
1979 currentPos_ = videoPattern->GetCurrentPos();
1980 if (mediaPlayer_ && mediaPlayer_->IsMediaPlayerValid() && mediaPlayer_->IsPlaying() != isPlaying_) {
1981 isPlaying_ = mediaPlayer_->IsPlaying();
1982 ChangePlayButtonTag();
1983 }
1984 isInitialState_ = videoPattern->GetInitialState();
1985 auto layoutProperty = videoPattern->GetLayoutProperty<VideoLayoutProperty>();
1986 CHECK_NULL_VOID(layoutProperty);
1987 auto videoSrcInfo = layoutProperty->GetVideoSourceValue(VideoSourceInfo());
1988 videoSrcInfo_.src_ = videoSrcInfo.src_;
1989 videoSrcInfo_.bundleName_ = videoSrcInfo.bundleName_;
1990 videoSrcInfo_.moduleName_ = videoSrcInfo.moduleName_;
1991 isPrepared_ = videoPattern->GetIsPrepared();
1992 isSeeking_ = videoPattern->GetIsSeeking();
1993 isStop_ = videoPattern->GetIsStop();
1994 muted_ = videoPattern->GetMuted();
1995 autoPlay_ = videoPattern->GetAutoPlay();
1996 loop_ = videoPattern->GetLoop();
1997 duration_ = videoPattern->GetDuration();
1998 showFirstFrame_ = videoPattern->showFirstFrame_;
1999 progressRate_ = videoPattern->GetProgressRate();
2000 isAnalyzerCreated_ = videoPattern->GetAnalyzerState();
2001 isEnableAnalyzer_ = videoPattern->isEnableAnalyzer_;
2002 SetShortcutKeyEnabled(videoPattern->GetShortcutKeyEnabled());
2003 SetCurrentVolume(videoPattern->GetCurrentVolume());
2004
2005 fullScreenNodeId_.reset();
2006 RegisterMediaPlayerEvent(WeakClaim(this), mediaPlayer_, videoSrcInfo_.src_, instanceId_);
2007 auto videoNode = GetHost();
2008 CHECK_NULL_VOID(videoNode);
2009 // change event hub to the origin video node
2010 videoPattern->GetEventHub<VideoEventHub>()->AttachHost(videoNode);
2011 videoNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
2012 }
2013
2014 void VideoPattern::UpdateFsState()
2015 {
2016 if (!fullScreenNodeId_.has_value()) {
2017 return;
2018 }
2019 auto videoNode = FrameNode::GetFrameNode(V2::VIDEO_ETS_TAG, fullScreenNodeId_.value());
2020 CHECK_NULL_VOID(videoNode);
2021 auto videoPattern = AceType::DynamicCast<VideoFullScreenPattern>(videoNode->GetPattern());
2022 CHECK_NULL_VOID(videoPattern);
2023 // update full screen state
2024 videoPattern->UpdateState();
2025 }
2026
2027 bool VideoPattern::IsFullScreen() const
2028 {
2029 return fullScreenNodeId_.has_value();
2030 }
2031
2032 RefPtr<VideoPattern> VideoPattern::GetTargetVideoPattern()
2033 {
2034 auto isFullScreen = IsFullScreen();
2035 auto patternIsFullScreen = AceType::InstanceOf<VideoFullScreenPattern>(this);
2036 if ((isFullScreen && patternIsFullScreen) || (!isFullScreen && !patternIsFullScreen)) {
2037 return AceType::Claim(this);
2038 }
2039 if (patternIsFullScreen) {
2040 // current is full screen,need to be released
2041 auto fullScreenPattern = AceType::DynamicCast<VideoFullScreenPattern>(this);
2042 CHECK_NULL_RETURN(fullScreenPattern, nullptr);
2043 return fullScreenPattern->GetVideoPattern();
2044 }
2045 // current node is origin video node, need to operate full screen node
2046 auto fullScreenNode = GetFullScreenNode();
2047 CHECK_NULL_RETURN(fullScreenNode, nullptr);
2048 return fullScreenNode->GetPattern<VideoPattern>();
2049 }
2050
2051 void VideoPattern::EnableAnalyzer(bool enable)
2052 {
2053 isEnableAnalyzer_ = enable;
2054 if (!isEnableAnalyzer_) {
2055 DestroyAnalyzerOverlay();
2056 return;
2057 }
2058
2059 CHECK_NULL_VOID(!imageAnalyzerManager_);
2060 auto host = GetHost();
2061 CHECK_NULL_VOID(host);
2062 imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(host, ImageAnalyzerHolder::VIDEO_CUSTOM);
2063 }
2064
2065 void VideoPattern::SetShortcutKeyEnabled(bool isEnableShortcutKey)
2066 {
2067 isEnableShortcutKey_ = isEnableShortcutKey;
2068 }
2069
2070 bool VideoPattern::GetShortcutKeyEnabled() const
2071 {
2072 return isEnableShortcutKey_;
2073 }
2074
2075 void VideoPattern::SetCurrentVolume(float currentVolume)
2076 {
2077 currentVolume_ = currentVolume;
2078 }
2079
2080 float VideoPattern::GetCurrentVolume() const
2081 {
2082 return currentVolume_;
2083 }
2084
2085 void VideoPattern::SetImageAnalyzerConfig(void* config)
2086 {
2087 if (isEnableAnalyzer_) {
2088 CHECK_NULL_VOID(imageAnalyzerManager_);
2089 imageAnalyzerManager_->SetImageAnalyzerConfig(config);
2090 }
2091 }
2092
2093 void VideoPattern::SetImageAIOptions(void* options)
2094 {
2095 if (!imageAnalyzerManager_) {
2096 imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::VIDEO_CUSTOM);
2097 }
2098 CHECK_NULL_VOID(imageAnalyzerManager_);
2099 imageAnalyzerManager_->SetImageAIOptions(options);
2100 }
2101
2102 bool VideoPattern::IsSupportImageAnalyzer()
2103 {
2104 auto host = GetHost();
2105 CHECK_NULL_RETURN(host, false);
2106 auto layoutProperty = host->GetLayoutProperty<VideoLayoutProperty>();
2107 CHECK_NULL_RETURN(layoutProperty, false);
2108 bool needControlBar = layoutProperty->GetControlsValue(true);
2109 CHECK_NULL_RETURN(imageAnalyzerManager_, false);
2110 return isEnableAnalyzer_ && !needControlBar && imageAnalyzerManager_->IsSupportImageAnalyzerFeature();
2111 }
2112
2113 bool VideoPattern::ShouldUpdateImageAnalyzer() {
2114 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
2115 CHECK_NULL_RETURN(layoutProperty, false);
2116 const auto& constraint = layoutProperty->GetCalcLayoutConstraint();
2117 if (!constraint || !constraint->selfIdealSize.has_value() || !constraint->selfIdealSize->IsValid()) {
2118 return false;
2119 }
2120 auto selfIdealSize = constraint->selfIdealSize;
2121 if (!selfIdealSize->PercentWidth() && !selfIdealSize->PercentHeight()) {
2122 return false;
2123 }
2124 auto imageFit = layoutProperty->GetObjectFit().value_or(ImageFit::COVER);
2125 if (imageFit != ImageFit::COVER && imageFit != ImageFit::NONE) {
2126 return false;
2127 }
2128 return true;
2129 }
2130
2131 void VideoPattern::StartImageAnalyzer()
2132 {
2133 if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_) {
2134 return;
2135 }
2136
2137 if (imageAnalyzerManager_->IsOverlayCreated()) {
2138 DestroyAnalyzerOverlay();
2139 }
2140
2141 ContainerScope scope(instanceId_);
2142 auto host = GetHost();
2143 CHECK_NULL_VOID(host);
2144 auto context = host->GetContext();
2145 CHECK_NULL_VOID(context);
2146 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
2147 uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
2148 auto pattern = weak.Upgrade();
2149 CHECK_NULL_VOID(pattern);
2150 pattern->CreateAnalyzerOverlay();
2151 }, ANALYZER_DELAY_TIME, "ArkUIVideoCreateAnalyzerOverlay");
2152 }
2153
2154 void VideoPattern::CreateAnalyzerOverlay()
2155 {
2156 auto host = GetHost();
2157 CHECK_NULL_VOID(host);
2158 host->SetOverlayNode(nullptr);
2159 auto context = host->GetRenderContext();
2160 CHECK_NULL_VOID(context);
2161 auto nailPixelMap = context->GetThumbnailPixelMap();
2162 CHECK_NULL_VOID(nailPixelMap);
2163 auto pixelMap = nailPixelMap->GetCropPixelMap(contentRect_);
2164 CHECK_NULL_VOID(pixelMap);
2165 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
2166 CHECK_NULL_VOID(layoutProperty);
2167 auto padding = layoutProperty->CreatePaddingAndBorder();
2168 OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
2169 contentRect_.Top() - padding.top.value_or(0) };
2170 CHECK_NULL_VOID(imageAnalyzerManager_);
2171 imageAnalyzerManager_->CreateAnalyzerOverlay(pixelMap, contentOffset);
2172 }
2173
2174 void VideoPattern::StartUpdateImageAnalyzer()
2175 {
2176 CHECK_NULL_VOID(imageAnalyzerManager_);
2177 if (!imageAnalyzerManager_->IsOverlayCreated()) {
2178 return;
2179 }
2180
2181 UpdateOverlayVisibility(VisibleType::GONE);
2182 ContainerScope scope(instanceId_);
2183 auto host = GetHost();
2184 CHECK_NULL_VOID(host);
2185 auto context = host->GetContext();
2186 CHECK_NULL_VOID(context);
2187 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
2188 uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
2189 auto pattern = weak.Upgrade();
2190 CHECK_NULL_VOID(pattern);
2191 if (!pattern->isContentSizeChanged_) {
2192 return;
2193 }
2194 pattern->UpdateAnalyzerOverlay();
2195 pattern->isContentSizeChanged_ = false;
2196 }, ANALYZER_CAPTURE_DELAY_TIME, "ArkUIVideoUpdateAnalyzerOverlay");
2197 isContentSizeChanged_ = true;
2198 }
2199
2200 void VideoPattern::UpdateAnalyzerOverlay()
2201 {
2202 auto host = GetHost();
2203 CHECK_NULL_VOID(host);
2204 auto context = host->GetRenderContext();
2205 CHECK_NULL_VOID(context);
2206 auto nailPixelMap = context->GetThumbnailPixelMap();
2207 CHECK_NULL_VOID(nailPixelMap);
2208 auto pixelMap = nailPixelMap->GetCropPixelMap(contentRect_);
2209 CHECK_NULL_VOID(pixelMap);
2210 UpdateOverlayVisibility(VisibleType::VISIBLE);
2211
2212 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
2213 CHECK_NULL_VOID(layoutProperty);
2214 auto padding = layoutProperty->CreatePaddingAndBorder();
2215 OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
2216 contentRect_.Top() - padding.top.value_or(0) };
2217 CHECK_NULL_VOID(imageAnalyzerManager_);
2218 imageAnalyzerManager_->UpdateAnalyzerOverlay(pixelMap, contentOffset);
2219 }
2220
2221 void VideoPattern::UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)
2222 {
2223 if (IsSupportImageAnalyzer()) {
2224 auto layoutProperty = GetLayoutProperty<VideoLayoutProperty>();
2225 CHECK_NULL_VOID(layoutProperty);
2226 auto padding = layoutProperty->CreatePaddingAndBorder();
2227 OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
2228 contentRect_.Top() - padding.top.value_or(0) };
2229 PixelMapInfo info = { contentRect_.GetSize().Width(), contentRect_.GetSize().Height(), contentOffset };
2230 CHECK_NULL_VOID(imageAnalyzerManager_);
2231 imageAnalyzerManager_->UpdateAnalyzerUIConfig(geometryNode, info);
2232 }
2233 }
2234
2235 void VideoPattern::DestroyAnalyzerOverlay()
2236 {
2237 CHECK_NULL_VOID(imageAnalyzerManager_);
2238 imageAnalyzerManager_->DestroyAnalyzerOverlay();
2239 }
2240
2241 bool VideoPattern::GetAnalyzerState()
2242 {
2243 CHECK_NULL_RETURN(imageAnalyzerManager_, false);
2244 return imageAnalyzerManager_->IsOverlayCreated();
2245 }
2246
2247 void VideoPattern::UpdateOverlayVisibility(VisibleType type)
2248 {
2249 auto host = GetHost();
2250 CHECK_NULL_VOID(host);
2251 auto overlayNode = host->GetOverlayNode();
2252 CHECK_NULL_VOID(overlayNode);
2253 auto prop = overlayNode->GetLayoutProperty();
2254 CHECK_NULL_VOID(prop);
2255 prop->UpdateVisibility(type);
2256 }
2257
2258 void VideoPattern::OnWindowHide()
2259 {
2260 #if defined(OHOS_PLATFORM)
2261 if (!BackgroundTaskHelper::GetInstance().HasBackgroundTask()) {
2262 autoPlay_ = false;
2263 Pause();
2264 }
2265 #else
2266 Pause();
2267 #endif
2268 }
2269
2270 void VideoPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
2271 {
2272 Pattern::ToJsonValue(json, filter);
2273 if (filter.IsFastFilter()) {
2274 return;
2275 }
2276
2277 json->PutExtAttr("enableAnalyzer", isEnableAnalyzer_ ? "true" : "false", filter);
2278 json->PutExtAttr("currentProgressRate", progressRate_, filter);
2279 json->PutExtAttr("surfaceBackgroundColor",
2280 renderContextForMediaPlayer_
2281 ? renderContextForMediaPlayer_->GetBackgroundColorValue(Color::BLACK).ColorToString().c_str()
2282 : "",
2283 filter);
2284 json->PutExtAttr("enableShortcutKey", isEnableShortcutKey_ ? "true" : "false", filter);
2285 }
2286 } // namespace OHOS::Ace::NG
2287