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