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