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