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 #include "acelite_config.h"
16 #if (FEATURE_COMPONENT_VIDEO == 1)
17
18 #include "video_view.h"
19 #include "video_state_callback.h"
20
21 namespace OHOS {
22 namespace ACELite {
23 pthread_mutex_t VideoView::rebuildPlayerlock_ = PTHREAD_MUTEX_INITIALIZER;
24 pthread_cond_t VideoView::rebuildPlayerCondition_ = PTHREAD_COND_INITIALIZER;
25
VideoView()26 VideoView::VideoView()
27 : panelView_(nullptr),
28 videoPlayer_(nullptr),
29 surfaceView_(nullptr),
30 playEventListener_(nullptr),
31 playStateCallback_(nullptr),
32 preparedSyncCallBackFunc_(UNDEFINED),
33 startSyncCallBackFunc_(UNDEFINED),
34 pauseSyncCallBackFunc_(UNDEFINED),
35 timeUpdateSyncCallBackFunc_(UNDEFINED),
36 videoSrc_(nullptr),
37 mutedFlag_(false),
38 autoPlayFlag_(false) {}
39
CreateVideoView()40 bool VideoView::CreateVideoView()
41 {
42 videoPlayer_ = new Media::Player();
43 surfaceView_ = new UISurfaceView();
44 panelView_ = new PanelView();
45 if ((videoPlayer_ == nullptr) || (surfaceView_ == nullptr) ||
46 (panelView_ == nullptr) || !(panelView_->InitView())) {
47 return false;
48 }
49 Add(surfaceView_);
50 Add(panelView_);
51 SetLayoutDirection(LAYOUT_VER);
52 SetMajorAxisAlign(OHOS::ALIGN_END);
53 LayoutChildren();
54 return true;
55 }
SetVideoView()56 void VideoView::SetVideoView()
57 {
58 SetSurfaceView();
59 SetVideoPanel();
60 }
61
SetSurfaceView()62 void VideoView::SetSurfaceView()
63 {
64 if (surfaceView_ == nullptr) {
65 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView get surfaceView is nullptr");
66 return;
67 }
68 surfaceView_->SetPosition(0, 0);
69 surfaceView_->SetWidth(GetWidth());
70 surfaceView_->SetHeight(GetHeight() - PanelView::DEFAULT_PANEL_HEIGHT);
71 }
72
PanelRefreshLayout()73 void VideoView::PanelRefreshLayout()
74 {
75 if (panelView_ == nullptr) {
76 return;
77 }
78 panelView_->LayoutChildren();
79 panelView_->Invalidate();
80 LayoutChildren();
81 }
82
~VideoView()83 VideoView::~VideoView()
84 {
85 if (!DestroyPlayer()) {
86 HILOG_ERROR(HILOG_MODULE_ACE, "videoView destroy player failed");
87 }
88 ACE_DELETE(panelView_);
89 ACE_DELETE(surfaceView_);
90 jerry_release_value(preparedSyncCallBackFunc_);
91 jerry_release_value(startSyncCallBackFunc_);
92 jerry_release_value(pauseSyncCallBackFunc_);
93 jerry_release_value(timeUpdateSyncCallBackFunc_);
94 (void)pthread_mutex_destroy(&rebuildPlayerlock_);
95 (void)pthread_cond_destroy(&rebuildPlayerCondition_);
96 }
97
GetVideoPlayer() const98 const Media::Player *VideoView::GetVideoPlayer() const
99 {
100 return videoPlayer_;
101 }
102
103 /* player info */
Prepare()104 int32_t VideoView::Prepare()
105 {
106 if ((videoPlayer_ != nullptr) && (surfaceView_ != nullptr) && (videoPlayer_->Prepare() == 0)) {
107 Surface *surface = surfaceView_->GetSurface();
108 if (surface == nullptr) {
109 HILOG_DEBUG(HILOG_MODULE_ACE, "surfaceView get surface failed");
110 return -1;
111 }
112 videoPlayer_->SetVideoSurface(surface);
113 /* call js prepare sync callback function */
114 if (jerry_value_is_function(preparedSyncCallBackFunc_)) {
115 CallJSFunctionAutoRelease(preparedSyncCallBackFunc_, UNDEFINED, nullptr, 0);
116 }
117 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView prepare");
118 return 0;
119 }
120 return -1;
121 }
122
Play()123 int32_t VideoView::Play()
124 {
125 if ((videoPlayer_ != nullptr) && (videoPlayer_->Play() == 0)) {
126 /* call js start play sync callback function */
127 if (jerry_value_is_function(startSyncCallBackFunc_)) {
128 CallJSFunctionAutoRelease(startSyncCallBackFunc_, UNDEFINED, nullptr, 0);
129 }
130 UpdatePlayState(VideoPlayState::STATE_PLAYING);
131 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView play");
132 return 0;
133 }
134 return -1;
135 }
136
Pause()137 int32_t VideoView::Pause()
138 {
139 if ((videoPlayer_ != nullptr) && (videoPlayer_->Pause() == 0)) {
140 /* call js pause play sync callback function */
141 if (jerry_value_is_function(pauseSyncCallBackFunc_)) {
142 CallJSFunctionAutoRelease(pauseSyncCallBackFunc_, UNDEFINED, nullptr, 0);
143 }
144 UpdatePlayState(VideoPlayState::STATE_PAUSED);
145 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView Pause");
146 return 0;
147 }
148 return -1;
149 }
150
Stop()151 int32_t VideoView::Stop()
152 {
153 if ((videoPlayer_ != nullptr) && (videoPlayer_->Stop() == 0)) {
154 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView Stop");
155 UpdatePlayState(VideoPlayState::STATE_STOPPED);
156 return 0;
157 }
158 return -1;
159 }
160
WaitRebuildPlayerFinish()161 bool VideoView::WaitRebuildPlayerFinish()
162 {
163 int retCode = pthread_mutex_lock(&rebuildPlayerlock_);
164 if (retCode != 0) {
165 HILOG_ERROR(HILOG_MODULE_ACE, "WaitRebuildPlayerFinish mutex lock failed: %{public}d", retCode);
166 return false;
167 }
168 PrepareRebuildPlayerThread();
169 (void)pthread_cond_wait(&rebuildPlayerCondition_, &rebuildPlayerlock_);
170 retCode = pthread_mutex_unlock(&rebuildPlayerlock_);
171 if (retCode != 0) {
172 HILOG_ERROR(HILOG_MODULE_ACE, "WaitRebuildPlayerFinish mutex unlock failed: %{public}d", retCode);
173 return false;
174 }
175 return true;
176 }
177
PrepareRebuildPlayerThread()178 void VideoView::PrepareRebuildPlayerThread()
179 {
180 pthread_t threadId;
181 pthread_attr_t attr;
182 pthread_attr_init(&attr);
183 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
184 int retCode = pthread_create(&threadId, &attr, VideoView::RebuildPlayerHandler, this);
185 if (retCode != 0) {
186 HILOG_ERROR(HILOG_MODULE_ACE, "fork play complete thread failed, %{public}d", retCode);
187 return;
188 }
189 }
190
RebuildPlayerHandler(void * arg)191 void *VideoView::RebuildPlayerHandler(void *arg)
192 {
193 VideoView *videoView = static_cast<VideoView *>(arg);
194 HILOG_DEBUG(HILOG_MODULE_ACE, "rebuild player handler");
195 prctl(PR_SET_NAME, "VideoPlayerRebuildHandler");
196 if (!videoView->ResetPlayer()) {
197 HILOG_ERROR(HILOG_MODULE_ACE, "videoView reset player failed");
198 }
199 return nullptr;
200 }
201
ResetPlayer()202 bool VideoView::ResetPlayer()
203 {
204 (void)pthread_mutex_lock(&rebuildPlayerlock_);
205 if (!DestroyPlayer()) {
206 HILOG_ERROR(HILOG_MODULE_ACE, "videoView destroy player failed");
207 }
208 if (!CreatePlayer()) {
209 HILOG_ERROR(HILOG_MODULE_ACE, "videoView create player failed");
210 }
211 (void)pthread_mutex_unlock(&rebuildPlayerlock_);
212 int retCode = pthread_cond_signal(&rebuildPlayerCondition_);
213 if (retCode != 0) {
214 HILOG_ERROR(HILOG_MODULE_ACE, "mutex unlock failed: %{public}d", retCode);
215 return false;
216 }
217 return true;
218 }
219
DestroyPlayer()220 bool VideoView::DestroyPlayer()
221 {
222 if (videoPlayer_ == nullptr) {
223 return false;
224 }
225 if (videoPlayer_->IsPlaying() && videoPlayer_->Stop() != 0) {
226 HILOG_ERROR(HILOG_MODULE_ACE, "DestroyPlayer fail to stop videoplayer");
227 }
228 if (videoPlayer_->Reset() != 0) {
229 HILOG_ERROR(HILOG_MODULE_ACE, "DestroyPlayer fail to reset videoplayer");
230 }
231 if (videoPlayer_->Release() != 0) {
232 HILOG_ERROR(HILOG_MODULE_ACE, "DestroyPlayer fail to release videoplayer");
233 }
234 delete videoPlayer_;
235 videoPlayer_ = nullptr;
236 HILOG_DEBUG(HILOG_MODULE_ACE, "delete player");
237 return true;
238 }
239
CreatePlayer()240 bool VideoView::CreatePlayer()
241 {
242 videoPlayer_ = new Media::Player();
243 if (videoPlayer_ == nullptr) {
244 HILOG_ERROR(HILOG_MODULE_ACE, "fail to create videoplayer");
245 return false;
246 }
247 videoPlayer_->SetPlayerCallback(playEventListener_);
248 const float volumeValue = mutedFlag_ ? 0 : PanelView::DEFAULT_VOLUME_VALUE;
249 SetVolume(volumeValue);
250 if (SetSource(videoSrc_) != 0) {
251 HILOG_ERROR(HILOG_MODULE_ACE, "video view SetSource failed");
252 return false;
253 }
254 if (Prepare() != 0) {
255 HILOG_ERROR(HILOG_MODULE_ACE, "video view prepare failed");
256 return false;
257 }
258 HILOG_DEBUG(HILOG_MODULE_ACE, "reCreate player success");
259 return true;
260 }
261
UpdatePlayState(VideoPlayState newState)262 void VideoView::UpdatePlayState(VideoPlayState newState)
263 {
264 if (playStateCallback_ != nullptr) {
265 playStateCallback_->OnPlayStateChanged(newState);
266 }
267 }
268
SeekTo(int64_t currentTime)269 int32_t VideoView::SeekTo(int64_t currentTime)
270 {
271 if ((videoPlayer_ != nullptr) &&
272 videoPlayer_->Rewind(currentTime, Media::PlayerSeekMode::PLAYER_SEEK_CLOSEST_SYNC) == 0) {
273 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView SeekTo %{public}lld", currentTime);
274 return 0;
275 }
276 return -1;
277 }
278
SetVolume(float volumeValue)279 int32_t VideoView::SetVolume(float volumeValue)
280 {
281 if ((videoPlayer_ != nullptr) && videoPlayer_->SetVolume(volumeValue, volumeValue) == 0) {
282 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView setVolume %{public}f", volumeValue);
283 return 0;
284 }
285 return -1;
286 }
287
GetCurrentPosition(int64_t & currentPosition)288 int32_t VideoView::GetCurrentPosition(int64_t ¤tPosition)
289 {
290 if ((videoPlayer_ != nullptr) && videoPlayer_->GetCurrentTime(currentPosition) == 0) {
291 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView GetCurrentTime %{public}lld", currentPosition);
292 return 0;
293 }
294 return -1;
295 }
296
297 /* get video total time */
GetDuration(int64_t & duration)298 int32_t VideoView::GetDuration(int64_t &duration)
299 {
300 if ((videoPlayer_ != nullptr) && videoPlayer_->GetDuration(duration) == 0) {
301 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView GetDuration %{public}lld", duration);
302 return 0;
303 }
304 return -1;
305 }
306
SetSource(const char * const videoSourceUrl)307 int32_t VideoView::SetSource(const char * const videoSourceUrl)
308 {
309 if ((videoPlayer_ == nullptr) || (videoSourceUrl == nullptr)) {
310 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView videoSourceUrl is nullptr");
311 return -1;
312 }
313 std::string uri(videoSourceUrl);
314 std::map<std::string, std::string> header;
315 Media::Source source(uri, header);
316 if (videoPlayer_->SetSource(source) == 0) {
317 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView set source success, %{public}s", videoSourceUrl);
318 return 0;
319 }
320 return -1;
321 }
322
323 /* panel info */
HideVideoPanel()324 bool VideoView::HideVideoPanel()
325 {
326 if (panelView_ == nullptr) {
327 return false;
328 }
329 UILabel* curPlayTime = const_cast<UILabel *>(panelView_->GetCurTimeText());
330 if (curPlayTime != nullptr) {
331 curPlayTime->SetVisible(false);
332 }
333 UIImageView* playImage = const_cast<UIImageView *>(panelView_->GetVideoPlayImage());
334 if (playImage != nullptr) {
335 playImage->SetVisible(false);
336 }
337 UISlider* slider = const_cast<UISlider *>(panelView_->GetVideoSlider());
338 if (slider != nullptr) {
339 slider->SetVisible(false);
340 }
341 UILabel* totalTimeLabel = const_cast<UILabel *>(panelView_->GetVideoTotalTimeText());
342 if (totalTimeLabel != nullptr) {
343 totalTimeLabel->SetVisible(false);
344 }
345 UIImageView* mutedImage = const_cast<UIImageView *>(panelView_->GetVideoMutedImage());
346 if (mutedImage != nullptr) {
347 mutedImage->SetVisible(false);
348 }
349
350 panelView_->SetVisible(false);
351 PanelRefreshLayout();
352 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView hide control panel");
353 return true;
354 }
355
SetVideoPanel()356 void VideoView::SetVideoPanel()
357 {
358 if (panelView_ == nullptr) {
359 HILOG_DEBUG(HILOG_MODULE_ACE, "native VideoView get panel view is nullptr");
360 return;
361 }
362 const int16_t panelViewWidth = GetWidth();
363 const int16_t panelViewHeight = PanelView::DEFAULT_PANEL_HEIGHT;
364 const int16_t imageWidth = 48;
365 const int16_t imageHeight = 48;
366 /* set panelView layout children from left to right in one row */
367 (reinterpret_cast<FlexLayout *>(panelView_))->SetLayoutDirection(LAYOUT_HOR);
368 SetMajorAxisAlign(OHOS::ALIGN_CENTER);
369 panelView_->SetWidth(panelViewWidth);
370 panelView_->SetHeight(panelViewHeight);
371 /* set video current play time label in video panel */
372
373 UILabel* curTimeLabel = const_cast<UILabel *>(panelView_->GetCurTimeText());
374 if (curTimeLabel != nullptr) {
375 panelView_->SetTextInPanel(curTimeLabel);
376 }
377 UIImageView* playImage = const_cast<UIImageView *>(panelView_->GetVideoPlayImage());
378 if (playImage != nullptr) {
379 panelView_->SetImageInPanel(playImage, imageWidth, imageHeight, GetVideoPlayImageOnInfo());
380 }
381 /* set video total time label in video panel */
382 UILabel* totalTimeLabel = const_cast<UILabel *>(panelView_->GetVideoTotalTimeText());
383 if (totalTimeLabel != nullptr) {
384 panelView_->SetTextInPanel(totalTimeLabel);
385 }
386 /* set muted image in video panel */
387 UIImageView* mutedImage = const_cast<UIImageView *>(panelView_->GetVideoMutedImage());
388 if (mutedImage != nullptr) {
389 panelView_->SetImageInPanel(mutedImage, imageWidth, imageHeight, GetVideoMutedImageOffInfo());
390 }
391 /* video slider set last in video panel, because slider width depend others */
392 panelView_->SetVideoSlider();
393 }
394
UpdatePanelProgress()395 void VideoView::UpdatePanelProgress()
396 {
397 // update current play position time
398 UpdatePanelTimeText(true);
399 }
400
SetCurrentPlayTimeText(int32_t inSeconds)401 void VideoView::SetCurrentPlayTimeText(int32_t inSeconds)
402 {
403 if (panelView_ == nullptr || inSeconds <= 0 || inSeconds >= (PanelView::MAX_HOURS * PanelView::SECONDS_PER_HOUR)) {
404 HILOG_ERROR(HILOG_MODULE_ACE, "input duration inSeconds time exception");
405 return;
406 }
407 UILabel *curTimeLabel = const_cast<UILabel *>(panelView_->GetCurTimeText());
408 if (curTimeLabel == nullptr) {
409 return;
410 }
411 const uint8_t timeStrLength = 16;
412 char timeStr[timeStrLength] = {0};
413 FormatTime(inSeconds, timeStr, timeStrLength);
414 curTimeLabel->SetText(timeStr);
415 curTimeLabel->Invalidate();
416 }
417
UpdatePanelTimeText(bool currentTime)418 void VideoView::UpdatePanelTimeText(bool currentTime)
419 {
420 if (panelView_ == nullptr) {
421 return;
422 }
423 UILabel *timeLabel = currentTime ?
424 const_cast<UILabel *>(panelView_->GetCurTimeText()) :
425 const_cast<UILabel *>(panelView_->GetVideoTotalTimeText());
426 if (timeLabel == nullptr) {
427 return;
428 }
429
430 int64_t duration = 0;
431 if (currentTime) {
432 if (GetCurrentPosition(duration) != 0) {
433 HILOG_ERROR(HILOG_MODULE_ACE, "UpdatePanelTimeText GetCurrentPosition failed");
434 return;
435 }
436 } else {
437 if (GetDuration(duration) != 0) {
438 HILOG_ERROR(HILOG_MODULE_ACE, "UpdatePanelTimeText GetDuration failed");
439 return;
440 }
441 }
442 if (duration < 0 || duration >= PanelView::MAX_SHOW_TIME) {
443 HILOG_ERROR(HILOG_MODULE_ACE, "input duration exception");
444 duration = 0;
445 }
446 const uint8_t timeStrLength = 16;
447 char timeStr[timeStrLength] = {0};
448 FormatTime((duration / PanelView::MILLIONS_PER_SECOND), timeStr, timeStrLength);
449 HILOG_DEBUG(HILOG_MODULE_ACE, "--- set time =%{public}s -----", timeStr);
450 timeLabel->SetText(timeStr);
451 timeLabel->Invalidate();
452 PanelRefreshLayout();
453 // update video slider status when play changed
454 UISlider* videoSlider = const_cast<UISlider *>(panelView_->GetVideoSlider());
455 if (videoSlider != nullptr && currentTime) {
456 videoSlider->SetValue(duration / PanelView::MILLIONS_PER_SECOND);
457 videoSlider->Invalidate();
458 // call js timeupdate callback function
459 if (!jerry_value_is_function(timeUpdateSyncCallBackFunc_)) {
460 return;
461 }
462 CallJSFunctionWithOnePara(timeUpdateSyncCallBackFunc_, duration / PanelView::MILLIONS_PER_SECOND);
463 }
464 }
465
UpdateMutedStatus()466 void VideoView::UpdateMutedStatus()
467 {
468 if (panelView_ == nullptr) {
469 HILOG_ERROR(HILOG_MODULE_ACE, "video view get mpanelView_ is nullptr");
470 return;
471 }
472 UIImageView *mutedImageView = const_cast<UIImageView *>(panelView_->GetVideoMutedImage());
473 if (mutedImageView == nullptr) {
474 HILOG_ERROR(HILOG_MODULE_ACE, "video view get muted image view is nullptr");
475 return;
476 }
477 float volumeValue = mutedFlag_ ? 0 : PanelView::DEFAULT_VOLUME_VALUE;
478 const ImageInfo* mutedImageSrc = mutedFlag_ ? GetVideoMutedImageOffInfo() : GetVideoMutedImageOnInfo();
479 if (SetVolume(volumeValue) != 0) {
480 HILOG_ERROR(HILOG_MODULE_ACE, "video set volume failed");
481 return;
482 }
483 mutedImageView->SetSrc(mutedImageSrc);
484 }
485
FormatTime(uint32_t inSeconds,char * outBuffer,uint8_t bufferLength)486 void VideoView::FormatTime(uint32_t inSeconds, char *outBuffer, uint8_t bufferLength)
487 {
488 if (inSeconds >= (PanelView::MAX_HOURS * PanelView::SECONDS_PER_HOUR)) {
489 HILOG_ERROR(HILOG_MODULE_ACE, "input duration time exception");
490 return;
491 }
492 const uint8_t minBufferLength = 6; // xx:xx
493 const uint8_t minBufferLength2 = 9; // xx:xx:xx
494 if (outBuffer == nullptr) {
495 return;
496 }
497 uint8_t hours = inSeconds / PanelView::SECONDS_PER_HOUR;
498 uint32_t remainSeconds = inSeconds % PanelView::SECONDS_PER_HOUR;
499 uint8_t minutes = remainSeconds / PanelView::SECONDS_PER_MINUTE;
500 uint8_t seconds = remainSeconds % PanelView::SECONDS_PER_MINUTE;
501 if (hours >= PanelView::MAX_HOURS) {
502 HILOG_ERROR(HILOG_MODULE_ACE, "input video length more than the max length");
503 return;
504 }
505 if (hours == 0) {
506 if (sprintf_s(outBuffer, bufferLength, "%02d:%02d", minutes, seconds) < 0) {
507 HILOG_ERROR(HILOG_MODULE_ACE, "xx:xx transfer error");
508 return;
509 }
510 outBuffer[minBufferLength - 1] = '\0';
511 } else {
512 if (sprintf_s(outBuffer, bufferLength, "%02d:%02d:%02d", hours, minutes, seconds) < 0) {
513 HILOG_ERROR(HILOG_MODULE_ACE, "xx:xx:xx transfer error");
514 return;
515 }
516 outBuffer[minBufferLength2 - 1] = '\0';
517 }
518 }
519
CallJSFunctionWithOnePara(const jerry_value_t & callBackFunc,const int64_t inputValue)520 void VideoView::CallJSFunctionWithOnePara(const jerry_value_t &callBackFunc, const int64_t inputValue)
521 {
522 if (!jerry_value_is_function(callBackFunc)) {
523 return;
524 }
525 jerry_value_t value = jerry_create_number(inputValue);
526 jerry_value_t args[1];
527 args[0] = jerry_create_object();
528 jerry_value_t result = jerryx_set_property_str(args[0], "currenttime", value);
529 if (!jerry_value_is_error(result)) {
530 CallJSFunctionAutoRelease(callBackFunc, jerry_create_undefined(), args, 1);
531 }
532 ReleaseJerryValue(result, args[0], value, VA_ARG_END_FLAG);
533 }
534 } // namespace ACELite
535 } // namespace OHOS
536
537 #endif // FEATURE_COMPONENT_VIDEO
538