1 /*
2 * Copyright (c) 2021-2023 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/video/video_element.h"
17
18 #include <algorithm>
19 #include <iomanip>
20 #include <regex>
21 #include <sstream>
22 #include <string>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 #include "base/i18n/localization.h"
27 #include "base/image/file_uri_helper.h"
28 #include "base/json/json_util.h"
29 #include "base/log/dump_log.h"
30 #include "base/log/log.h"
31 #include "base/resource/asset_manager.h"
32 #include "base/resource/internal_resource.h"
33 #include "base/utils/system_properties.h"
34 #include "base/utils/utils.h"
35 #include "core/common/container_scope.h"
36 #include "core/components/align/align_component.h"
37 #include "core/components/box/box_component.h"
38 #include "core/components/button/button_component.h"
39 #include "core/components/flex/flex_component.h"
40 #include "core/components/flex/flex_item_component.h"
41 #include "core/components/gesture_listener/gesture_listener_component.h"
42 #include "core/components/image/image_component.h"
43 #include "core/components/padding/padding_component.h"
44 #include "core/components/slider/slider_component.h"
45 #include "core/components/stage/stage_element.h"
46 #include "core/components/text/text_component.h"
47 #include "core/components/theme/resource_adapter.h"
48 #include "core/components/theme/theme_manager.h"
49 #include "core/components/video/render_texture.h"
50 #include "core/event/ace_event_helper.h"
51 #include "core/event/back_end_event_manager.h"
52 #include "core/pipeline/base/composed_component.h"
53 #include "core/pipeline/pipeline_context.h"
54
55 #ifdef OHOS_STANDARD_SYSTEM
56 #include <securec.h>
57
58 #include "display_type.h"
59 #include "surface.h"
60
61 #ifdef ENABLE_ROSEN_BACKEND
62 #include "core/components/video/rosen_render_texture.h"
63 #endif
64
65 #endif
66
67 namespace OHOS::Ace {
68 namespace {
69
70 const char* PLAY_LABEL = "play";
71 const char* PAUSE_LABEL = "pause";
72 const char* FULLSCREEN_LABEL = "fullscreen";
73 const char* EXIT_FULLSCREEN_LABEL = "exitFullscreen";
74
75 #ifdef OHOS_STANDARD_SYSTEM
76 const char* SURFACE_STRIDE_ALIGNMENT = "8";
77 constexpr int32_t SURFACE_QUEUE_SIZE = 5;
78 constexpr uint32_t MEDIA_RESOURCE_MATCH_SIZE = 2;
79 const int32_t RAWFILE_PREFIX_LENGTH = strlen("resource://RAWFILE/");
80 const std::regex MEDIA_RES_ID_REGEX(R"(^resource://\w+/([0-9]+)\.\w+$)", std::regex::icase);
81 const std::regex MEDIA_APP_RES_ID_REGEX(R"(^resource://.*/([0-9]+)\.\w+$)", std::regex::icase);
82 #endif
83 constexpr float ILLEGAL_SPEED = 0.0f;
84 constexpr int32_t COMPATIBLE_VERSION = 5;
85
86 #ifdef OHOS_STANDARD_SYSTEM
87 constexpr float SPEED_0_75_X = 0.75;
88 constexpr float SPEED_1_00_X = 1.00;
89 constexpr float SPEED_1_25_X = 1.25;
90 constexpr float SPEED_1_75_X = 1.75;
91 constexpr float SPEED_2_00_X = 2.00;
92
ConvertToMediaSeekMode(SeekMode seekMode)93 OHOS::Media::PlayerSeekMode ConvertToMediaSeekMode(SeekMode seekMode)
94 {
95 OHOS::Media::PlayerSeekMode mode = OHOS::Media::SEEK_PREVIOUS_SYNC;
96 if (seekMode == SeekMode::SEEK_NEXT_SYNC) {
97 mode = OHOS::Media::SEEK_NEXT_SYNC;
98 } else if (seekMode == SeekMode::SEEK_CLOSEST_SYNC) {
99 mode = OHOS::Media::SEEK_CLOSEST_SYNC;
100 } else if (seekMode == SeekMode::SEEK_CLOSEST) {
101 mode = OHOS::Media::SEEK_CLOSEST;
102 }
103 return mode;
104 }
105
ConvertToMediaPlaybackSpeed(float speed)106 OHOS::Media::PlaybackRateMode ConvertToMediaPlaybackSpeed(float speed)
107 {
108 OHOS::Media::PlaybackRateMode mode = OHOS::Media::SPEED_FORWARD_1_00_X;
109 if (NearEqual(speed, SPEED_0_75_X)) {
110 mode = OHOS::Media::PlaybackRateMode::SPEED_FORWARD_0_75_X;
111 } else if (NearEqual(speed, SPEED_1_00_X)) {
112 mode = OHOS::Media::PlaybackRateMode::SPEED_FORWARD_1_00_X;
113 } else if (NearEqual(speed, SPEED_1_25_X)) {
114 mode = OHOS::Media::PlaybackRateMode::SPEED_FORWARD_1_25_X;
115 } else if (NearEqual(speed, SPEED_1_75_X)) {
116 mode = OHOS::Media::PlaybackRateMode::SPEED_FORWARD_1_75_X;
117 } else if (NearEqual(speed, SPEED_2_00_X)) {
118 mode = OHOS::Media::PlaybackRateMode::SPEED_FORWARD_2_00_X;
119 } else {
120 LOGW("speed is not supported yet.");
121 }
122 return mode;
123 }
124 #endif
125
126 } // namespace
127
~VideoElement()128 VideoElement::~VideoElement()
129 {
130 if (!startBtnClickId_.IsEmpty()) {
131 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(startBtnClickId_);
132 }
133
134 if (!sliderMovedCallbackId_.IsEmpty()) {
135 BackEndEventManager<void(const std::string&)>::GetInstance().RemoveBackEndEvent(sliderMovedCallbackId_);
136 }
137
138 if (!sliderMovingCallbackId_.IsEmpty()) {
139 BackEndEventManager<void(const std::string&)>::GetInstance().RemoveBackEndEvent(sliderMovingCallbackId_);
140 }
141
142 if (!fullscreenBtnClickId_.IsEmpty()) {
143 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(fullscreenBtnClickId_);
144 }
145
146 if (!shieldId_.IsEmpty()) {
147 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(startBtnClickId_);
148 }
149
150 if (isMediaPlayerFullStatus_) {
151 ExitFullScreen();
152 }
153
154 if (!isExternalResource_) {
155 if (isFullScreen_) {
156 ExitFullScreen();
157 }
158 UnSubscribeMultiModal();
159 } else {
160 if (player_) {
161 player_->PopListener();
162 }
163 }
164 ReleasePlatformResource();
165 #ifdef OHOS_STANDARD_SYSTEM
166 if (mediaPlayer_ != nullptr) {
167 mediaPlayer_->Release();
168 }
169 if (SystemProperties::GetExtSurfaceEnabled() && surfaceDelegate_) {
170 surfaceDelegate_->ReleaseSurface();
171 }
172 #endif
173 }
174
PerformBuild()175 void VideoElement::PerformBuild()
176 {
177 RefPtr<VideoComponent> videoComponent = AceType::DynamicCast<VideoComponent>(component_);
178
179 if (videoComponent == nullptr) {
180 return;
181 }
182 const auto& child = children_.empty() ? nullptr : children_.front();
183 UpdateChild(child, videoComponent->GetChild());
184 }
185
InitStatus(const RefPtr<VideoComponent> & videoComponent)186 void VideoElement::InitStatus(const RefPtr<VideoComponent>& videoComponent)
187 {
188 imageFit_ = videoComponent->GetFit();
189 imagePosition_ = videoComponent->GetImagePosition();
190 needControls_ = videoComponent->NeedControls();
191 isAutoPlay_ = videoComponent->IsAutoPlay();
192 isMute_ = videoComponent->IsMute();
193 src_ = videoComponent->GetSrc();
194 poster_ = videoComponent->GetPoster();
195 posterImage_ = videoComponent->GetPosterImage();
196 isFullScreen_ = videoComponent->IsFullscreen();
197 direction_ = videoComponent->GetDirection();
198 startTime_ = videoComponent->GetStartTime();
199 isMediaPlayerFullStatus_ = videoComponent->GetMediaPlayerFullStatus();
200 if (isMediaPlayerFullStatus_) {
201 pastPlayingStatus_ = videoComponent->GetPastPlayingStatus();
202 if (startTime_ != 0) {
203 currentPos_ = static_cast<uint32_t>(startTime_);
204 IntTimeToText(currentPos_, currentPosText_);
205 }
206 }
207 if (isLoop_ != videoComponent->IsLoop()) {
208 isLoop_ = videoComponent->IsLoop();
209 EnableLooping(isLoop_);
210 }
211
212 if (speed_ != videoComponent->GetSpeed()) {
213 speed_ = videoComponent->GetSpeed();
214 SetSpeed(speed_);
215 }
216
217 #ifdef OHOS_STANDARD_SYSTEM
218 PreparePlayer();
219 if (isMediaPlayerFullStatus_) {
220 isExternalResource_ = true;
221 }
222 #endif
223
224 if (!videoComponent->GetPlayer().Invalid() && !videoComponent->GetTexture().Invalid()) {
225 player_ = videoComponent->GetPlayer().Upgrade();
226 texture_ = videoComponent->GetTexture().Upgrade();
227 if (player_ && texture_) {
228 isExternalResource_ = true;
229 videoComponent->SetPlayer(nullptr);
230 videoComponent->SetTexture(nullptr);
231 InitListener();
232 }
233 }
234 }
235
236 #ifdef OHOS_STANDARD_SYSTEM
RegisterMediaPlayerEvent()237 void VideoElement::RegisterMediaPlayerEvent()
238 {
239 auto context = context_.Upgrade();
240 if (context == nullptr) {
241 LOGE("context is nullptr");
242 return;
243 }
244
245 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
246 auto videoElement = WeakClaim(this);
247
248 auto&& positionUpdatedEvent = [videoElement, uiTaskExecutor](uint32_t currentPos) {
249 uiTaskExecutor.PostSyncTask([&videoElement, currentPos] {
250 auto video = videoElement.Upgrade();
251 if (video != nullptr) {
252 video->OnCurrentTimeChange(currentPos);
253 }
254 }, "ArkUIVideoCurrentTimeChange");
255 };
256
257 auto&& stateChangedEvent = [videoElement, uiTaskExecutor](PlaybackStatus status) {
258 uiTaskExecutor.PostSyncTask([&videoElement, status] {
259 auto video = videoElement.Upgrade();
260 if (video) {
261 video->OnPlayerStatus(status);
262 }
263 }, "ArkUIVideoStatusChange");
264 };
265
266 auto&& errorEvent = [videoElement, uiTaskExecutor]() {
267 uiTaskExecutor.PostTask([&videoElement] {
268 auto video = videoElement.Upgrade();
269 if (video) {
270 video->OnError("", "");
271 }
272 }, "ArkUIVideoError");
273 };
274
275 auto&& resolutionChangeEvent = [videoElement, uiTaskExecutor]() {
276 uiTaskExecutor.PostSyncTask([&videoElement] {
277 auto video = videoElement.Upgrade();
278 if (video) {
279 video->OnResolutionChange();
280 }
281 }, "ArkUIVideoResolutionChange");
282 };
283
284 mediaPlayerCallback_ = std::make_shared<MediaPlayerCallback>(ContainerScope::CurrentId());
285 mediaPlayerCallback_->SetPositionUpdatedEvent(positionUpdatedEvent);
286 mediaPlayerCallback_->SetStateChangedEvent(stateChangedEvent);
287 mediaPlayerCallback_->SetErrorEvent(errorEvent);
288 mediaPlayerCallback_->SetResolutionChangeEvent(resolutionChangeEvent);
289 mediaPlayer_->SetPlayerCallback(mediaPlayerCallback_);
290 }
291
CreateMediaPlayer()292 void VideoElement::CreateMediaPlayer()
293 {
294 if (mediaPlayer_ != nullptr) {
295 return;
296 }
297
298 mediaPlayer_ = OHOS::Media::PlayerFactory::CreatePlayer();
299 if (mediaPlayer_ == nullptr) {
300 LOGE("Create player failed");
301 return;
302 }
303
304 PreparePlayer();
305 }
306
PreparePlayer()307 void VideoElement::PreparePlayer()
308 {
309 SetVolume(isMute_ ? 0.0f : 1.0f);
310 CHECK_NULL_VOID(hasSrcChanged_);
311 CHECK_NULL_VOID(mediaPlayer_);
312 (void)mediaPlayer_->Reset();
313 std::string filePath = src_;
314
315 int32_t fd = -1;
316 SetMediaSource(filePath, fd);
317
318 if (fd >= 0) {
319 // get size of file.
320 struct stat statBuf;
321 auto statRes = fstat(fd, &statBuf);
322 if (statRes != 0) {
323 LOGE("get stat fail");
324 close(fd);
325 return;
326 }
327 auto size = statBuf.st_size;
328 if (mediaPlayer_->SetSource(fd, 0, size) != 0) {
329 LOGE("Player SetSource failed");
330 close(fd);
331 return;
332 }
333 close(fd);
334 }
335
336 RegisterMediaPlayerEvent();
337
338 sptr<Surface> producerSurface;
339 if (SystemProperties::GetExtSurfaceEnabled()) {
340 auto context = context_.Upgrade();
341 uint32_t windowId = 0;
342 if (context && !surfaceDelegate_) {
343 windowId = context->GetWindowId();
344 surfaceDelegate_ = new OHOS::SurfaceDelegate(windowId);
345 surfaceDelegate_->CreateSurface();
346 producerSurface = surfaceDelegate_->GetSurface();
347 }
348 } else {
349 #ifdef ENABLE_ROSEN_BACKEND
350 if (renderNode_) {
351 auto rosenTexture = AceType::DynamicCast<RosenRenderTexture>(renderNode_);
352 if (rosenTexture) {
353 producerSurface = rosenTexture->GetSurface();
354 }
355 }
356 #endif
357 }
358
359 if (producerSurface == nullptr) {
360 LOGE("producerSurface is nullptr");
361 return;
362 }
363 producerSurface->SetQueueSize(SURFACE_QUEUE_SIZE);
364 producerSurface->SetUserData("SURFACE_STRIDE_ALIGNMENT", SURFACE_STRIDE_ALIGNMENT);
365 producerSurface->SetUserData("SURFACE_FORMAT", std::to_string(PIXEL_FMT_RGBA_8888));
366 if (mediaPlayer_->SetVideoSurface(producerSurface) != 0) {
367 LOGE("Player SetVideoSurface failed");
368 return;
369 }
370 if (!SystemProperties::GetExtSurfaceEnabled() && mediaPlayer_->PrepareAsync() != 0) {
371 LOGE("Player prepare failed");
372 return;
373 }
374 hasSrcChanged_ = false;
375 }
376
377 // Interim programme
MediaPlay(const std::string & filePath)378 void VideoElement::MediaPlay(const std::string& filePath)
379 {
380 auto assetManager = PipelineBase::GetCurrentContext()->GetAssetManager();
381 uint32_t resId = 0;
382 if (GetResourceId(filePath, resId)) {
383 auto themeManager = PipelineBase::GetCurrentContext()->GetThemeManager();
384 auto themeConstants = themeManager->GetThemeConstants();
385 std::string mediaPath;
386 auto state1 = themeConstants->GetMediaById(resId, mediaPath);
387 if (!state1) {
388 LOGE("GetMediaById failed");
389 return;
390 }
391 MediaFileInfo fileInfo;
392 auto state2 = assetManager->GetFileInfo(mediaPath.substr(mediaPath.find("resources/base")), fileInfo);
393 if (!state2) {
394 LOGE("GetMediaFileInfo failed");
395 return;
396 }
397 auto hapPath = Container::Current()->GetHapPath();
398 auto hapFd = open(hapPath.c_str(), O_RDONLY);
399 if (hapFd < 0) {
400 LOGE("Open hap file failed");
401 return;
402 }
403 if (mediaPlayer_->SetSource(hapFd, fileInfo.offset, fileInfo.length) != 0) {
404 LOGE("Player SetSource failed");
405 close(hapFd);
406 return;
407 }
408 close(hapFd);
409 }
410 }
411
RawFilePlay(const std::string & filePath)412 void VideoElement::RawFilePlay(const std::string& filePath)
413 {
414 auto assetManager = PipelineBase::GetCurrentContext()->GetAssetManager();
415 auto path = "resources/rawfile/" + filePath.substr(RAWFILE_PREFIX_LENGTH);
416 MediaFileInfo fileInfo;
417 auto state1 = assetManager->GetFileInfo(path, fileInfo);
418 if (!state1) {
419 LOGE("GetMediaFileInfo failed");
420 return;
421 }
422 auto hapPath = Container::Current()->GetHapPath();
423 auto hapFd = open(hapPath.c_str(), O_RDONLY);
424 if (hapFd < 0) {
425 LOGE("Open hap file failed");
426 return;
427 }
428 if (mediaPlayer_->SetSource(hapFd, fileInfo.offset, fileInfo.length) != 0) {
429 LOGE("Player SetSource failed");
430 close(hapFd);
431 return;
432 }
433 close(hapFd);
434 }
435
RelativePathPlay(const std::string & filePath)436 void VideoElement::RelativePathPlay(const std::string& filePath)
437 {
438 // relative path
439 auto assetManager = PipelineBase::GetCurrentContext()->GetAssetManager();
440 MediaFileInfo fileInfo;
441 auto state = assetManager->GetFileInfo(assetManager->GetAssetPath(filePath, false), fileInfo);
442 if (!state) {
443 LOGE("GetMediaFileInfo failed");
444 return;
445 }
446 auto hapPath = Container::Current()->GetHapPath();
447 auto hapFd = open(hapPath.c_str(), O_RDONLY);
448 if (hapFd < 0) {
449 LOGE("Open hap file failed");
450 return;
451 }
452 if (mediaPlayer_->SetSource(hapFd, fileInfo.offset, fileInfo.length) != 0) {
453 LOGE("Player SetSource failed");
454 close(hapFd);
455 return;
456 }
457 close(hapFd);
458 }
459
GetResourceId(const std::string & path,uint32_t & resId)460 bool VideoElement::GetResourceId(const std::string& path, uint32_t& resId)
461 {
462 std::smatch matches;
463 if (std::regex_match(path, matches, MEDIA_RES_ID_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
464 resId = static_cast<uint32_t>(std::stoul(matches[1].str()));
465 return true;
466 }
467
468 std::smatch appMatches;
469 if (std::regex_match(path, appMatches, MEDIA_APP_RES_ID_REGEX) && appMatches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
470 resId = static_cast<uint32_t>(std::stoul(appMatches[1].str()));
471 return true;
472 }
473
474 return false;
475 }
476
SetMediaSource(std::string & filePath,int32_t & fd)477 void VideoElement::SetMediaSource(std::string& filePath, int32_t& fd)
478 {
479 if (StringUtils::StartWith(filePath, "dataability://") || StringUtils::StartWith(filePath, "datashare://") ||
480 StringUtils::StartWith(filePath, "file://media")) {
481 // dataability:// or datashare://
482 auto context = context_.Upgrade();
483 CHECK_NULL_VOID(context);
484 auto dataProvider = AceType::DynamicCast<DataProviderManagerStandard>(context->GetDataProviderManager());
485 CHECK_NULL_VOID(dataProvider);
486 fd = dataProvider->GetDataProviderFile(filePath, "r");
487 } else if (StringUtils::StartWith(filePath, "file://")) {
488 filePath = FileUriHelper::GetRealPath(filePath);
489 fd = open(filePath.c_str(), O_RDONLY);
490 } else if (StringUtils::StartWith(filePath, "resource:///")) {
491 // file path: resources/base/media/xxx.xx --> resource:///xxx.xx
492 MediaPlay(filePath);
493 } else if (StringUtils::StartWith(filePath, "resource://RAWFILE")) {
494 // file path: resource/rawfile/xxx.xx --> resource://rawfile/xxx.xx
495 RawFilePlay(filePath);
496 } else if (StringUtils::StartWith(filePath, "http")) {
497 // http or https
498 if (mediaPlayer_->SetSource(filePath) != 0) {
499 LOGE("Player SetSource failed");
500 return;
501 }
502 } else {
503 // relative path
504 if (StringUtils::StartWith(filePath, "/")) {
505 filePath = filePath.substr(1);
506 }
507 RelativePathPlay(filePath);
508 }
509 }
510
GetAssetAbsolutePath(const std::string & fileName)511 std::string VideoElement::GetAssetAbsolutePath(const std::string& fileName)
512 {
513 const auto pipelineContext = GetContext().Upgrade();
514 if (!pipelineContext) {
515 LOGW("the pipeline context is null");
516 return fileName;
517 }
518 auto assetManager = pipelineContext->GetAssetManager();
519 if (!assetManager) {
520 LOGW("the assetManager is null");
521 return fileName;
522 }
523 std::string filePath = assetManager->GetAssetPath(fileName, true);
524 std::string absolutePath = filePath + fileName;
525 return absolutePath;
526 }
527
OnTextureOffset(int64_t textureId,int32_t x,int32_t y)528 void VideoElement::OnTextureOffset(int64_t textureId, int32_t x, int32_t y)
529 {
530 if (SystemProperties::GetExtSurfaceEnabled() && surfaceDelegate_) {
531 const auto pipelineContext = GetContext().Upgrade();
532 if (!pipelineContext) {
533 LOGW("pipelineContext is null!");
534 return;
535 }
536 float viewScale = pipelineContext->GetViewScale();
537 textureOffsetX_ = x * viewScale;
538 textureOffsetY_ = y * viewScale;
539 surfaceDelegate_->SetBounds(textureOffsetX_, textureOffsetY_, textureWidth_, textureHeight_);
540 LOGI("OnTextureSize x = %{public}d y = %{public}d textureWidth_ = %{public}d textureHeight_ = %{public}d",
541 textureOffsetX_, textureOffsetY_, textureWidth_, textureHeight_);
542 }
543 }
544 #endif
545
ResetStatus()546 void VideoElement::ResetStatus()
547 {
548 needControls_ = true;
549 isAutoPlay_ = false;
550 isMute_ = false;
551 duration_ = 0;
552 currentPos_ = 0;
553 isPlaying_ = false;
554 isReady_ = false;
555 isInitialState_ = true;
556 isError_ = false;
557 videoWidth_ = 0.0;
558 videoHeight_ = 0.0;
559 isLoop_ = false;
560 startTime_ = 0;
561 durationText_ = Localization::GetInstance()->FormatDuration(0);
562 currentPosText_ = Localization::GetInstance()->FormatDuration(0);
563 }
564
Prepare(const WeakPtr<Element> & parent)565 void VideoElement::Prepare(const WeakPtr<Element>& parent)
566 {
567 auto themeManager = GetThemeManager();
568 if (!themeManager) {
569 return;
570 }
571 auto videoComponent = AceType::DynamicCast<VideoComponent>(component_);
572 theme_ = themeManager->GetTheme<VideoTheme>();
573 sliderTheme_ = themeManager->GetTheme<SliderTheme>();
574 if (videoComponent) {
575 textDirection_ = videoComponent->GetTextDirection();
576
577 ResetStatus();
578 InitStatus(videoComponent);
579 InitEvent(videoComponent);
580 SetRespondChildEvent();
581 if (!isExternalResource_) {
582 SetMethodCall(videoComponent);
583 CreatePlatformResource();
584 PrepareMultiModalEvent();
585 SubscribeMultiModal();
586 }
587 videoComponent->SetChild(CreateChild());
588 fullscreenEvent_ = videoComponent->GetFullscreenEvent();
589 if (!mediaFullscreenEvent_) {
590 mediaFullscreenEvent_ = videoComponent->GetMediaFullscreenEvent();
591 }
592 if (!mediaExitFullscreenEvent_ && isMediaPlayerFullStatus_) {
593 mediaExitFullscreenEvent_ = videoComponent->GetMediaExitFullscreenEvent();
594 }
595 }
596
597 RenderElement::Prepare(parent);
598 if (renderNode_) {
599 auto renderTexture = AceType::DynamicCast<RenderTexture>(renderNode_);
600 if (renderTexture) {
601 renderTexture->SetHiddenChangeEvent([weak = WeakClaim(this)](bool hidden) {
602 auto videoElement = weak.Upgrade();
603 if (videoElement) {
604 videoElement->HiddenChange(hidden);
605 }
606 });
607 renderTexture->SetTextureSizeChange(
608 [weak = WeakClaim(this)](int64_t textureId, int32_t textureWidth, int32_t textureHeight) {
609 auto videoElement = weak.Upgrade();
610 if (videoElement) {
611 videoElement->OnTextureSize(textureId, textureWidth, textureHeight);
612 }
613 });
614 }
615 #ifdef OHOS_STANDARD_SYSTEM
616 if (renderTexture && SystemProperties::GetExtSurfaceEnabled()) {
617 renderTexture->SetTextureOffsetChange([weak = WeakClaim(this)](int64_t textureId, int32_t x, int32_t y) {
618 auto videoElement = weak.Upgrade();
619 if (videoElement) {
620 videoElement->OnTextureOffset(textureId, x, y);
621 }
622 });
623 }
624 CreateMediaPlayer();
625 #endif
626 }
627 isElementPrepared_ = true;
628 }
629
OnTextureSize(int64_t textureId,int32_t textureWidth,int32_t textureHeight)630 void VideoElement::OnTextureSize(int64_t textureId, int32_t textureWidth, int32_t textureHeight)
631 {
632 #ifndef OHOS_STANDARD_SYSTEM
633 if (texture_) {
634 texture_->OnSize(textureId, textureWidth, textureHeight);
635 }
636 #else
637 if (SystemProperties::GetExtSurfaceEnabled() && surfaceDelegate_) {
638 const auto pipelineContext = GetContext().Upgrade();
639 if (!pipelineContext) {
640 LOGW("pipelineContext is null!");
641 return;
642 }
643 float viewScale = pipelineContext->GetViewScale();
644 textureWidth_ = textureWidth * viewScale + 1;
645 textureHeight_ = textureHeight * viewScale + 1;
646 surfaceDelegate_->SetBounds(textureOffsetX_, textureOffsetY_, textureWidth_, textureHeight_);
647 LOGI("OnTextureSize x = %{public}d y = %{public}d textureWidth_ = %{public}d textureHeight_ = %{public}d",
648 textureOffsetX_, textureOffsetY_, textureWidth_, textureHeight_);
649 if (hasMediaPrepared_) {
650 return;
651 }
652 if (mediaPlayer_->PrepareAsync() != 0) {
653 LOGE("Player prepare failed");
654 } else {
655 hasMediaPrepared_ = true;
656 }
657 }
658 #endif
659 }
660
HasPlayer() const661 bool VideoElement::HasPlayer() const
662 {
663 #ifdef OHOS_STANDARD_SYSTEM
664 return mediaPlayer_ != nullptr;
665 #else
666 return player_ != nullptr;
667 #endif
668 }
669
HiddenChange(bool hidden)670 void VideoElement::HiddenChange(bool hidden)
671 {
672 if (isPlaying_ && hidden && HasPlayer()) {
673 pastPlayingStatus_ = isPlaying_;
674 Pause();
675 return;
676 }
677
678 if (!hidden && pastPlayingStatus_) {
679 isPlaying_ = !pastPlayingStatus_;
680 pastPlayingStatus_ = false;
681 Start();
682 }
683 }
684
PrepareMultiModalEvent()685 void VideoElement::PrepareMultiModalEvent()
686 {
687 if (!multimodalEventFullscreen_) {
688 multimodalEventFullscreen_ = [weak = WeakClaim(this)](const AceMultimodalEvent&) {
689 auto videoElement = weak.Upgrade();
690 if (videoElement) {
691 videoElement->FullScreen();
692 }
693 };
694 }
695
696 if (!multimodalEventPause_) {
697 multimodalEventPause_ = [weak = WeakClaim(this)](const AceMultimodalEvent&) {
698 auto videoElement = weak.Upgrade();
699 if (videoElement) {
700 videoElement->Pause();
701 }
702 };
703 }
704
705 if (!multimodalEventPlay_) {
706 multimodalEventPlay_ = [weak = WeakClaim(this)](const AceMultimodalEvent&) {
707 auto videoElement = weak.Upgrade();
708 if (videoElement) {
709 videoElement->Start();
710 }
711 };
712 }
713
714 if (!multimodalEventFullscreenExit_) {
715 multimodalEventFullscreenExit_ = [weak = WeakClaim(this)](const AceMultimodalEvent&) {
716 auto videoElement = weak.Upgrade();
717 if (videoElement) {
718 videoElement->ExitFullScreen();
719 }
720 };
721 };
722 }
723
SubscribeMultiModal()724 bool VideoElement::SubscribeMultiModal()
725 {
726 if (isSubscribeMultimodal_) {
727 return true;
728 }
729 if (multiModalScene_.Invalid()) {
730 const auto pipelineContext = GetContext().Upgrade();
731 if (!pipelineContext) {
732 LOGW("the pipeline context is null");
733 return false;
734 }
735 const auto multimodalManager = pipelineContext->GetMultiModalManager();
736 if (!multimodalManager) {
737 LOGW("the multimodal manager is null");
738 return false;
739 }
740 const auto scene = multimodalManager->GetCurrentMultiModalScene();
741 if (!scene) {
742 return false;
743 }
744
745 playVoiceEvent_ = VoiceEvent(PLAY_LABEL, SceneLabel::VIDEO);
746 scene->SubscribeVoiceEvent(playVoiceEvent_, multimodalEventPlay_);
747
748 pauseVoiceEvent_ = VoiceEvent(PAUSE_LABEL, SceneLabel::VIDEO);
749 scene->SubscribeVoiceEvent(pauseVoiceEvent_, multimodalEventPause_);
750
751 fullscreenVoiceEvent_ = VoiceEvent(FULLSCREEN_LABEL, SceneLabel::VIDEO);
752 scene->SubscribeVoiceEvent(fullscreenVoiceEvent_, multimodalEventFullscreen_);
753
754 exitFullscreenVoiceEvent_ = VoiceEvent(EXIT_FULLSCREEN_LABEL, SceneLabel::VIDEO);
755 scene->SubscribeVoiceEvent(exitFullscreenVoiceEvent_, multimodalEventFullscreenExit_);
756 multiModalScene_ = scene;
757 isSubscribeMultimodal_ = true;
758 }
759 return true;
760 }
761
UnSubscribeMultiModal()762 bool VideoElement::UnSubscribeMultiModal()
763 {
764 if (!isSubscribeMultimodal_) {
765 return true;
766 }
767 auto multiModalScene = multiModalScene_.Upgrade();
768 if (!multiModalScene) {
769 LOGE("fail to destroy multimodal event due to multiModalScene is null");
770 return false;
771 }
772 if (!playVoiceEvent_.GetVoiceContent().empty()) {
773 multiModalScene->UnSubscribeVoiceEvent(playVoiceEvent_);
774 }
775 if (!pauseVoiceEvent_.GetVoiceContent().empty()) {
776 multiModalScene->UnSubscribeVoiceEvent(pauseVoiceEvent_);
777 }
778 if (!exitFullscreenVoiceEvent_.GetVoiceContent().empty()) {
779 multiModalScene->UnSubscribeVoiceEvent(exitFullscreenVoiceEvent_);
780 }
781 if (!fullscreenVoiceEvent_.GetVoiceContent().empty()) {
782 multiModalScene->UnSubscribeVoiceEvent(fullscreenVoiceEvent_);
783 }
784 isSubscribeMultimodal_ = false;
785 return true;
786 }
787
SetNewComponent(const RefPtr<Component> & newComponent)788 void VideoElement::SetNewComponent(const RefPtr<Component>& newComponent)
789 {
790 if (newComponent == nullptr || !isElementPrepared_) {
791 Element::SetNewComponent(newComponent);
792 return;
793 }
794 auto videoComponent = AceType::DynamicCast<VideoComponent>(newComponent);
795 if (videoComponent) {
796 if (src_ == videoComponent->GetSrc()) {
797 if (isError_) {
798 return;
799 }
800 hasSrcChanged_ = false;
801 InitStatus(videoComponent);
802
803 // When the video is in the initial state and the attribute is auto play, start playing.
804 if (isInitialState_ && isAutoPlay_) {
805 Start();
806 }
807 } else {
808 hasSrcChanged_ = true;
809 ResetStatus();
810 InitStatus(videoComponent);
811 CreatePlatformResource();
812 }
813 if (texture_) {
814 #ifndef OHOS_STANDARD_SYSTEM
815 videoComponent->SetTextureId(texture_->GetId());
816 #endif
817 videoComponent->SetSrcWidth(videoWidth_);
818 videoComponent->SetSrcHeight(videoHeight_);
819 videoComponent->SetFit(imageFit_);
820 videoComponent->SetImagePosition(imagePosition_);
821 }
822 videoComponent->SetChild(CreateChild());
823
824 Element::SetNewComponent(videoComponent);
825 }
826 }
827
InitEvent(const RefPtr<VideoComponent> & videoComponent)828 void VideoElement::InitEvent(const RefPtr<VideoComponent>& videoComponent)
829 {
830 if (!videoComponent->GetPreparedEventId().IsEmpty()) {
831 onPrepared_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetPreparedEventId(), context_);
832 }
833
834 if (!videoComponent->GetFinishEventId().IsEmpty()) {
835 onFinish_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetFinishEventId(), context_);
836 }
837
838 if (!videoComponent->GetErrorEventId().IsEmpty()) {
839 onError_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetErrorEventId(), context_);
840 }
841
842 if (!videoComponent->GetTimeUpdateEventId().IsEmpty()) {
843 onTimeUpdate_ =
844 AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetTimeUpdateEventId(), context_);
845 }
846
847 if (!videoComponent->GetStartEventId().IsEmpty()) {
848 onStart_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetStartEventId(), context_);
849 }
850
851 if (!videoComponent->GetPauseEventId().IsEmpty()) {
852 onPause_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetPauseEventId(), context_);
853 }
854
855 if (!videoComponent->GetStopEventId().IsEmpty()) {
856 onStop_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetStopEventId(), context_);
857 }
858
859 if (!videoComponent->GetSeekingEventId().IsEmpty()) {
860 onSeeking_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetSeekingEventId(), context_);
861 }
862
863 if (!videoComponent->GetSeekedEventId().IsEmpty()) {
864 onSeeked_ = AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetSeekedEventId(), context_);
865 }
866
867 if (!videoComponent->GetFullscreenChangeEventId().IsEmpty()) {
868 onFullScreenChange_ =
869 AceAsyncEvent<void(const std::string&)>::Create(videoComponent->GetFullscreenChangeEventId(), context_);
870 }
871 }
872
SetMethodCall(const RefPtr<VideoComponent> & videoComponent)873 void VideoElement::SetMethodCall(const RefPtr<VideoComponent>& videoComponent)
874 {
875 auto videoController = videoComponent->GetVideoController();
876 if (videoController) {
877 auto context = context_.Upgrade();
878 if (!context) {
879 return;
880 }
881 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
882 videoController->SetStartImpl([weak = WeakClaim(this), uiTaskExecutor]() {
883 uiTaskExecutor.PostTask([weak]() {
884 auto videoElement = weak.Upgrade();
885 if (videoElement) {
886 videoElement->Start();
887 }
888 }, "ArkUIVideoStart");
889 });
890 videoController->SetPausetImpl([weak = WeakClaim(this), uiTaskExecutor]() {
891 uiTaskExecutor.PostTask([weak]() {
892 auto videoElement = weak.Upgrade();
893 if (videoElement) {
894 videoElement->Pause();
895 }
896 }, "ArkUIVideoPause");
897 });
898 videoController->SetStopImpl([weak = WeakClaim(this), uiTaskExecutor]() {
899 uiTaskExecutor.PostTask([weak]() {
900 auto videoElement = weak.Upgrade();
901 if (videoElement) {
902 videoElement->Stop();
903 }
904 }, "ArkUIVideoStop");
905 });
906 videoController->SetSeekToImpl([weak = WeakClaim(this), uiTaskExecutor](float pos, SeekMode seekMode) {
907 uiTaskExecutor.PostTask([weak, pos, seekMode]() {
908 auto videoElement = weak.Upgrade();
909 if (videoElement) {
910 videoElement->SetCurrentTime(pos, seekMode);
911 }
912 }, "ArkUIVideoSetCurrentTime");
913 });
914 videoController->SetRequestFullscreenImpl([weak = WeakClaim(this), uiTaskExecutor](bool isPortrait) {
915 uiTaskExecutor.PostTask([weak, isPortrait]() {
916 auto videoElement = weak.Upgrade();
917 if (videoElement) {
918 videoElement->OnPreFullScreen(isPortrait);
919 videoElement->FullScreen();
920 }
921 }, "ArkUIVideoFullScreen");
922 });
923 videoController->SetExitFullscreenImpl([weak = WeakClaim(this), uiTaskExecutor](bool isSync) {
924 if (isSync) {
925 auto videoElement = weak.Upgrade();
926 if (videoElement) {
927 videoElement->ExitFullScreen();
928 }
929 return;
930 }
931 uiTaskExecutor.PostTask([weak]() {
932 auto videoElement = weak.Upgrade();
933 if (videoElement) {
934 videoElement->ExitFullScreen();
935 }
936 }, "ArkUIVideoExitFullScreen");
937 });
938 }
939 }
940
SetRespondChildEvent()941 void VideoElement::SetRespondChildEvent()
942 {
943 shieldId_ = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
944 startBtnClickId_ = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
945 BackEndEventManager<void()>::GetInstance().BindBackendEvent(startBtnClickId_, [weak = WeakClaim(this)]() {
946 auto videoElement = weak.Upgrade();
947 if (videoElement) {
948 videoElement->OnStartBtnClick();
949 }
950 });
951 sliderMovedCallbackId_ = BackEndEventManager<void(const std::string&)>::GetInstance().GetAvailableMarker();
952 BackEndEventManager<void(const std::string&)>::GetInstance().BindBackendEvent(
953 sliderMovedCallbackId_, [weak = WeakClaim(this)](const std::string& param) {
954 auto videoElement = weak.Upgrade();
955 if (videoElement) {
956 videoElement->OnSliderChange(param);
957 }
958 });
959 sliderMovingCallbackId_ = BackEndEventManager<void(const std::string&)>::GetInstance().GetAvailableMarker();
960 BackEndEventManager<void(const std::string&)>::GetInstance().BindBackendEvent(
961 sliderMovingCallbackId_, [weak = WeakClaim(this)](const std::string& param) {
962 auto videoElement = weak.Upgrade();
963 if (videoElement) {
964 videoElement->OnSliderMoving(param);
965 }
966 });
967 fullscreenBtnClickId_ = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
968 BackEndEventManager<void()>::GetInstance().BindBackendEvent(fullscreenBtnClickId_, [weak = WeakClaim(this)]() {
969 auto videoElement = weak.Upgrade();
970 if (videoElement) {
971 videoElement->OnFullScreenBtnClick();
972 }
973 });
974 }
975
CreatePlatformResource()976 void VideoElement::CreatePlatformResource()
977 {
978 ReleasePlatformResource();
979
980 auto context = context_.Upgrade();
981 if (!context) {
982 return;
983 }
984 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
985
986 auto errorCallback = [weak = WeakClaim(this), uiTaskExecutor](
987 const std::string& errorId, const std::string& param) {
988 uiTaskExecutor.PostTask([weak, errorId, param] {
989 auto videoElement = weak.Upgrade();
990 if (videoElement) {
991 videoElement->OnError(errorId, param);
992 }
993 }, "ArkUIVideoError");
994 };
995 texture_ = AceType::MakeRefPtr<Texture>(context_, errorCallback);
996
997 texture_->Create([weak = WeakClaim(this), errorCallback](int64_t id) mutable {
998 auto videoElement = weak.Upgrade();
999 if (videoElement) {
1000 videoElement->CreatePlayer(id, std::move(errorCallback));
1001 }
1002 });
1003 }
1004
CreatePlayer(int64_t id,ErrorCallback && errorCallback)1005 void VideoElement::CreatePlayer(int64_t id, ErrorCallback&& errorCallback)
1006 {
1007 player_ = AceType::MakeRefPtr<Player>(id, src_, context_, std::move(errorCallback));
1008 player_->SetMute(isMute_);
1009 player_->SetAutoPlay(isAutoPlay_);
1010 InitListener();
1011 player_->Create(nullptr);
1012 }
1013
InitListener()1014 void VideoElement::InitListener()
1015 {
1016 auto context = context_.Upgrade();
1017 if (!context) {
1018 return;
1019 }
1020
1021 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1022 auto videoElement = WeakClaim(this);
1023 if (!isExternalResource_) {
1024 auto onTextureRefresh = [videoElement, uiTaskExecutor]() {
1025 if (!videoElement.Upgrade()) {
1026 return;
1027 }
1028 uiTaskExecutor.PostSyncTask([&videoElement] {
1029 auto video = videoElement.Upgrade();
1030 if (video) {
1031 video->OnTextureRefresh();
1032 }
1033 }, "ArkUIVideoTextureRefresh");
1034 };
1035 texture_->SetRefreshListener(onTextureRefresh);
1036 }
1037
1038 auto onPrepared = [videoElement, uiTaskExecutor](uint32_t width, uint32_t height, bool isPlaying, uint32_t duration,
1039 uint32_t currentPos, bool needFireEvent) {
1040 if (!videoElement.Upgrade()) {
1041 return;
1042 }
1043 uiTaskExecutor.PostSyncTask([&videoElement, width, height, isPlaying, duration, currentPos, needFireEvent] {
1044 auto video = videoElement.Upgrade();
1045 if (video) {
1046 video->OnPrepared(width, height, isPlaying, duration, currentPos, needFireEvent);
1047 }
1048 }, "ArkUIVideoPrepared");
1049 };
1050
1051 auto onPlayerStatus = [videoElement, uiTaskExecutor](bool isPlaying) {
1052 if (!videoElement.Upgrade()) {
1053 return;
1054 }
1055 uiTaskExecutor.PostSyncTask([&videoElement, isPlaying] {
1056 auto video = videoElement.Upgrade();
1057 if (video) {
1058 video->OnPlayerStatus(isPlaying ? PlaybackStatus::STARTED : PlaybackStatus::NONE);
1059 }
1060 }, "ArkUIVideoPlayerStatus");
1061 };
1062
1063 auto onCurrentTimeChange = [videoElement, uiTaskExecutor](uint32_t currentPos) {
1064 if (!videoElement.Upgrade()) {
1065 return;
1066 }
1067 uiTaskExecutor.PostSyncTask([&videoElement, currentPos] {
1068 auto video = videoElement.Upgrade();
1069 if (video) {
1070 video->OnCurrentTimeChange(currentPos);
1071 }
1072 }, "ArkUIVideoCurrentTimeChange");
1073 };
1074
1075 auto onCompletion = [videoElement, uiTaskExecutor] {
1076 if (!videoElement.Upgrade()) {
1077 return;
1078 }
1079 uiTaskExecutor.PostSyncTask([&videoElement] {
1080 auto video = videoElement.Upgrade();
1081 if (video) {
1082 video->OnCompletion();
1083 }
1084 }, "ArkUIVideoCompletion");
1085 };
1086
1087 player_->AddPreparedListener(onPrepared);
1088 player_->AddPlayStatusListener(onPlayerStatus);
1089 player_->AddCurrentPosListener(onCurrentTimeChange);
1090 player_->AddCompletionListener(onCompletion);
1091
1092 player_->AddRefreshRenderListener([videoElement]() {
1093 auto video = videoElement.Upgrade();
1094 if (video) {
1095 video->OnTextureRefresh();
1096 }
1097 });
1098 }
1099
ReleasePlatformResource()1100 void VideoElement::ReleasePlatformResource()
1101 {
1102 #ifndef OHOS_STANDARD_SYSTEM
1103 auto context = context_.Upgrade();
1104 if (!context) {
1105 return;
1106 }
1107
1108 // Reusing texture will cause a problem that last frame of last video will be display.
1109 if (texture_) {
1110 auto platformTaskExecutor =
1111 SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::PLATFORM);
1112
1113 // Release player first.
1114 if (player_) {
1115 if (!isExternalResource_) {
1116 player_->Stop();
1117 player_->Release();
1118 }
1119
1120 if (platformTaskExecutor.IsRunOnCurrentThread()) {
1121 player_.Reset();
1122 } else {
1123 // Make sure it's destroyed when it's release task done.
1124 platformTaskExecutor.PostTask([player = player_]() {}, "ArkUIVideoReleasePlayer");
1125 }
1126 }
1127
1128 if (platformTaskExecutor.IsRunOnCurrentThread()) {
1129 if (!isExternalResource_) {
1130 texture_->Release();
1131 }
1132 texture_.Reset();
1133 } else {
1134 if (!isExternalResource_) {
1135 #if defined(ENABLE_NATIVE_VIEW)
1136 texture_->Release();
1137 }
1138 // Make sure it's destroyed when it's release task done.
1139 platformTaskExecutor.PostTask([texture = texture_]() {}, "ArkUIVideoReleaseTexture");
1140 #else
1141 auto gpuTaskExecutor =
1142 SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::GPU);
1143 // Release texture after paint.
1144 auto weak = AceType::WeakClaim(AceType::RawPtr(texture_));
1145 gpuTaskExecutor.PostTask([weak, platformTaskExecutor]() {
1146 auto texture = weak.Upgrade();
1147 if (texture == nullptr) {
1148 LOGE("texture is nullptr");
1149 return;
1150 }
1151 texture->Release();
1152 // Make sure it's destroyed when it's release task done.
1153 platformTaskExecutor.PostTask([texture]() {}, "ArkUIVideoReleaseTexture");
1154 }, "ArkUIVideoReleaseTexture");
1155 } else {
1156 // Make sure it's destroyed when it's release task done.
1157 platformTaskExecutor.PostTask([texture = texture_]() {}, "ArkUIVideoReleaseTexture");
1158 }
1159 #endif
1160 }
1161 }
1162 #endif
1163 }
1164
UpdateChildInner(const RefPtr<Component> & childComponent)1165 void VideoElement::UpdateChildInner(const RefPtr<Component>& childComponent)
1166 {
1167 const auto& child = children_.empty() ? nullptr : children_.front();
1168 UpdateChild(child, childComponent);
1169 }
1170
OnError(const std::string & errorId,const std::string & param)1171 void VideoElement::OnError(const std::string& errorId, const std::string& param)
1172 {
1173 isError_ = true;
1174 std::string errorcode = Localization::GetInstance()->GetErrorDescription(errorId);
1175 UpdateChildInner(CreateErrorText(errorcode));
1176
1177 if (onError_) {
1178 std::string param;
1179 if (IsDeclarativePara()) {
1180 auto json = JsonUtil::Create(true);
1181 json->Put("error", "");
1182 param = json->ToString();
1183 } else {
1184 param = std::string("\"error\",{").append("}");
1185 }
1186 onError_(param);
1187 }
1188 }
1189
OnResolutionChange() const1190 void VideoElement::OnResolutionChange() const
1191 {
1192 #if defined(ENABLE_ROSEN_BACKEND) && defined(OHOS_STANDARD_SYSTEM)
1193 if (!mediaPlayer_ || !renderNode_) {
1194 LOGE("player or render is null");
1195 return;
1196 }
1197
1198 auto rosenTexture = DynamicCast<RosenRenderTexture>(renderNode_);
1199 if (!rosenTexture) {
1200 LOGE("backend is not rosen.");
1201 return;
1202 }
1203
1204 Size videoSize = Size(mediaPlayer_->GetVideoWidth(), mediaPlayer_->GetVideoHeight());
1205 LOGI("OnResolutionChange video size: %{public}s", videoSize.ToString().c_str());
1206 rosenTexture->SyncProperties(videoSize, imageFit_, imagePosition_);
1207 #endif
1208 }
1209
OnPrepared(uint32_t width,uint32_t height,bool isPlaying,uint32_t duration,uint32_t currentPos,bool needFireEvent)1210 void VideoElement::OnPrepared(
1211 uint32_t width, uint32_t height, bool isPlaying, uint32_t duration, uint32_t currentPos, bool needFireEvent)
1212 {
1213 isPlaying_ = isPlaying;
1214 isReady_ = true;
1215 videoWidth_ = width;
1216 videoHeight_ = height;
1217 duration_ = duration;
1218 currentPos_ = std::max(startTime_, static_cast<int32_t>(currentPos));
1219
1220 IntTimeToText(duration_, durationText_);
1221 IntTimeToText(currentPos_, currentPosText_);
1222
1223 auto video = AceType::MakeRefPtr<VideoComponent>();
1224 #ifndef OHOS_STANDARD_SYSTEM
1225 video->SetTextureId(texture_->GetId());
1226 #endif
1227 video->SetSrcWidth(videoWidth_);
1228 video->SetSrcHeight(videoHeight_);
1229 video->SetFit(imageFit_);
1230 video->SetImagePosition(imagePosition_);
1231
1232 if (isPlaying || currentPos != 0) {
1233 isInitialState_ = false;
1234 }
1235
1236 if (renderNode_ != nullptr) {
1237 video->SetNeedControls(needControls_);
1238 renderNode_->Update(video);
1239 }
1240 UpdateChildInner(CreateChild());
1241
1242 if (needFireEvent && onPrepared_) {
1243 std::string param;
1244 if (IsDeclarativePara()) {
1245 auto json = JsonUtil::Create(true);
1246 json->Put("duration", static_cast<double>(duration_));
1247 param = json->ToString();
1248 } else {
1249 param = std::string("\"prepared\",{\"duration\":").append(std::to_string(duration_)).append("}");
1250 }
1251 LOGI("video onPrepared event: %s ", param.c_str());
1252 onPrepared_(param);
1253 }
1254
1255 if (!isExternalResource_ || isMediaPlayerFullStatus_) {
1256 SetCurrentTime(startTime_, SeekMode::SEEK_CLOSEST);
1257 EnableLooping(isLoop_);
1258 SetSpeed(speed_);
1259 }
1260
1261 if (isStop_) {
1262 isStop_ = false;
1263 Start();
1264 }
1265
1266 #ifdef OHOS_STANDARD_SYSTEM
1267 if (isAutoPlay_) {
1268 Start();
1269 } else if (isMediaPlayerFullStatus_ && pastPlayingStatus_) {
1270 Start();
1271 pastPlayingStatus_ = false;
1272 }
1273 #endif
1274 }
1275
OnPlayerStatus(PlaybackStatus status)1276 void VideoElement::OnPlayerStatus(PlaybackStatus status)
1277 {
1278 bool isPlaying = (status == PlaybackStatus::STARTED);
1279 if (isInitialState_) {
1280 isInitialState_ = !isPlaying;
1281 }
1282
1283 isPlaying_ = isPlaying;
1284 if (!isFullScreen_ || isExternalResource_) {
1285 UpdateChildInner(CreateChild());
1286 }
1287
1288 if (isPlaying) {
1289 if (onStart_) {
1290 std::string param;
1291 if (IsDeclarativePara()) {
1292 auto json = JsonUtil::Create(true);
1293 json->Put("start", "");
1294 param = json->ToString();
1295 } else {
1296 param = std::string("\"start\",{").append("}");
1297 }
1298 LOGE("video onStart event: %s ", param.c_str());
1299 onStart_(param);
1300 }
1301 } else {
1302 if (onPause_) {
1303 std::string param;
1304 if (IsDeclarativePara()) {
1305 auto json = JsonUtil::Create(true);
1306 json->Put("pause", "");
1307 param = json->ToString();
1308 } else {
1309 param = std::string("\"pause\",{").append("}");
1310 }
1311 LOGE("video onPause event: %s ", param.c_str());
1312 onPause_(param);
1313 }
1314 }
1315
1316 #ifdef OHOS_STANDARD_SYSTEM
1317 if (status == PlaybackStatus::PREPARED) {
1318 auto context = context_.Upgrade();
1319 if (context == nullptr) {
1320 LOGE("context is nullptr");
1321 return;
1322 }
1323 if (!mediaPlayer_) {
1324 return;
1325 }
1326 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1327 auto videoElement = WeakClaim(this);
1328 Size videoSize = Size(mediaPlayer_->GetVideoWidth(), mediaPlayer_->GetVideoHeight());
1329 int32_t milliSecondDuration = 0;
1330 mediaPlayer_->GetDuration(milliSecondDuration);
1331 uiTaskExecutor.PostSyncTask([&videoElement, videoSize, duration = milliSecondDuration / MILLISECONDS_TO_SECONDS,
1332 startTime = startTime_] {
1333 auto video = videoElement.Upgrade();
1334 if (video) {
1335 LOGI("Video OnPrepared video size: %{public}s", videoSize.ToString().c_str());
1336 video->OnPrepared(videoSize.Width(), videoSize.Height(), false, duration, startTime, true);
1337 }
1338 }, "ArkUIVideoPlaybackPrepared");
1339 } else if (status == PlaybackStatus::PLAYBACK_COMPLETE) {
1340 OnCompletion();
1341 }
1342 #endif
1343 }
1344
OnCurrentTimeChange(uint32_t currentPos)1345 void VideoElement::OnCurrentTimeChange(uint32_t currentPos)
1346 {
1347 #ifdef OHOS_STANDARD_SYSTEM
1348 if (isMediaPlayerFullStatus_ && startTime_ != 0) {
1349 if (GreatNotEqual(startTime_, currentPos)) {
1350 currentPos = static_cast<uint32_t>(startTime_);
1351 }
1352 }
1353 if (currentPos == currentPos_ || isStop_) {
1354 return;
1355 }
1356 if (duration_ == 0) {
1357 int32_t duration = 0;
1358 if (mediaPlayer_->GetDuration(duration) == 0) {
1359 duration_ = static_cast<uint32_t>(duration / MILLISECONDS_TO_SECONDS);
1360 IntTimeToText(duration_, durationText_);
1361 }
1362 }
1363 #endif
1364
1365 isInitialState_ = isInitialState_ ? currentPos == 0 : false;
1366 IntTimeToText(currentPos, currentPosText_);
1367 currentPos_ = currentPos;
1368
1369 UpdateChildInner(CreateChild());
1370
1371 if (onTimeUpdate_) {
1372 std::string param;
1373 if (IsDeclarativePara()) {
1374 auto json = JsonUtil::Create(true);
1375 json->Put("time", static_cast<double>(currentPos));
1376 param = json->ToString();
1377 } else {
1378 param = std::string("\"timeupdate\",{\"currenttime\":").append(std::to_string(currentPos)).append("}");
1379 }
1380 LOGI("video onTimeUpdate event: %s ", param.c_str());
1381 onTimeUpdate_(param);
1382 }
1383 }
1384
OnCompletion()1385 void VideoElement::OnCompletion()
1386 {
1387 LOGI("VideoElement::OnCompletion");
1388 currentPos_ = duration_;
1389 IntTimeToText(currentPos_, currentPosText_);
1390
1391 isPlaying_ = false;
1392 UpdateChildInner(CreateChild());
1393
1394 if (onFinish_) {
1395 std::string param;
1396 if (IsDeclarativePara()) {
1397 auto json = JsonUtil::Create(true);
1398 json->Put("finish", "");
1399 param = json->ToString();
1400 } else {
1401 param = std::string("\"finish\",{").append("}");
1402 }
1403 LOGI("video onFinish event: %s ", param.c_str());
1404 onFinish_(param);
1405 }
1406 }
1407
CreateErrorText(const std::string & errorMsg)1408 const RefPtr<Component> VideoElement::CreateErrorText(const std::string& errorMsg)
1409 {
1410 auto text = AceType::MakeRefPtr<TextComponent>(errorMsg);
1411 text->SetTextStyle(theme_->GetErrorTextStyle());
1412 text->SetTextDirection(textDirection_);
1413
1414 std::list<RefPtr<Component>> childrenAlign;
1415 childrenAlign.emplace_back(text);
1416
1417 return AceType::MakeRefPtr<AlignComponent>(childrenAlign, Alignment::TOP_CENTER);
1418 }
1419
CreateCurrentText()1420 const RefPtr<Component> VideoElement::CreateCurrentText()
1421 {
1422 auto textPos = AceType::MakeRefPtr<TextComponent>(currentPosText_);
1423 textPos->SetTextStyle(theme_->GetTimeTextStyle());
1424 return textPos;
1425 }
1426
CreateDurationText()1427 const RefPtr<Component> VideoElement::CreateDurationText()
1428 {
1429 auto textDuration = AceType::MakeRefPtr<TextComponent>(durationText_);
1430 textDuration->SetTextStyle(theme_->GetTimeTextStyle());
1431 return textDuration;
1432 }
1433
CreateSlider()1434 const RefPtr<Component> VideoElement::CreateSlider()
1435 {
1436 auto slider = AceType::MakeRefPtr<SliderComponent>(currentPos_, 1.0, 0.0, duration_);
1437 slider->InitStyle(sliderTheme_);
1438 slider->SetOnMoveEndEventId(sliderMovedCallbackId_);
1439 slider->SetOnMovingEventId(sliderMovingCallbackId_);
1440 slider->SetTextDirection(textDirection_);
1441 return slider;
1442 }
1443
CreatePlayBtn()1444 const RefPtr<Component> VideoElement::CreatePlayBtn()
1445 {
1446 auto imageIcon = InternalResource::ResourceId::PLAY_SVG;
1447
1448 if (pastPlayingStatus_ || isPlaying_) {
1449 imageIcon = InternalResource::ResourceId::PAUSE_SVG;
1450 }
1451
1452 auto image = AceType::MakeRefPtr<ImageComponent>(imageIcon);
1453 const Size& btnSize = theme_->GetBtnSize();
1454 image->SetWidth(Dimension(btnSize.Width(), DimensionUnit::VP));
1455 image->SetHeight(Dimension(btnSize.Height(), DimensionUnit::VP));
1456 image->SetTextDirection(textDirection_);
1457 image->SetMatchTextDirection(true);
1458 std::list<RefPtr<Component>> btnChildren;
1459 btnChildren.emplace_back(image);
1460
1461 auto button = AceType::MakeRefPtr<ButtonComponent>(btnChildren);
1462 button->SetWidth(Dimension(btnSize.Width(), DimensionUnit::VP));
1463 button->SetHeight(Dimension(btnSize.Height(), DimensionUnit::VP));
1464 button->SetType(ButtonType::ICON);
1465
1466 if (IsDeclarativePara()) {
1467 button->SetClickFunction([weak = WeakClaim(this)]() {
1468 auto videoElement = weak.Upgrade();
1469 if (videoElement) {
1470 videoElement->OnStartBtnClick();
1471 }
1472 });
1473 } else {
1474 button->SetClickedEventId(startBtnClickId_);
1475 }
1476 return button;
1477 }
1478
CreateFullScreenBtn()1479 const RefPtr<Component> VideoElement::CreateFullScreenBtn()
1480 {
1481 auto imageIcon = InternalResource::ResourceId::FULLSCREEN_SVG;
1482
1483 if (isFullScreen_) {
1484 imageIcon = InternalResource::ResourceId::QUIT_FULLSCREEN_SVG;
1485 }
1486
1487 auto image = AceType::MakeRefPtr<ImageComponent>(imageIcon);
1488 const Size& btnSize = theme_->GetBtnSize();
1489 image->SetWidth(Dimension(btnSize.Width(), DimensionUnit::VP));
1490 image->SetHeight(Dimension(btnSize.Height(), DimensionUnit::VP));
1491 image->SetTextDirection(textDirection_);
1492 image->SetMatchTextDirection(true);
1493
1494 std::list<RefPtr<Component>> btnChildren;
1495 btnChildren.emplace_back(image);
1496
1497 auto button = AceType::MakeRefPtr<ButtonComponent>(btnChildren);
1498 button->SetWidth(Dimension(btnSize.Width(), DimensionUnit::VP));
1499 button->SetHeight(Dimension(btnSize.Height(), DimensionUnit::VP));
1500 button->SetType(ButtonType::ICON);
1501
1502 if (IsDeclarativePara()) {
1503 button->SetClickFunction([weak = WeakClaim(this), isFullScreen = isFullScreen_]() {
1504 auto videoElement = weak.Upgrade();
1505 if (videoElement) {
1506 videoElement->OnFullScreenBtnClick();
1507 }
1508 });
1509 } else {
1510 button->SetClickedEventId(fullscreenBtnClickId_);
1511 }
1512 return button;
1513 }
1514
SetPadding(const RefPtr<Component> & component,Edge && edge)1515 const RefPtr<Component> VideoElement::SetPadding(const RefPtr<Component>& component, Edge&& edge)
1516 {
1517 auto paddingComponent = AceType::MakeRefPtr<PaddingComponent>();
1518 paddingComponent->SetPadding(std::move(edge));
1519 paddingComponent->SetChild(component);
1520
1521 return paddingComponent;
1522 }
1523
CreateControl()1524 const RefPtr<Component> VideoElement::CreateControl()
1525 {
1526 std::list<RefPtr<Component>> rowChildren;
1527
1528 rowChildren.emplace_back(SetPadding(CreatePlayBtn(), Edge(theme_->GetBtnEdge())));
1529
1530 rowChildren.emplace_back(SetPadding(CreateCurrentText(), Edge(theme_->GetTextEdge())));
1531
1532 rowChildren.emplace_back(
1533 AceType::MakeRefPtr<FlexItemComponent>(VIDEO_CHILD_COMMON_FLEX_GROW, VIDEO_CHILD_COMMON_FLEX_SHRINK,
1534 VIDEO_CHILD_COMMON_FLEX_BASIS, SetPadding(CreateSlider(), Edge(theme_->GetSliderEdge()))));
1535
1536 rowChildren.emplace_back(SetPadding(CreateDurationText(), Edge(theme_->GetTextEdge())));
1537
1538 #ifndef OHOS_STANDARD_SYSTEM
1539 rowChildren.emplace_back(SetPadding(CreateFullScreenBtn(), Edge(theme_->GetBtnEdge())));
1540 #endif
1541
1542 auto decoration = AceType::MakeRefPtr<Decoration>();
1543 decoration->SetBackgroundColor(theme_->GetBkgColor());
1544 auto box = AceType::MakeRefPtr<BoxComponent>();
1545 box->SetBackDecoration(decoration);
1546 auto row = AceType::MakeRefPtr<RowComponent>(FlexAlign::CENTER, FlexAlign::CENTER, rowChildren);
1547 row->SetTextDirection(textDirection_);
1548 box->SetChild(row);
1549
1550 auto gestureListener = AceType::MakeRefPtr<GestureListenerComponent>(box);
1551 gestureListener->SetOnClickId(shieldId_);
1552 gestureListener->SetOnLongPressId(shieldId_);
1553
1554 return gestureListener;
1555 }
1556
CreatePoster()1557 const RefPtr<Component> VideoElement::CreatePoster()
1558 {
1559 RefPtr<ImageComponent> image;
1560 if (posterImage_) {
1561 image = posterImage_;
1562 } else {
1563 image = AceType::MakeRefPtr<ImageComponent>(poster_);
1564 }
1565 if (!image) {
1566 LOGE("create poster image fail");
1567 return nullptr;
1568 }
1569 image->SetImageFit(imageFit_);
1570 image->SetImageObjectPosition(imagePosition_);
1571 image->SetFitMaxSize(true);
1572
1573 std::list<RefPtr<Component>> childrenAlign;
1574 childrenAlign.emplace_back(image);
1575
1576 auto box = AceType::MakeRefPtr<BoxComponent>();
1577 box->SetChild(AceType::MakeRefPtr<AlignComponent>(childrenAlign, Alignment::CENTER));
1578 return box;
1579 }
1580
CreateChild()1581 const RefPtr<Component> VideoElement::CreateChild()
1582 {
1583 RefPtr<Component> child;
1584 if (isInitialState_ && (!poster_.empty() || posterImage_)) {
1585 std::list<RefPtr<Component>> columnChildren;
1586 #ifndef OHOS_STANDARD_SYSTEM
1587 columnChildren.emplace_back(AceType::MakeRefPtr<FlexItemComponent>(VIDEO_CHILD_COMMON_FLEX_GROW,
1588 VIDEO_CHILD_COMMON_FLEX_SHRINK, VIDEO_CHILD_COMMON_FLEX_BASIS, CreatePoster()));
1589 #else
1590 if (startTime_ == 0) {
1591 columnChildren.emplace_back(AceType::MakeRefPtr<FlexItemComponent>(VIDEO_CHILD_COMMON_FLEX_GROW,
1592 VIDEO_CHILD_COMMON_FLEX_SHRINK, VIDEO_CHILD_COMMON_FLEX_BASIS, CreatePoster()));
1593 }
1594 #endif
1595 if (needControls_) {
1596 columnChildren.emplace_back(CreateControl());
1597 } else if (IsDeclarativePara()) {
1598 columnChildren.emplace_back(AceType::MakeRefPtr<BoxComponent>());
1599 }
1600 child = AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_END, FlexAlign::SPACE_AROUND, columnChildren);
1601 } else if (needControls_) {
1602 std::list<RefPtr<Component>> childrenAlign;
1603 childrenAlign.emplace_back(CreateControl());
1604 child = AceType::MakeRefPtr<AlignComponent>(childrenAlign, Alignment::BOTTOM_RIGHT);
1605 }
1606
1607 if (child) {
1608 auto display = AceType::MakeRefPtr<DisplayComponent>(child);
1609 if (!display) {
1610 LOGE("Create display component failed. display is null.");
1611 return display;
1612 }
1613 auto textureRender = GetRenderNode();
1614 if (!textureRender) {
1615 return display;
1616 }
1617 auto displayRender = AceType::DynamicCast<RenderDisplay>(textureRender->GetFirstChild());
1618 if (!displayRender) {
1619 return display;
1620 }
1621 uint8_t opacity = displayRender->GetOpacity();
1622 display->SetOpacity(opacity * 1.0 / UINT8_MAX);
1623 return display;
1624 } else {
1625 return child;
1626 }
1627 }
1628
IsDeclarativePara()1629 bool VideoElement::IsDeclarativePara()
1630 {
1631 auto context = context_.Upgrade();
1632 if (!context) {
1633 return false;
1634 }
1635
1636 return context->GetIsDeclarative();
1637 }
1638
OnStartBtnClick()1639 void VideoElement::OnStartBtnClick()
1640 {
1641 #ifdef OHOS_STANDARD_SYSTEM
1642 if (!mediaPlayer_) {
1643 LOGE("Media Player is empty");
1644 return;
1645 }
1646 if (mediaPlayer_->IsPlaying()) {
1647 #else
1648 if (isPlaying_) {
1649 #endif
1650 Pause();
1651 } else {
1652 Start();
1653 }
1654 }
1655
1656 void VideoElement::OnFullScreenBtnClick()
1657 {
1658 if (!isFullScreen_) {
1659 FullScreen();
1660 } else {
1661 ExitFullScreen();
1662 }
1663 }
1664
1665 void VideoElement::OnSliderChange(const std::string& param)
1666 {
1667 size_t pos = param.find("\"value\":");
1668 if (pos != std::string::npos) {
1669 if (pastPlayingStatus_) {
1670 isPlaying_ = false;
1671 Start();
1672 pastPlayingStatus_ = false;
1673 }
1674 std::stringstream ss;
1675 uint32_t value = 0;
1676
1677 ss << param.substr(pos + 8); // Need to add the length of "\"value\":".
1678 ss >> value;
1679
1680 SetCurrentTime(value);
1681 if (onSeeked_) {
1682 std::string param;
1683 if (IsDeclarativePara()) {
1684 auto json = JsonUtil::Create(true);
1685 json->Put("time", static_cast<double>(value));
1686 param = json->ToString();
1687 } else {
1688 param = std::string("\"seeked\",{\"currenttime\":").append(std::to_string(value)).append("}");
1689 }
1690 onSeeked_(param);
1691 }
1692 }
1693 }
1694
1695 void VideoElement::OnSliderMoving(const std::string& param)
1696 {
1697 size_t pos = param.find("\"value\":");
1698 if (pos != std::string::npos) {
1699 if (isPlaying_ && !pastPlayingStatus_) {
1700 Pause();
1701 pastPlayingStatus_ = true;
1702 }
1703 std::stringstream ss;
1704 uint32_t value = 0;
1705
1706 // Need to add the length of "\"value\":".
1707 if (param.size() > (pos + 8)) {
1708 ss << param.substr(pos + 8);
1709 ss >> value;
1710 }
1711
1712 SetCurrentTime(value);
1713 if (onSeeking_) {
1714 std::string param;
1715 if (IsDeclarativePara()) {
1716 auto json = JsonUtil::Create(true);
1717 json->Put("time", static_cast<double>(value));
1718 param = json->ToString();
1719 } else {
1720 param = std::string("\"seeking\",{\"currenttime\":").append(std::to_string(value)).append("}");
1721 }
1722 onSeeking_(param);
1723 }
1724 }
1725 }
1726
1727 void VideoElement::IntTimeToText(uint32_t time, std::string& timeText)
1728 {
1729 // Whether the duration is longer than 1 hour.
1730 bool needShowHour = duration_ > 3600;
1731 timeText = Localization::GetInstance()->FormatDuration(time, needShowHour);
1732 }
1733
1734 void VideoElement::Start()
1735 {
1736 #ifdef OHOS_STANDARD_SYSTEM
1737 if (mediaPlayer_ == nullptr) {
1738 LOGE("player is null");
1739 return;
1740 }
1741 if (isStop_) {
1742 if (mediaPlayer_->PrepareAsync() != 0) {
1743 LOGE("Player prepare failed");
1744 return;
1745 }
1746 }
1747 if (!mediaPlayer_->IsPlaying()) {
1748 LOGI("Video Start");
1749 auto context = context_.Upgrade();
1750 if (context == nullptr) {
1751 LOGE("context is nullptr");
1752 return;
1753 }
1754 auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1755 platformTask.PostTask([mediaPlayer = mediaPlayer_] { mediaPlayer->Play(); }, "ArkUIVideoPlay");
1756 }
1757 #else
1758 if (isStop_) {
1759 CreatePlatformResource();
1760 return;
1761 }
1762 if (!isPlaying_ && player_) {
1763 player_->Start();
1764 }
1765 #endif
1766 }
1767
1768 void VideoElement::Pause()
1769 {
1770 #ifdef OHOS_STANDARD_SYSTEM
1771 if (mediaPlayer_ != nullptr && mediaPlayer_->IsPlaying()) {
1772 LOGI("Video Pause");
1773 mediaPlayer_->Pause();
1774 }
1775 #else
1776 if (isPlaying_ && player_) {
1777 player_->Pause();
1778 }
1779 #endif
1780 }
1781
1782 void VideoElement::Stop()
1783 {
1784 startTime_ = 0;
1785 OnCurrentTimeChange(0);
1786 OnPlayerStatus(PlaybackStatus::STOPPED);
1787 #ifndef OHOS_STANDARD_SYSTEM
1788 ReleasePlatformResource();
1789 #else
1790 if (mediaPlayer_ != nullptr) {
1791 LOGI("Video Stop");
1792 mediaPlayer_->Stop();
1793 }
1794 #endif
1795 isStop_ = true;
1796 }
1797
1798 void VideoElement::SetCurrentTime(float currentPos, SeekMode seekMode)
1799 {
1800 LOGI("pos: %{public}lf, mode: %{public}d", currentPos, seekMode);
1801 #ifdef OHOS_STANDARD_SYSTEM
1802 if (mediaPlayer_ != nullptr && GreatOrEqual(currentPos, 0.0) && LessOrEqual(currentPos, duration_)) {
1803 LOGI("Video Seek");
1804 startTime_ = currentPos;
1805 mediaPlayer_->Seek(currentPos * MILLISECONDS_TO_SECONDS, ConvertToMediaSeekMode(seekMode));
1806 }
1807 #else
1808 if (currentPos >= 0 && currentPos < duration_ && player_) {
1809 player_->SeekTo(currentPos);
1810 }
1811 #endif
1812 }
1813
1814 void VideoElement::FullScreen()
1815 {
1816 if (!isFullScreen_ && !isError_) {
1817 RefPtr<Component> component;
1818 #ifdef OHOS_STANDARD_SYSTEM
1819 if (mediaFullscreenEvent_) {
1820 component = mediaFullscreenEvent_(true, isPlaying_, texture_);
1821 }
1822 #else
1823 if (fullscreenEvent_) {
1824 component = fullscreenEvent_(true, player_, texture_);
1825 }
1826 #endif
1827 if (component) {
1828 auto context = context_.Upgrade();
1829 CHECK_NULL_VOID(context);
1830
1831 auto stackElement = context->GetLastStack();
1832 CHECK_NULL_VOID(stackElement);
1833
1834 // add fullscreen component cover component
1835 if (IsDeclarativePara()) {
1836 #ifdef OHOS_STANDARD_SYSTEM
1837 if (mediaPlayer_ != nullptr && mediaPlayer_->IsPlaying()) {
1838 mediaPlayer_->Pause();
1839 }
1840 #endif
1841 stackElement->PushComponent(AceType::MakeRefPtr<ComposedComponent>("0", "fullscreen", component));
1842 } else {
1843 auto composedComponent = AceType::DynamicCast<ComposedComponent>(component);
1844 if (!composedComponent) {
1845 LOGE("VideoElement::FullScreen: is not ComposedComponent");
1846 return;
1847 }
1848 if (composedComponent->IsInspector()) {
1849 LOGE("VideoElement::FullScreen: is InspectorComposedComponent");
1850 return;
1851 }
1852 stackElement->PushComponent(
1853 AceType::MakeRefPtr<ComposedComponent>(composedComponent->GetId() + "fullscreen",
1854 composedComponent->GetName() + "fullscreen", composedComponent->GetChild()));
1855 }
1856 isFullScreen_ = true;
1857 currentPlatformVersion_ = context->GetMinPlatformVersion();
1858 if (player_ && currentPlatformVersion_ > COMPATIBLE_VERSION) {
1859 #ifndef OHOS_STANDARD_SYSTEM
1860 player_->SetDirection(direction_);
1861 #endif
1862 }
1863 if (onFullScreenChange_) {
1864 std::string param;
1865 if (IsDeclarativePara()) {
1866 auto json = JsonUtil::Create(true);
1867 json->Put("fullscreen", isFullScreen_);
1868 param = json->ToString();
1869 } else {
1870 param = std::string("\"fullscreenchange\",{\"fullscreen\":")
1871 .append(std::to_string(isFullScreen_))
1872 .append("}");
1873 }
1874 onFullScreenChange_(param);
1875 }
1876 }
1877 }
1878 }
1879
1880 void VideoElement::ExitFullScreen()
1881 {
1882 #ifdef OHOS_STANDARD_SYSTEM
1883 if (mediaExitFullscreenEvent_ && isFullScreen_) {
1884 mediaExitFullscreenEvent_(false, isPlaying_, currentPos_);
1885 }
1886 #else
1887 if (fullscreenEvent_) {
1888 fullscreenEvent_(false, nullptr, nullptr);
1889 }
1890 #endif
1891
1892 if ((!isExternalResource_ && isFullScreen_) || isMediaPlayerFullStatus_) {
1893 auto context = context_.Upgrade();
1894 if (!context) {
1895 return;
1896 }
1897
1898 auto stackElement = context->GetLastStack();
1899 if (!stackElement) {
1900 return;
1901 }
1902 stackElement->PopVideo();
1903 currentPlatformVersion_ = context->GetMinPlatformVersion();
1904 if (player_ && currentPlatformVersion_ > COMPATIBLE_VERSION) {
1905 #ifndef OHOS_STANDARD_SYSTEM
1906 player_->SetLandscape();
1907 #endif
1908 }
1909 isFullScreen_ = false;
1910 if (onFullScreenChange_) {
1911 std::string param;
1912 if (IsDeclarativePara()) {
1913 auto json = JsonUtil::Create(true);
1914 json->Put("fullscreen", isFullScreen_);
1915 param = json->ToString();
1916 } else {
1917 param = std::string("\"fullscreenchange\",{\"fullscreen\":")
1918 .append(std::to_string(isFullScreen_))
1919 .append("}");
1920 }
1921 onFullScreenChange_(param);
1922 }
1923 if (renderNode_) {
1924 renderNode_->MarkNeedLayout();
1925 }
1926 }
1927 }
1928
1929 void VideoElement::SetVolume(float volume)
1930 {
1931 LOGI("volume: %{public}lf", volume);
1932 #ifdef OHOS_STANDARD_SYSTEM
1933 if (mediaPlayer_ != nullptr) {
1934 mediaPlayer_->SetVolume(volume, volume);
1935 }
1936 #else
1937 if (player_) {
1938 player_->SetVolume(volume);
1939 }
1940 #endif
1941 }
1942
1943 void VideoElement::EnableLooping(bool loop)
1944 {
1945 LOGI("loop: %{public}d", loop);
1946 #ifdef OHOS_STANDARD_SYSTEM
1947 if (mediaPlayer_) {
1948 mediaPlayer_->SetLooping(loop);
1949 }
1950 #else
1951 if (player_) {
1952 player_->EnableLooping(loop);
1953 }
1954 #endif
1955 }
1956
1957 void VideoElement::SetSpeed(float speed)
1958 {
1959 LOGI("speed: %{public}lf", speed);
1960 if (speed <= ILLEGAL_SPEED) {
1961 LOGE("speed is not valid: %{public}lf", speed);
1962 return;
1963 }
1964 #ifdef OHOS_STANDARD_SYSTEM
1965 if (mediaPlayer_ != nullptr) {
1966 mediaPlayer_->SetPlaybackSpeed(ConvertToMediaPlaybackSpeed(speed));
1967 }
1968 #else
1969 if (player_) {
1970 player_->SetSpeed(speed);
1971 }
1972 #endif
1973 }
1974
1975 void VideoElement::Dump()
1976 {
1977 if (texture_) {
1978 DumpLog::GetInstance().AddDesc("texture:", texture_->GetHashCode());
1979 }
1980 if (player_) {
1981 DumpLog::GetInstance().AddDesc("player:", player_->GetHashCode());
1982 }
1983 DumpLog::GetInstance().AddDesc("isError:", isError_);
1984 DumpLog::GetInstance().AddDesc("poster:", poster_);
1985 DumpLog::GetInstance().AddDesc("isInitialState_:", isInitialState_);
1986 DumpLog::GetInstance().AddDesc("videoWidth:", videoWidth_);
1987 DumpLog::GetInstance().AddDesc("videoHeight:", videoHeight_);
1988 DumpLog::GetInstance().AddDesc("isReady:", isReady_);
1989 DumpLog::GetInstance().AddDesc("src:", src_);
1990 DumpLog::GetInstance().AddDesc("isAutoPlay:", isAutoPlay_);
1991 DumpLog::GetInstance().AddDesc("needControls:", needControls_);
1992 DumpLog::GetInstance().AddDesc("isMute:", isMute_);
1993 }
1994
1995 bool VideoElement::OnKeyEvent(const KeyEvent& keyEvent)
1996 {
1997 if (keyEvent.action != KeyAction::UP) {
1998 return false;
1999 }
2000 switch (keyEvent.code) {
2001 case KeyCode::KEY_BACK:
2002 case KeyCode::KEY_ESCAPE: {
2003 if (isFullScreen_) {
2004 ExitFullScreen();
2005 return true;
2006 }
2007 break;
2008 }
2009 case KeyCode::KEY_ENTER: {
2010 if (!isFullScreen_) {
2011 FullScreen();
2012 } else {
2013 OnStartBtnClick();
2014 }
2015 return true;
2016 }
2017 case KeyCode::TV_CONTROL_MEDIA_PLAY: {
2018 OnStartBtnClick();
2019 return true;
2020 }
2021 case KeyCode::TV_CONTROL_LEFT: {
2022 if (isFullScreen_) {
2023 OnKeyLeft();
2024 if (!isPlaying_) {
2025 Start();
2026 }
2027 return true;
2028 }
2029 break;
2030 }
2031 case KeyCode::TV_CONTROL_RIGHT: {
2032 if (isFullScreen_) {
2033 OnKeyRight();
2034 if (!isPlaying_) {
2035 Start();
2036 }
2037 return true;
2038 }
2039 break;
2040 }
2041 default:
2042 break;
2043 }
2044 return false;
2045 }
2046
2047 void VideoElement::OnKeyLeft()
2048 {
2049 SetCurrentTime(currentPos_ > VIDEO_SEEK_STEP ? currentPos_ - VIDEO_SEEK_STEP : 0);
2050 }
2051
2052 void VideoElement::OnKeyRight()
2053 {
2054 if (currentPos_ + VIDEO_SEEK_STEP < duration_) {
2055 SetCurrentTime(currentPos_ + VIDEO_SEEK_STEP);
2056 }
2057 }
2058
2059 void VideoElement::OnTextureRefresh()
2060 {
2061 auto context = context_.Upgrade();
2062 if (context) {
2063 context->MarkForcedRefresh();
2064 }
2065 }
2066 } // namespace OHOS::Ace
2067