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