1 // Copyright 2023 Samsung Electronics Inc. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/media_player_bridge_capi.h"
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "build/tizen_version.h"
10 #include "media/base/buffering_state.h"
11 #include "media/base/efl/media_player_util_efl.h"
12 #include "third_party/libyuv/include/libyuv/planar_functions.h"
13 #include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h"
14 #include "ui/gfx/geometry/size.h"
16 #if defined(TIZEN_VIDEO_HOLE)
17 #include <Ecore_Wl2.h>
18 #include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller_capi.h"
19 #if BUILDFLAG(IS_TIZEN_TV)
20 #include <player_product_platform_interface.h>
25 // Update duration every 100ms.
26 const int kDurationUpdateInterval = 100;
28 // TODO(max): Remove these proxy free functions.
30 // Called by player_prepare_async()
31 // It's guaranteed that no callback after player destructed.
32 static void PlayerPreparedCb(void* data) {
34 media::MediaPlayerBridgeCapi* player =
35 static_cast<media::MediaPlayerBridgeCapi*>(data);
37 player->OnPlayerPrepared();
40 static void MediaPacketDecodedCb(media_packet_h packet, void* data) {
43 LOG(ERROR) << "media_packet handle is null";
46 media::MediaPlayerBridgeCapi* player =
47 static_cast<media::MediaPlayerBridgeCapi*>(data);
49 player->OnMediaPacketUpdated(packet);
52 // Called by player_set_completed_cb()
53 static void PlaybackCompleteCb(void* data) {
55 media::MediaPlayerBridgeCapi* player =
56 static_cast<media::MediaPlayerBridgeCapi*>(data);
58 player->OnPlaybackCompleteUpdate();
61 // Called by player_set_play_position() / player_set_position()
62 static void SeekCompletedCb(void* data) {
64 media::MediaPlayerBridgeCapi* player =
65 static_cast<media::MediaPlayerBridgeCapi*>(data);
67 player->OnSeekCompleteUpdate();
70 // Called by player_set_buffering_cb()
71 static void ChangedBufferingStatusCb(int percent, void* data) {
73 media::MediaPlayerBridgeCapi* player =
74 static_cast<media::MediaPlayerBridgeCapi*>(data);
76 player->OnHandleBufferingStatus(percent);
79 // Called by player_set_error_cb()
80 static void ErrorCb(int error_code, void* data) {
82 media::MediaPlayerBridgeCapi* player =
83 static_cast<media::MediaPlayerBridgeCapi*>(data);
85 player->OnHandlePlayerError(error_code, FROM_HERE);
88 // Called by player_set_interrupted_cb()
89 static void InterruptCb(player_interrupted_code_e code, void* data) {
91 media::MediaPlayerBridgeCapi* player =
92 static_cast<media::MediaPlayerBridgeCapi*>(data);
94 player->OnResourceConflict();
101 MediaPlayerBridgeCapi::MediaPlayerBridgeCapi(const GURL& url,
102 const std::string& user_agent,
104 : task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
105 delayed_player_state_(PLAYER_STATE_DELAYED_NULL),
108 user_agent_(user_agent),
109 weak_factory_(this) {
110 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
113 MediaPlayerBridgeCapi::~MediaPlayerBridgeCapi() {
114 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
117 weak_factory_.InvalidateWeakPtrs();
118 player_destroy(player_);
121 bool MediaPlayerBridgeCapi::IsInitialized() {
122 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
123 << " ; state : " << GetPlayerState();
124 // create_player is called before Initialized
125 // after create_player state change to PLAYER_STATE_IDLE
126 return (GetPlayerState() > PLAYER_STATE_IDLE);
129 bool MediaPlayerBridgeCapi::IsPrepared() {
130 return (GetPlayerState() >= PLAYER_STATE_READY);
133 bool MediaPlayerBridgeCapi::CanPrepare() {
134 return !IsPrepared() && !is_preparing_;
137 void MediaPlayerBridgeCapi::Flush(base::OnceClosure flush_cb) {
139 std::move(flush_cb).Run();
142 void MediaPlayerBridgeCapi::SetTaskRunner(
143 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
144 task_runner_ = task_runner.get();
147 bool MediaPlayerBridgeCapi::CreatePlayer(int player_id) {
148 player_id_ = player_id;
150 // Player is created, state change to PLAYER_STATE_IDLE
151 int ret = player_create(&player_);
152 if (ret != PLAYER_ERROR_NONE) {
153 OnHandlePlayerError(ret, FROM_HERE);
159 void MediaPlayerBridgeCapi::Prepare() {
160 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
161 << " ; player: " << player_ << " ; url: " << url_.spec().c_str();
162 int ret = PLAYER_ERROR_NONE;
163 if (url_.SchemeIsFile())
166 player_set_uri(player_, url_.spec().c_str());
167 #if !defined(EWK_BRINGUP)
168 player_set_sound_type(player_, SOUND_TYPE_MEDIA);
170 player_set_volume(player_, static_cast<float>(volume_),
171 static_cast<float>(volume_));
172 if (player_set_streaming_user_agent(player_, user_agent_.c_str(),
173 user_agent_.length()) !=
175 LOG(ERROR) << "Unable to set streaming user agent.";
177 #if defined(TIZEN_VIDEO_HOLE)
178 if (is_video_hole_) {
179 if (video_plane_controller_->rendering_mode() ==
180 VideoPlaneController::RenderingMode::OFFSCREEN) {
181 ret = player_set_display(player_, PLAYER_DISPLAY_TYPE_OVERLAY,
182 video_plane_controller_->GetVideoPlaneHandle());
184 Ecore_Wl2_Window* window_handle = static_cast<Ecore_Wl2_Window*>(
185 video_plane_controller_->GetVideoPlaneHandle());
186 int wl_w, wl_h, wl_x, wl_y;
187 ecore_wl2_window_geometry_get(window_handle, &wl_x, &wl_y, &wl_w, &wl_h);
188 #if BUILDFLAG(IS_TIZEN_TV)
189 unsigned int resource_id =
190 ecore_wl2_window_resource_id_get(window_handle);
191 ret = player_set_display_webapp(player_, PLAYER_DISPLAY_TYPE_OVERLAY,
192 resource_id, wl_h, wl_w, wl_x, wl_y);
194 ret = player_set_ecore_wl_display(player_, PLAYER_DISPLAY_TYPE_OVERLAY,
195 window_handle, wl_x, wl_y, wl_w, wl_h);
199 if (ret != PLAYER_ERROR_NONE) {
200 OnHandlePlayerError(ret, FROM_HERE);
206 ret = player_set_media_packet_video_frame_decoded_cb(
207 player_, MediaPacketDecodedCb, this);
208 if (ret != PLAYER_ERROR_NONE) {
209 OnHandlePlayerError(ret, FROM_HERE);
214 if (!PreloadIfNeeded(ret))
215 SetPlayerPrepareAsync();
217 is_preparing_ = true;
218 OnReadyStateChange(player_id_, blink::WebMediaPlayer::kReadyStateHaveNothing);
219 OnNetworkStateChange(player_id_, blink::WebMediaPlayer::kNetworkStateLoading);
222 bool MediaPlayerBridgeCapi::SetPlayerPrepareAsync() {
223 int ret = player_prepare_async(player_, PlayerPreparedCb, this);
224 if (ret != PLAYER_ERROR_NONE) {
225 OnHandlePlayerError(ret, FROM_HERE);
232 void MediaPlayerBridgeCapi::OnMediaError(MediaError error_type) {
233 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
234 << " error_type : " << error_type;
235 StopBufferingUpdateTimer();
236 StopCurrentTimeUpdateTimer();
238 blink::WebMediaPlayer::NetworkState state =
239 blink::WebMediaPlayer::kNetworkStateEmpty;
241 switch (error_type) {
242 case MEDIA_ERROR_FORMAT:
243 state = blink::WebMediaPlayer::kNetworkStateFormatError;
245 case MEDIA_ERROR_DECODE:
246 state = blink::WebMediaPlayer::kNetworkStateDecodeError;
248 case MEDIA_ERROR_NETWORK:
249 state = blink::WebMediaPlayer::kNetworkStateNetworkError;
253 OnNetworkStateChange(player_id_, state);
254 ReleaseDisplayLock();
257 void MediaPlayerBridgeCapi::Initialize(VideoRendererSink* sink) {
258 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
260 // register capi-player callback
261 player_set_completed_cb(player_, PlaybackCompleteCb, this);
262 player_set_buffering_cb(player_, ChangedBufferingStatusCb, this);
263 player_set_interrupted_cb(player_, InterruptCb, this);
264 player_set_error_cb(player_, ErrorCb, this);
266 #if defined(TIZEN_VIDEO_HOLE)
267 if (is_video_hole_) {
268 if (!video_plane_controller_)
271 int ret = video_plane_controller_->Initialize();
272 if (ret != PLAYER_ERROR_NONE) {
273 OnHandlePlayerError(ret, FROM_HERE);
280 void MediaPlayerBridgeCapi::Resume() {
281 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
286 void MediaPlayerBridgeCapi::Suspend() {
287 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
288 if (IsPlayerSuspended()) {
289 LOG(INFO) << "Player already suspended. Nothing to do. Returning";
295 is_play_pending_ = false;
296 seek_duration_ = base::TimeDelta();
298 playback_time_ = GetCurrentTime();
302 // Rare scenario: Player's resource are released while prerolling.
303 // In this case we need to inform HTMLMediaElement that we can play,
304 // otherwise we will never be able to play such video.
305 if (GetPlayerState() == PLAYER_STATE_NONE) {
306 OnReadyStateChange(player_id_,
307 blink::WebMediaPlayer::kReadyStateHaveEnoughData);
308 OnNetworkStateChange(player_id_,
309 blink::WebMediaPlayer::kNetworkStateLoaded);
312 // manager()->OnPauseStateChange(player_id_, true);
315 void MediaPlayerBridgeCapi::Release() {
316 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
317 is_preparing_ = false;
318 StopCurrentTimeUpdateTimer();
319 StopBufferingUpdateTimer();
320 player_unset_completed_cb(player_);
321 player_unset_interrupted_cb(player_);
322 player_unset_error_cb(player_);
323 player_unset_buffering_cb(player_);
325 if (GetPlayerState() > PLAYER_STATE_READY &&
326 player_stop(player_) != PLAYER_ERROR_NONE) {
327 LOG(ERROR) << "|player_stop| failed";
330 #if defined(TIZEN_VIDEO_HOLE)
333 player_unset_media_packet_video_frame_decoded_cb(player_);
335 if (GetPlayerState() >= PLAYER_STATE_IDLE &&
336 player_unprepare(player_) != PLAYER_ERROR_NONE)
337 LOG(ERROR) << "|player_unprepare| failed";
339 // manager()->OnSuspendComplete(player_id_);
342 bool MediaPlayerBridgeCapi::Play() {
343 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
345 if (IsPlayerSuspended()) {
346 is_play_pending_ = true;
347 delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
348 if (playback_time_ != base::Milliseconds(0)) {
349 delayed_player_state_ = PLAYER_STATE_DELAYED_SEEK;
350 pending_seek_duration_ = playback_time_;
357 delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
361 if (GetPlayerState() < PLAYER_STATE_READY || !player_prepared_) {
362 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
363 << " Player is not ready.";
364 delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
368 if (playback_rate_ == 0.0) {
373 if (is_set_playback_rate_delayed_) {
374 is_set_playback_rate_delayed_ = false;
375 SetRate(playback_rate_);
378 if (player_start(player_) != PLAYER_ERROR_NONE) {
379 LOG(ERROR) << "|player_start| failed";
383 #if defined(TIZEN_VIDEO_HOLE)
384 if (!delayed_rect_.IsEmpty() && !delayed_viewport_rect_.IsEmpty()) {
385 SetMediaGeometry(delayed_viewport_rect_, delayed_rect_);
386 delayed_viewport_rect_ = gfx::Rect();
387 delayed_rect_ = gfx::RectF();
391 WakeUpDisplayAndAcquireDisplayLock();
393 StartCurrentTimeUpdateTimer();
395 StartBufferingUpdateTimer();
397 is_end_reached_ = false;
402 void MediaPlayerBridgeCapi::Pause(bool /* is_media_related_action */) {
403 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
405 if (GetPlayerState() != PLAYER_STATE_PLAYING) {
406 LOG(ERROR) << "Player is not in playing state, no need to pause.";
411 delayed_player_state_ = PLAYER_STATE_DELAYED_PAUSE;
415 if (player_pause(player_) != PLAYER_ERROR_NONE) {
416 LOG(ERROR) << "|player_pause| failed";
421 StartBufferingUpdateTimer();
423 ReleaseDisplayLock();
424 StopCurrentTimeUpdateTimer();
428 void MediaPlayerBridgeCapi::SetRate(double rate) {
429 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
430 << " rate: " << rate;
432 if (playback_rate_ == rate)
435 if (GetPlayerState() < PLAYER_STATE_READY) {
436 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
437 << " ; Player is not ready.";
438 playback_rate_ = rate;
439 is_set_playback_rate_delayed_ = true;
444 playback_rate_ = rate;
450 player_set_streaming_playback_rate(player_, static_cast<float>(rate)) !=
452 LOG(ERROR) << "|player_set_streaming_playback_rate| failed";
454 } else if (player_set_playback_rate(player_, static_cast<float>(rate)) !=
456 LOG(ERROR) << "|player_set_playback_rate| failed";
460 // If previous rate was zero and requested rate is non-zero, change the
461 // playback rate and call play.
462 if (playback_rate_ == 0.0) {
463 playback_rate_ = rate;
466 playback_rate_ = rate;
470 void MediaPlayerBridgeCapi::Seek(base::TimeDelta time,
471 base::OnceClosure seek_cb) {
472 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
473 << " time: " << time.InSecondsF();
475 seek_cb_ = std::move(seek_cb);
476 if (IsPlayerSuspended() && playback_time_ != time) {
477 playback_time_ = time;
478 delayed_player_state_ = PLAYER_STATE_DELAYED_SEEK;
479 pending_seek_duration_ = playback_time_;
480 OnTimeUpdate(player_id_, playback_time_);
481 OnTimeChanged(player_id_);
489 void MediaPlayerBridgeCapi::SeekInternal(base::TimeDelta time) {
490 int err = player_set_play_position(
491 player_, ConvertSecondsToMilliSeconds(time.InSecondsF()), true,
492 SeekCompletedCb, this);
493 if (err != PLAYER_ERROR_NONE) {
494 LOG(ERROR) << "|player_set_play_position| failed";
495 OnTimeUpdate(player_id_, GetCurrentTime());
496 OnTimeChanged(player_id_);
498 std::move(seek_cb_).Run();
503 StopCurrentTimeUpdateTimer();
505 StopBufferingUpdateTimer();
506 UpdateSeekState(true);
507 seek_duration_ = time;
508 is_end_reached_ = time != duration_ ? false : true;
509 OnTimeUpdate(player_id_, time);
512 StartCurrentTimeUpdateTimer();
515 void MediaPlayerBridgeCapi::SetVolume(double volume) {
516 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
517 << " volume: " << volume;
519 LOG(ERROR) << "Player is not ready.";
523 if (player_set_volume(player_, volume, volume) != PLAYER_ERROR_NONE)
524 LOG(ERROR) << "|player_set_volume| failed";
529 #if defined(TIZEN_VIDEO_HOLE)
530 void MediaPlayerBridgeCapi::SetVideoHole(bool is_video_hole) {
531 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
532 << " is_video_hole : " << is_video_hole;
533 is_video_hole_ = is_video_hole;
534 if (is_video_hole_ && player_ && !video_plane_controller_) {
535 video_plane_controller_.reset(new VideoPlaneControllerCapi(player_));
539 void MediaPlayerBridgeCapi::SetMediaGeometry(const gfx::Rect& viewport_rect,
540 const gfx::RectF& rect) {
541 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
545 if (GetPlayerState() < PLAYER_STATE_PLAYING) {
546 delayed_viewport_rect_ = viewport_rect;
547 delayed_rect_ = rect;
551 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
552 << " viewport_rect: " << viewport_rect.ToString()
553 << " rect : " << rect.ToString();
554 video_plane_controller_->SetMediaGeometry(viewport_rect, rect);
558 void MediaPlayerBridgeCapi::RequestSuspend(bool resource_conflicted) {
559 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
560 GetMediaPlayerClient()->OnRequestSuspend(resource_conflicted);
564 void MediaPlayerBridgeCapi::UpdateMediaType() {
565 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
568 int audio_bit_rate = 0;
569 media_type_ = MediaType::Invalid;
571 int err = player_get_audio_stream_info(player_, &sample_rate, &channel,
573 if (err != PLAYER_ERROR_NONE) {
574 OnHandlePlayerError(err, FROM_HERE);
578 // Audio stream is present if sample rate is valid.
580 media_type_ |= MediaType::Audio;
582 // Video stream is present if both video width and height are valid.
583 if (width_ > 0 && height_ > 0)
584 media_type_ |= MediaType::Video;
586 OnMediaDataChange(player_id_, width_, height_, media_type_);
589 void MediaPlayerBridgeCapi::UpdateDuration() {
591 int ret = player_get_duration(player_, &duration);
592 if (ret != PLAYER_ERROR_NONE) {
593 OnHandlePlayerError(ret, FROM_HERE);
597 if (duration_.InSecondsF() != ConvertMilliSecondsToSeconds(duration)) {
598 duration_ = base::Milliseconds(duration);
599 OnDurationChange(player_id_, duration_.InSecondsF());
602 // No need to buffer 'local file'. Update buffered percentage.
604 std::vector<TimeRanges> buffer_range;
607 range.end = duration_.InSecondsF() * base::Time::kMicrosecondsPerSecond;
608 buffer_range.push_back(range);
609 OnBufferUpdate(player_id_, buffer_range);
613 base::TimeDelta MediaPlayerBridgeCapi::GetCurrentTime() {
614 // If we're seeking or have a stashed pending seek, let's return the seek
615 // time, because the underlying player calls might return pre-seek values.
616 if (delayed_player_state_ == PLAYER_STATE_DELAYED_SEEK) {
617 return pending_seek_duration_;
621 return seek_duration_;
624 // For http://instagram.com/p/tMQOo0lWqm/
625 // After playback completed current-time and duration are not equal.
626 if (is_end_reached_) {
627 if (playback_rate_ < 0)
628 return base::TimeDelta();
629 if (!is_live_stream_ && duration_.InSecondsF())
634 player_get_play_position(player_, &postion);
635 return base::Milliseconds(postion);
638 void MediaPlayerBridgeCapi::OnCurrentTimeUpdateTimerFired() {
639 OnTimeUpdate(player_id_, GetCurrentTime());
643 void MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer() {
644 if (!current_time_update_timer_.IsRunning()) {
645 current_time_update_timer_.Start(
646 FROM_HERE, base::Milliseconds(kDurationUpdateInterval), this,
647 &MediaPlayerBridgeCapi::OnCurrentTimeUpdateTimerFired);
651 void MediaPlayerBridgeCapi::StopCurrentTimeUpdateTimer() {
652 if (current_time_update_timer_.IsRunning())
653 current_time_update_timer_.Stop();
656 void MediaPlayerBridgeCapi::OnBufferingUpdateTimerFired() {
657 /* player_get_streaming_download_progress is not apply for live stream
658 here no need triggered*/
662 int start = 0, current = 0;
663 if (player_get_streaming_download_progress(player_, &start, ¤t) ==
665 if (current == 100) {
666 StopBufferingUpdateTimer();
667 OnNetworkStateChange(player_id_,
668 blink::WebMediaPlayer::kNetworkStateLoaded);
670 std::vector<TimeRanges> buffer_range;
674 // Get current% of |duration_| and convert into microseconds
675 range.end = ((duration_.InSecondsF() * current) / 100) *
676 base::Time::kMicrosecondsPerSecond;
677 buffer_range.push_back(range);
678 OnBufferUpdate(player_id_, buffer_range);
682 void MediaPlayerBridgeCapi::StartBufferingUpdateTimer() {
683 if (!buffering_update_timer_.IsRunning()) {
684 buffering_update_timer_.Start(
685 FROM_HERE, base::Milliseconds(kDurationUpdateInterval), this,
686 &MediaPlayerBridgeCapi::OnBufferingUpdateTimerFired);
690 void MediaPlayerBridgeCapi::StopBufferingUpdateTimer() {
691 if (buffering_update_timer_.IsRunning())
692 buffering_update_timer_.Stop();
695 void MediaPlayerBridgeCapi::OnTimeChanged() {
696 DCHECK(task_runner_->BelongsToCurrentThread());
697 OnTimeChanged(player_id_);
700 void MediaPlayerBridgeCapi::PlaybackCompleteUpdate() {
701 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
702 is_end_reached_ = true;
703 ReleaseDisplayLock();
705 StopCurrentTimeUpdateTimer();
706 OnTimeUpdate(player_id_, GetCurrentTime());
707 OnTimeChanged(player_id_);
708 GetMediaPlayerClient()->OnEnded();
711 void MediaPlayerBridgeCapi::SeekCompleteUpdate() {
712 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
713 UpdateSeekState(false);
714 OnTimeChanged(player_id_);
717 StartBufferingUpdateTimer();
719 if (is_play_pending_) {
720 is_play_pending_ = false;
721 delayed_player_state_ =
722 is_end_reached_ ? PLAYER_STATE_DELAYED_NULL : PLAYER_STATE_DELAYED_PLAY;
726 std::move(seek_cb_).Run();
727 ExecuteDelayedPlayerState();
730 void MediaPlayerBridgeCapi::UpdateSeekState(bool state) {
734 void MediaPlayerBridgeCapi::PlayerPrepared() {
735 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
736 if (GetPlayerState() < PLAYER_STATE_READY) {
740 player_prepared_ = true;
741 is_preparing_ = false;
743 #if defined(TIZEN_VIDEO_HOLE)
745 video_plane_controller_->ApplyDeferredVideoRectIfNeeded();
749 if (media_type_ == 0) {
753 OnReadyStateChange(player_id_,
754 blink::WebMediaPlayer::kReadyStateHaveEnoughData);
755 OnNetworkStateChange(player_id_, blink::WebMediaPlayer::kNetworkStateLoaded);
756 ExecuteDelayedPlayerState();
759 void MediaPlayerBridgeCapi::HandleBufferingStatus(int percent) {
760 if (is_paused_ || is_seeking_)
763 if (percent == 100) {
764 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
765 if (GetPlayerState() != PLAYER_STATE_PAUSED)
767 if (player_start(player_) != PLAYER_ERROR_NONE) {
768 LOG(ERROR) << "|player_start| failed";
771 StartCurrentTimeUpdateTimer();
774 StartBufferingUpdateTimer();
776 OnReadyStateChange(player_id_,
777 blink::WebMediaPlayer::kReadyStateHaveEnoughData);
779 if (GetPlayerState() != PLAYER_STATE_PLAYING)
781 if (player_pause(player_) != PLAYER_ERROR_NONE) {
782 LOG(ERROR) << "|player_pause| failed";
786 StopCurrentTimeUpdateTimer();
787 OnReadyStateChange(player_id_,
788 blink::WebMediaPlayer::kReadyStateHaveCurrentData);
790 OnNetworkStateChange(player_id_, blink::WebMediaPlayer::kNetworkStateLoading);
793 player_state_e MediaPlayerBridgeCapi::GetPlayerState() {
794 player_state_e state = PLAYER_STATE_NONE;
795 player_get_state(player_, &state);
796 LOG(INFO) << __func__ << " ; state: " << state;
800 void MediaPlayerBridgeCapi::ExecuteDelayedPlayerState() {
801 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
802 switch (delayed_player_state_) {
803 case PLAYER_STATE_DELAYED_PLAY:
804 delayed_player_state_ = PLAYER_STATE_DELAYED_NULL;
807 case PLAYER_STATE_DELAYED_PAUSE:
808 delayed_player_state_ = PLAYER_STATE_DELAYED_NULL;
811 case PLAYER_STATE_DELAYED_SEEK:
813 << "(" << static_cast<void*>(this) << ") " << __func__
814 << " applying pending seek - " << pending_seek_duration_.InSecondsF();
815 delayed_player_state_ = PLAYER_STATE_DELAYED_NULL;
816 SeekInternal(pending_seek_duration_);
823 void MediaPlayerBridgeCapi::OnMediaPacketUpdated(media_packet_h packet) {
824 ScopedMediaPacket packet_proxy(packet);
825 task_runner_->PostTask(
827 base::BindOnce(&MediaPlayerBridgeCapi::DeliverMediaPacket,
828 weak_factory_.GetWeakPtr(), std::move(packet_proxy)));
831 void MediaPlayerBridgeCapi::OnPlaybackCompleteUpdate() {
832 task_runner_->PostTask(
833 FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapi::PlaybackCompleteUpdate,
834 weak_factory_.GetWeakPtr()));
837 void MediaPlayerBridgeCapi::OnSeekCompleteUpdate() {
838 task_runner_->PostTask(
839 FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapi::SeekCompleteUpdate,
840 weak_factory_.GetWeakPtr()));
843 void MediaPlayerBridgeCapi::OnPlayerPrepared() {
844 task_runner_->PostTask(FROM_HERE,
845 base::BindOnce(&MediaPlayerBridgeCapi::PlayerPrepared,
846 weak_factory_.GetWeakPtr()));
849 void MediaPlayerBridgeCapi::OnHandleBufferingStatus(int percent) {
850 task_runner_->PostTask(
851 FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapi::HandleBufferingStatus,
852 weak_factory_.GetWeakPtr(), percent));
855 void MediaPlayerBridgeCapi::OnHandlePlayerError(
856 int player_error_code,
857 const base::Location& location) {
858 LOG(ERROR) << GetErrorString(player_error_code) << " from "
859 << location.ToString();
861 OnMediaError(GetMediaError(player_error_code));
864 void MediaPlayerBridgeCapi::OnResourceConflict() {
865 if (!task_runner_->BelongsToCurrentThread()) {
866 task_runner_->PostTask(
867 FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapi::OnResourceConflict,
868 weak_factory_.GetWeakPtr()));
871 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
872 RequestSuspend(true);
875 void MediaPlayerBridgeCapi::OnResumeComplete(bool success) {
879 void MediaPlayerBridgeCapi::OnReadyStateChange(
881 blink::WebMediaPlayer::ReadyState state) {
882 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
883 << " ; ready_state : " << state;
884 media::BufferingState buffer_state = media::BUFFERING_HAVE_NOTHING;
885 media::BufferingStateChangeReason reason =
886 media::BUFFERING_CHANGE_REASON_UNKNOWN;
888 case blink::WebMediaPlayer::kReadyStateHaveEnoughData:
889 case blink::WebMediaPlayer::kReadyStateHaveCurrentData:
890 buffer_state = media::BUFFERING_HAVE_ENOUGH;
891 reason = media::BUFFERING_CHANGE_REASON_UNKNOWN;
893 case blink::WebMediaPlayer::kReadyStateHaveNothing:
894 // buffer_state = media::BUFFERING_HAVE_NOTHING;
895 // reason = media::DEMUXER_UNDERFLOW;
900 GetMediaPlayerClient()->OnBufferingStateChange(buffer_state, reason);
903 void MediaPlayerBridgeCapi::OnNetworkStateChange(
905 blink::WebMediaPlayer::NetworkState state) {}
907 void MediaPlayerBridgeCapi::OnMediaDataChange(int player_id,
911 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
912 << " width : " << width << " ; height : " << height;
915 GetMediaPlayerClient()->OnVideoNaturalSizeChange(gfx::Size(width, height));
918 void MediaPlayerBridgeCapi::OnTimeChanged(int player_id) {}
920 void MediaPlayerBridgeCapi::OnTimeUpdate(int player_id,
921 base::TimeDelta current_time) {
922 // Move to OnSeekStateChange?
923 GetMediaPlayerClient()->OnBufferingStateChange(
924 media::BUFFERING_HAVE_ENOUGH, media::BUFFERING_CHANGE_REASON_UNKNOWN);
927 void MediaPlayerBridgeCapi::OnDurationChange(int player_id, double duration) {
928 GetMediaPlayerClient()->OnDurationChange(base::Seconds(duration));
931 void MediaPlayerBridgeCapi::OnBufferUpdate(
933 std::vector<TimeRanges> buffer_range) {
934 TimeRanges range = buffer_range.at(0);
935 GetMediaPlayerClient()->OnBufferUpdate(base::Microseconds(range.end));
938 void MediaPlayerBridgeCapi::SetMediaType(DemuxerStream::Type type) {
939 if (type == DemuxerStream::AUDIO)
940 SetMediaType(GetMediaType() | MediaType::Audio);
941 else if (type == DemuxerStream::VIDEO)
942 SetMediaType(GetMediaType() | MediaType::Video);
945 PlayerRoleFlags MediaPlayerBridgeCapi::GetRoles() const noexcept {
946 return PlayerRole::UrlBased;
949 void MediaPlayerBridgeCapi::DeliverMediaPacket(ScopedMediaPacket packet) {
950 tbm_surface_info_s suf_info = {
953 tbm_surface_h tbm_surface = nullptr;
955 if (MEDIA_PACKET_ERROR_NONE !=
956 media_packet_get_tbm_surface(packet.get(), &tbm_surface)) {
957 LOG(ERROR) << "|media_packet_get_tbm_surface| failed";
961 if (TBM_SURFACE_ERROR_NONE != tbm_surface_get_info(tbm_surface, &suf_info)) {
962 LOG(ERROR) << "|tbm_surface_get_info| failed";
966 if (width_ != static_cast<int>(suf_info.width) ||
967 height_ != static_cast<int>(suf_info.height)) {
968 width_ = static_cast<int>(suf_info.width);
969 height_ = static_cast<int>(suf_info.height);
971 OnMediaDataChange(player_id_, width_, height_,
972 static_cast<int>(MediaType::Video));
975 // TODO(max): Need to check if we can use "media_packet_get_pts" instead of
976 // generating a new timestamp in here.
977 base::TimeDelta timestamp = GetCurrentTime();
979 #if defined(TIZEN_TBM_SUPPORT)
980 gfx::TbmBufferHandle tbm_handle;
981 tbm_handle.tbm_surface = reinterpret_cast<uint64_t>(tbm_surface);
982 tbm_handle.media_packet = reinterpret_cast<uint64_t>(packet.release());
983 OnNewTbmBufferAvailable(player_id_, tbm_handle, timestamp);
985 base::UnsafeSharedMemoryRegion shared_memory;
986 base::WritableSharedMemoryMapping memory_mapping;
987 uint32_t shared_memory_size =
988 suf_info.planes[0].size + (suf_info.planes[0].size / 2);
989 shared_memory = base::UnsafeSharedMemoryRegion::Create(shared_memory_size);
990 if (!shared_memory.IsValid()) {
991 LOG(ERROR) << "Shared Memory creation failed. Player " << player_id_;
995 memory_mapping = shared_memory.Map();
996 if (!memory_mapping.IsValid()) {
997 LOG(ERROR) << "Shared Memory handle could not be obtained. Player "
1002 unsigned char* y_ptr = static_cast<unsigned char*>(memory_mapping.memory());
1004 // Video format will always be converted to I420
1005 switch (suf_info.format) {
1006 case TBM_FORMAT_NV12: {
1007 unsigned char* u_ptr = y_ptr + suf_info.planes[0].size;
1008 unsigned char* v_ptr = u_ptr + (suf_info.planes[0].size * 5 / 4);
1009 libyuv::NV12ToI420(suf_info.planes[0].ptr, suf_info.planes[0].stride,
1010 suf_info.planes[1].ptr, suf_info.planes[1].stride,
1011 y_ptr, suf_info.planes[0].stride, u_ptr,
1012 suf_info.planes[1].stride / 2, v_ptr,
1013 suf_info.planes[1].stride / 2, suf_info.width,
1017 case TBM_FORMAT_YUV420: {
1018 unsigned char* u_ptr = y_ptr + suf_info.planes[0].size;
1019 unsigned char* v_ptr = u_ptr + suf_info.planes[1].size;
1021 suf_info.planes[0].ptr, suf_info.planes[0].stride,
1022 suf_info.planes[1].ptr, suf_info.planes[1].stride,
1023 suf_info.planes[2].ptr, suf_info.planes[2].stride, y_ptr,
1024 suf_info.planes[0].stride, u_ptr, suf_info.planes[1].stride, v_ptr,
1025 suf_info.planes[2].stride, suf_info.width, suf_info.height);
1030 LOG(WARNING) << "Not supported format";
1035 OnNewFrameAvailable(player_id_, std::move(shared_memory), shared_memory_size,
1040 #if defined(TIZEN_TBM_SUPPORT)
1041 void MediaPlayerBridgeCapi::DestroyMediaPacket(void* media_packet) {
1042 if (!task_runner_->BelongsToCurrentThread()) {
1043 task_runner_->PostTask(
1044 FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapi::DestroyMediaPacket,
1045 weak_factory_.GetWeakPtr(), media_packet));
1049 if (MEDIA_PACKET_ERROR_NONE !=
1050 media_packet_destroy(static_cast<media_packet_h>(media_packet))) {
1051 LOG(WARNING) << "Fail to release media_packet";
1055 void MediaPlayerBridgeCapi::OnNewTbmBufferAvailable(
1057 gfx::TbmBufferHandle tbm_handle,
1058 base::TimeDelta timestamp) {
1059 DCHECK(GetMediaPlayerClient());
1061 void* media_packet = reinterpret_cast<void*>(tbm_handle.media_packet);
1062 tbm_handle.media_packet = reinterpret_cast<uint64_t>(media_packet);
1063 tbm_handle.player_id = player_id_;
1064 tbm_handle.width = width_;
1065 tbm_handle.height = height_;
1067 GetMediaPlayerClient()->OnNewTbmFrameAvailable(player_id, tbm_handle,
1071 void MediaPlayerBridgeCapi::OnNewFrameAvailable(
1073 base::UnsafeSharedMemoryRegion shm_region,
1075 base::TimeDelta timestamp) {
1079 } // namespace media