1 /* 2 * Copyright (c) 2020-2021 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 #ifndef OHOS_ACELITE_VIDEO_COMPONENT_H 16 #define OHOS_ACELITE_VIDEO_COMPONENT_H 17 18 #include "acelite_config.h" 19 #if (FEATURE_COMPONENT_VIDEO == 1) 20 #if (FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC == 1) 21 #include <pthread.h> 22 #include <unistd.h> 23 #endif // FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC 24 #include "component.h" 25 #include "gfx_utils/list.h" 26 #include "panel_view.h" 27 #include "video_state_callback.h" 28 #include "video_view.h" 29 30 namespace OHOS { 31 namespace ACELite { 32 class VideoPlayImageOnClickListener final : public UIView::OnClickListener { 33 public: 34 ACE_DISALLOW_COPY_AND_MOVE(VideoPlayImageOnClickListener); VideoPlayImageOnClickListener(VideoView * aceVideo)35 explicit VideoPlayImageOnClickListener(VideoView *aceVideo) 36 : video_(aceVideo), 37 videoPlayImageClick_(false), 38 videoMutedImageClick_(false) {} ~VideoPlayImageOnClickListener()39 ~VideoPlayImageOnClickListener() {} OnClick(UIView & view,const ClickEvent & event)40 bool OnClick(UIView &view, const ClickEvent &event) override 41 { 42 if (video_ == nullptr) { 43 return false; 44 } 45 UIImageView *image = reinterpret_cast<UIImageView *>(&view); 46 if (image == nullptr) { 47 return false; 48 } 49 PanelView* panelView = const_cast<PanelView *>(video_->GetPanelView()); 50 if (panelView == nullptr) { 51 return false; 52 } 53 UIImageView* playImage = const_cast<UIImageView *>(panelView->GetVideoPlayImage()); 54 if (playImage != nullptr && playImage == image) { 55 if (SetPlayImageInfo(playImage) == false) { 56 HILOG_ERROR(HILOG_MODULE_ACE, "set play image info failed."); 57 return false; 58 } 59 } 60 61 UIImageView* mutedImage = const_cast<UIImageView *>(panelView->GetVideoMutedImage()); 62 if (mutedImage != nullptr && mutedImage == image) { 63 if (SetMutedImageInfo(mutedImage) == false) { 64 HILOG_ERROR(HILOG_MODULE_ACE, "set muted image info failed."); 65 return false; 66 } 67 } 68 video_->PanelRefreshLayout(); 69 return true; 70 } 71 SetPlayImageInfo(UIImageView * playImage)72 bool SetPlayImageInfo(UIImageView* playImage) 73 { 74 if (video_ == nullptr || playImage == nullptr) { 75 return false; 76 } 77 if (videoPlayImageClick_) { 78 if ((video_->Pause()) == 0) { 79 playImage->SetSrc(GetVideoPlayImageOnInfo()); 80 videoPlayImageClick_ = false; 81 return true; 82 } 83 } else { 84 if ((video_->Play()) == 0) { 85 playImage->SetSrc(GetVideoPlayImageOffInfo()); 86 videoPlayImageClick_ = true; 87 return true; 88 } 89 } 90 return false; 91 } 92 SetMutedImageInfo(UIImageView * mutedImage)93 bool SetMutedImageInfo(UIImageView* mutedImage) 94 { 95 if (video_ == nullptr || mutedImage == nullptr) { 96 return false; 97 } 98 if (videoMutedImageClick_) { 99 if (video_->SetVolume(PanelView::DEFAULT_VOLUME_VALUE) == 0) { 100 mutedImage->SetSrc(GetVideoMutedImageOnInfo()); 101 videoMutedImageClick_ = false; 102 return true; 103 } 104 } else { 105 if (video_->SetVolume(0) == 0) { 106 mutedImage->SetSrc(GetVideoMutedImageOffInfo()); 107 video_->setMuted(true); 108 videoMutedImageClick_ = true; 109 return true; 110 } 111 } 112 return false; 113 } 114 setVideoPlayImageClickStatus(bool status)115 bool setVideoPlayImageClickStatus(bool status) 116 { 117 videoPlayImageClick_ = status; 118 return true; 119 } 120 setVideoMutedImageClickStatus(bool status)121 bool setVideoMutedImageClickStatus(bool status) 122 { 123 videoMutedImageClick_ = status; 124 return true; 125 } 126 127 private: 128 VideoView* video_; 129 bool videoPlayImageClick_; 130 bool videoMutedImageClick_; 131 }; 132 133 class VideoSliderEventListener final: public UISlider::UISliderEventListener, public UISlider::OnClickListener { 134 public: 135 ACE_DISALLOW_COPY_AND_MOVE(VideoSliderEventListener); VideoSliderEventListener(VideoView * aceVideo)136 explicit VideoSliderEventListener(VideoView *aceVideo) 137 : video_(aceVideo), playSeekingFunc_(UNDEFINED), progressValue_(0) {} ~VideoSliderEventListener()138 ~VideoSliderEventListener() 139 { 140 ReleaseJerryValue(playSeekingFunc_, VA_ARG_END_FLAG); 141 } 142 OnChange(int32_t progress)143 void OnChange(int32_t progress) override 144 { 145 if (video_ == nullptr) { 146 return; 147 } 148 progressValue_ = progress; 149 Media::Player* videoPlayer = const_cast<Media::Player *>(video_->GetPlayer()); 150 if (videoPlayer != nullptr && videoPlayer->IsPlaying()) { 151 // when slider changing && videoPlayer is playing, notify UpdateProgressHandler stop update 152 video_->UpdatePlayState(VideoPlayState::STATE_STOPPED); 153 } 154 video_->SetCurrentPlayTimeText(progress); 155 video_->PanelRefreshLayout(); 156 // call js registered on seeking function 157 if (!jerry_value_is_function(playSeekingFunc_)) { 158 return; 159 } 160 video_->CallJSFunctionWithOnePara(playSeekingFunc_, progress); 161 } 162 OnClick(UIView & view,const ClickEvent & event)163 bool OnClick(UIView &view, const ClickEvent& event) override 164 { 165 if (SetPlayPositionInfo(progressValue_)) { 166 HILOG_DEBUG(HILOG_MODULE_ACE, "slider onClick video to %{public}d", progressValue_); 167 return true; 168 } 169 return false; 170 } OnRelease(int32_t progress)171 void OnRelease(int32_t progress) override 172 { 173 if (SetPlayPositionInfo(progress)) { 174 HILOG_DEBUG(HILOG_MODULE_ACE, "slider release video to %{public}d", progress); 175 } 176 } 177 SetPlayPositionInfo(int32_t progressValue)178 bool SetPlayPositionInfo(int32_t progressValue) 179 { 180 if (video_ == nullptr) { 181 return false; 182 } 183 int64_t playPosition = progressValue * PanelView::MILLIONS_PER_SECOND; 184 if (video_->SeekTo(playPosition) == 0) { 185 video_->SetCurrentPlayTimeText(progressValue); 186 video_->PanelRefreshLayout(); 187 Media::Player* videoPlayer = const_cast<Media::Player *>(video_->GetPlayer()); 188 if (videoPlayer != nullptr && videoPlayer->IsPlaying()) { 189 // when slider clicked && videoPlayer is playing, notify UpdateProgressHandler start update 190 video_->UpdatePlayState(VideoPlayState::STATE_PLAYING); 191 } 192 } 193 return true; 194 } 195 SetOnPlaySeekingFuncName(jerry_value_t bindFunc)196 void SetOnPlaySeekingFuncName(jerry_value_t bindFunc) 197 { 198 playSeekingFunc_ = jerry_acquire_value(bindFunc); 199 } 200 private: 201 VideoView* video_; 202 jerry_value_t playSeekingFunc_; 203 int32_t progressValue_; 204 }; 205 206 class VideoEventListener final: public OHOS::Media::PlayerCallback { 207 public: 208 ACE_DISALLOW_COPY_AND_MOVE(VideoEventListener); VideoEventListener(VideoView * aceVideo,VideoPlayImageOnClickListener * imageClickListener)209 VideoEventListener(VideoView *aceVideo, VideoPlayImageOnClickListener *imageClickListener) 210 : playErrorFunc_(UNDEFINED), 211 playCompleteFunc_(UNDEFINED), 212 playSeekedFunc_(UNDEFINED), 213 video_(aceVideo), 214 playImageListener_(imageClickListener) {} 215 ~VideoEventListener()216 ~VideoEventListener() 217 { 218 ReleaseJerryValue(playErrorFunc_, playCompleteFunc_, playSeekedFunc_, VA_ARG_END_FLAG); 219 } OnError(int32_t errorType,int32_t errorCode)220 void OnError(int32_t errorType, int32_t errorCode) override 221 { 222 if (video_ == nullptr) { 223 return; 224 } 225 video_->UpdatePlayState(VideoPlayState::STATE_STOPPED); 226 if (jerry_value_is_function(playErrorFunc_)) { 227 CallJSFunctionAutoRelease(playErrorFunc_, UNDEFINED, nullptr, 0); 228 } 229 HILOG_DEBUG(HILOG_MODULE_ACE, "video play errorType = %{public}d, errCode= %{public}d", errorType, errorCode); 230 } 231 OnPlaybackComplete()232 void OnPlaybackComplete() override 233 { 234 if (video_ == nullptr) { 235 return; 236 } 237 video_->UpdatePlayState(VideoPlayState::STATE_STOPPED); 238 video_->PrepareRebuildPlayerThread(); 239 // call js complete function 240 if (jerry_value_is_function(playCompleteFunc_)) { 241 CallJSFunctionAutoRelease(playCompleteFunc_, UNDEFINED, nullptr, 0); 242 } 243 // update play image when video play complete 244 PanelView* panelView = const_cast<PanelView *>(video_->GetPanelView()); 245 if (panelView == nullptr) { 246 return; 247 } 248 UIImageView* playImage = const_cast<UIImageView *>(panelView->GetVideoPlayImage()); 249 if (playImage == nullptr || playImageListener_ == nullptr) { 250 return; 251 } 252 playImage->SetSrc(GetVideoPlayImageOnInfo()); 253 playImageListener_->setVideoPlayImageClickStatus(false); 254 video_->PanelRefreshLayout(); 255 HILOG_DEBUG(HILOG_MODULE_ACE, "video play complete."); 256 } 257 OnInfo(int type,int extra)258 void OnInfo(int type, int extra) override 259 { 260 HILOG_DEBUG(HILOG_MODULE_ACE, "video play on Info. type= %{public}d, extra= %{public}d", type, extra); 261 } 262 OnVideoSizeChanged(int width,int height)263 void OnVideoSizeChanged(int width, int height) override 264 { 265 HILOG_DEBUG(HILOG_MODULE_ACE, "Video Size Changed. width= %{public}d, height= %{public}d", width, height); 266 } 267 OnRewindToComplete()268 void OnRewindToComplete() override 269 { 270 if (video_ == nullptr) { 271 return; 272 } 273 PanelView* panelView = const_cast<PanelView *>(video_->GetPanelView()); 274 if (panelView == nullptr) { 275 return; 276 } 277 const UISlider* slider = panelView->GetVideoSlider(); 278 if (slider == nullptr) { 279 return; 280 } 281 int16_t sliderValue = slider->GetValue(); 282 if (!jerry_value_is_function(playSeekedFunc_)) { 283 return; 284 } 285 video_->CallJSFunctionWithOnePara(playSeekedFunc_, sliderValue); 286 HILOG_DEBUG(HILOG_MODULE_ACE, "video seek to play complete."); 287 } 288 SetOnErrorFuncName(jerry_value_t bindFunc)289 void SetOnErrorFuncName(jerry_value_t bindFunc) 290 { 291 playErrorFunc_ = jerry_acquire_value(bindFunc); 292 } 293 SetOnPlayCompleteFuncName(jerry_value_t bindFunc)294 void SetOnPlayCompleteFuncName(jerry_value_t bindFunc) 295 { 296 playCompleteFunc_ = jerry_acquire_value(bindFunc); 297 } 298 SetOnPlaySeekedFuncName(jerry_value_t bindFunc)299 void SetOnPlaySeekedFuncName(jerry_value_t bindFunc) 300 { 301 playSeekedFunc_ = jerry_acquire_value(bindFunc); 302 } 303 304 private: 305 jerry_value_t playErrorFunc_; 306 jerry_value_t playCompleteFunc_; 307 jerry_value_t playSeekedFunc_; 308 VideoView* video_; 309 VideoPlayImageOnClickListener* playImageListener_; 310 }; 311 312 class VideoComponent : public Component, public VideoStateCallback { 313 public: 314 ACE_DISALLOW_COPY_AND_MOVE(VideoComponent); 315 VideoComponent(jerry_value_t options, jerry_value_t children, AppStyleManager* styleManager); ~VideoComponent()316 ~VideoComponent() override {} 317 void OnPlayStateChanged(VideoPlayState newState) override; 318 319 protected: 320 bool CreateNativeViews() override; 321 void ReleaseNativeViews() override; 322 UIView *GetComponentRootView() const override; 323 bool SetPrivateAttribute(uint16_t attrKeyId, jerry_value_t attrValue) override; 324 bool ApplyPrivateStyle(const AppStyleItem* style) override; 325 void OnViewAttached() override; 326 void PostUpdate(uint16_t attrKeyId) override; 327 bool RegisterPrivateEventListener(uint16_t eventTypeId, jerry_value_t funcValue, bool isStopPropagation) override; 328 329 static List<Component *> componentNodes_; 330 331 private: 332 bool SetPanelView(); 333 void SetMuted(jerry_value_t attrValue); 334 void SetVideoSource(jerry_value_t attrValue); 335 void SetVideoAutoPlay(jerry_value_t attrValue); 336 void SetVideoControls(jerry_value_t attrValue); 337 void RegisterNativeFunctions(); 338 bool RegisterVideoEventListener(); 339 bool PrepareProgressUpdatingThread(); 340 void UpdatePlayImageInfo(bool playFlag); 341 void UpdateProgress(); 342 void SetVideoPlayingFlag(bool playing); 343 void SetComponentReleasingFlag(bool releasing); 344 bool IsComponentReleasing() const; 345 bool IsVideoPlaying() const; 346 void NotifyUpdatingThreadDestroy(); 347 static void AddComponentNode(Component *component); 348 static void RemoveComponentNode(const Component *component); 349 static bool ContainComponentNode(Component *component); 350 static void VideoStateCallback(VideoPlayState state); 351 static void *UpdateProgressHandler(void *arg); 352 353 static JSValue Start(const jerry_value_t func, 354 const jerry_value_t context, 355 const jerry_value_t args[], 356 const jerry_length_t argsNum); 357 static JSValue Pause(const jerry_value_t func, 358 const jerry_value_t context, 359 const jerry_value_t args[], 360 const jerry_length_t argsNum); 361 static JSValue SetCurrentTime(const jerry_value_t func, 362 const jerry_value_t context, 363 const jerry_value_t args[], 364 const jerry_length_t argsNum); 365 366 static JSValue SetVolume(const jerry_value_t func, 367 const jerry_value_t context, 368 const jerry_value_t args[], 369 const jerry_length_t argsNum); 370 371 static const char * const FUNC_START; 372 static const char * const FUNC_PAUSE; 373 static const char * const FUNC_SET_CURRENT_TIME; 374 static const char * const FUNC_SET_Volume; 375 376 char* videoSourceUrl_; 377 VideoView* videoView_; 378 std::shared_ptr<VideoEventListener> videoEventListener_; 379 VideoSliderEventListener* videoSliderListener_; 380 VideoPlayImageOnClickListener* videoPlayImageClickListener_; 381 bool autoPlay_; 382 bool videoMuted_; 383 bool isPlaying_; 384 bool isReleasing_; 385 bool isUpdatingHandlerQuited_; 386 #if (FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC == 1) 387 static pthread_mutex_t updateLock_; 388 static pthread_cond_t updateCondition_; 389 #endif // FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC 390 }; 391 } // namespace ACELite 392 } // namespace OHOS 393 #endif // FEATURE_COMPONENT_VIDEO 394 #endif // OHOS_ACELITE_VIDEO_COMPONENT_H 395