1 // Copyright 2022 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 "tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h"
7 #include <esplusplayer_internal.h>
8 #include <tbm_surface.h>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "media/base/decoder_buffer.h"
15 #include "media/base/renderer_client.h"
16 #include "third_party/libyuv/include/libyuv/convert.h"
17 #include "tizen_src/chromium_impl/media/filters/media_player_registry.h"
19 #if defined(TIZEN_VIDEO_HOLE)
20 #include <Ecore_Wl2.h>
21 #include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller_esplusplayer.h"
25 using player_buffer_size_t = unsigned long long;
27 // Limit of platform player's total (audio and video) buffer size in bytes
28 const media::player_buffer_size_t kPlayerTotalBufferSize = 64 * 1024 * 1024;
29 // Limit of platform player's audio buffer in bytes
30 const media::player_buffer_size_t kPlayerAudioBufferSize = 768 * 1024;
32 espp_buffer_size_t GetMaxAudioBufferSize() {
33 return kPlayerAudioBufferSize;
36 espp_buffer_size_t GetMaxVideoBufferSize(gfx::Size size) {
37 return kPlayerTotalBufferSize - kPlayerAudioBufferSize;
40 void ReadyToPrepareCallback(const esplusplayer_stream_type stream_type,
42 MediaPlayerESPlusPlayer* player =
43 static_cast<MediaPlayerESPlusPlayer*>(user_data);
47 player->OnReadyToPrepare(stream_type);
50 void PrepareCompleteCallback(bool result, void* user_data) {
51 MediaPlayerESPlusPlayer* player =
52 static_cast<MediaPlayerESPlusPlayer*>(user_data);
56 player->OnPrepareComplete(result);
59 void EosCallback(void* user_data) {
60 MediaPlayerESPlusPlayer* player =
61 static_cast<MediaPlayerESPlusPlayer*>(user_data);
68 void FrameReadyCallback(const esplusplayer_decoded_video_packet* packet,
70 MediaPlayerESPlusPlayer* player =
71 static_cast<MediaPlayerESPlusPlayer*>(user_data);
75 player->OnFrameReady(packet);
78 void FlushCompleteCallback(void* user_data) {
79 MediaPlayerESPlusPlayer* player =
80 static_cast<MediaPlayerESPlusPlayer*>(user_data);
84 player->OnFlushComplete();
87 void ReadyToSeekCallback(const esplusplayer_stream_type stream_type,
88 const uint64_t seek_time,
90 MediaPlayerESPlusPlayer* player =
91 static_cast<MediaPlayerESPlusPlayer*>(user_data);
95 player->OnReadyToSeek(stream_type, seek_time);
98 void SeekCompleteCallback(void* user_data) {
99 MediaPlayerESPlusPlayer* player =
100 static_cast<MediaPlayerESPlusPlayer*>(user_data);
104 player->OnSeekComplete();
107 void ResourceConflictCallback(void* user_data) {
108 MediaPlayerESPlusPlayer* player =
109 static_cast<MediaPlayerESPlusPlayer*>(user_data);
113 player->OnResourceConflict();
116 void ErrorCallback(const esplusplayer_error_type error_type, void* user_data) {
117 MediaPlayerESPlusPlayer* player =
118 static_cast<MediaPlayerESPlusPlayer*>(user_data);
122 player->OnError(error_type);
125 MediaPlayerESPlusPlayer::MediaPlayerESPlusPlayer() {
126 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
127 player_id_ = MediaPlayerRegistry::GetInstance()->RegisterMediaPlayer(this);
130 MediaPlayerESPlusPlayer::~MediaPlayerESPlusPlayer() {
131 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
132 weak_factory_.InvalidateWeakPtrs();
134 MediaPlayerRegistry::GetInstance()->UnregisterMediaPlayer(player_id_);
136 // Player should be released before destroyed.
139 int error = esplusplayer_destroy(esplayer_);
140 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
141 LOG(ERROR) << "esplusplayer_destroy failed, error #"
142 << esplusplayer_get_error_string(
143 static_cast<esplusplayer_error_type>(error));
147 bool MediaPlayerESPlusPlayer::CreatePlayer() {
151 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
152 esplayer_ = esplusplayer_create();
154 LOG(ERROR) << "Cannot create esplus player!";
158 last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
159 last_frames_.get<DemuxerStream::AUDIO>().second = media::kNoTimestamp;
160 last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
161 last_frames_.get<DemuxerStream::VIDEO>().second = media::kNoTimestamp;
163 buffer_observer_.reset(BufferObserver::CreateBufferObserver());
165 #if defined(TIZEN_VIDEO_HOLE)
166 LOG(INFO) << __func__ << " is_video_hole_: " << is_video_hole_;
167 if (is_video_hole_) {
168 video_plane_controller_.reset(
169 new VideoPlaneControllerESPlusPlayer(esplayer_));
176 void MediaPlayerESPlusPlayer::Initialize(VideoRendererSink* sink) {
177 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
178 esplusplayer_set_ready_to_prepare_cb(esplayer_, &ReadyToPrepareCallback,
180 esplusplayer_set_prepare_async_done_cb(esplayer_, &PrepareCompleteCallback,
182 esplusplayer_set_eos_cb(esplayer_, &EosCallback, this);
183 esplusplayer_set_media_packet_video_decoded_cb(esplayer_, &FrameReadyCallback,
185 esplusplayer_set_flush_done_cb(esplayer_, &FlushCompleteCallback, this);
186 esplusplayer_set_ready_to_seek_cb(esplayer_, &ReadyToSeekCallback, this);
187 esplusplayer_set_seek_done_cb(esplayer_, &SeekCompleteCallback, this);
188 esplusplayer_set_resource_conflicted_cb(esplayer_, &ResourceConflictCallback,
190 esplusplayer_set_error_cb(esplayer_, &ErrorCallback, this);
191 buffer_observer_->SetBufferingCallback(
192 base::BindRepeating(&MediaPlayerESPlusPlayer::OnBufferingStatusChanged,
193 weak_factory_.GetWeakPtr()));
195 int error = esplusplayer_open(esplayer_);
196 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
197 LOG(ERROR) << "esplusplayer_open failed. error #"
198 << esplusplayer_get_error_string(
199 static_cast<esplusplayer_error_type>(error));
203 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
204 << " state:" << GetString(GetPlayerState());
206 esplusplayer_decoded_video_frame_buffer_type video_frame_buffer_type =
207 ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY;
208 #if defined(TIZEN_VIDEO_HOLE)
210 video_frame_buffer_type = ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE;
213 error = esplusplayer_set_video_frame_buffer_type(esplayer_,
214 video_frame_buffer_type);
215 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
216 LOG(ERROR) << "esplusplayer_set_video_frame_buffer_type failed. error #"
217 << esplusplayer_get_error_string(
218 static_cast<esplusplayer_error_type>(error));
225 bool MediaPlayerESPlusPlayer::IsInitialized() {
226 return (GetPlayerState() >= ESPLUSPLAYER_STATE_IDLE);
229 void MediaPlayerESPlusPlayer::SetTaskRunner(
230 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
231 task_runner_ = task_runner.get();
234 void MediaPlayerESPlusPlayer::SetStreamInfo(DemuxerStream::Type type,
235 DemuxerStream* stream,
236 RendererClient* client) {
238 LOG(ERROR) << "Invalid player handle. Send error to client.";
239 client->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
243 SetDemuxerStream(type, stream);
244 SetRendererClient(type, client);
245 InitializeStreamConfig(type);
248 void MediaPlayerESPlusPlayer::SetRendererClientExtension(
249 media::MediaPlayerTizenClientExtension* client_extension) {
253 void MediaPlayerESPlusPlayer::Prepare() {
254 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
255 if (is_prepared_ || is_preparing_)
258 if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) {
259 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
260 << " Prepare called on invalid state : "
261 << GetString(GetPlayerState());
265 #if defined(TIZEN_VIDEO_HOLE)
266 if (is_video_hole_ && video_plane_controller_) {
267 if (video_plane_controller_->Initialize() != TIZEN_ERROR_NONE) {
268 LOG(ERROR) << "video_plane_controller init error";
271 LOG(INFO) << __func__ << " set ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY";
272 int player_error = ESPLUSPLAYER_ERROR_TYPE_NONE;
273 if (video_plane_controller_->rendering_mode() ==
274 VideoPlaneController::RenderingMode::OFFSCREEN) {
275 player_error = esplusplayer_set_display(
276 esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
277 video_plane_controller_->GetVideoPlaneHandle());
279 int wl_w, wl_h, wl_x, wl_y;
280 ecore_wl2_window_geometry_get(
281 static_cast<Ecore_Wl2_Window*>(
282 video_plane_controller_->GetVideoPlaneHandle()),
283 &wl_x, &wl_y, &wl_w, &wl_h);
285 player_error = esplusplayer_set_ecore_display(
286 esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
287 static_cast<Ecore_Wl2_Window*>(
288 video_plane_controller_->GetVideoPlaneHandle()),
289 wl_x, wl_y, wl_w, wl_h);
291 if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
292 LOG(ERROR) << "player_error #"
293 << esplusplayer_get_error_string(
294 static_cast<esplusplayer_error_type>(player_error));
300 int error = esplusplayer_prepare_async(esplayer_);
301 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
302 LOG(ERROR) << "player prepare failed! error #"
303 << esplusplayer_get_error_string(
304 static_cast<esplusplayer_error_type>(error));
306 if (IsValid(DemuxerStream::AUDIO))
307 GetRendererClient(DemuxerStream::AUDIO)
308 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
309 else if (IsValid(DemuxerStream::VIDEO))
310 GetRendererClient(DemuxerStream::VIDEO)
311 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
314 is_preparing_ = true;
317 bool MediaPlayerESPlusPlayer::IsPrepared() {
318 return (GetPlayerState() >= ESPLUSPLAYER_STATE_READY);
321 void MediaPlayerESPlusPlayer::Release() {
325 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
326 SetIsEos(DemuxerStream::AUDIO, false);
327 SetShouldFeed(DemuxerStream::AUDIO, false);
328 SetIsValid(DemuxerStream::AUDIO, false);
329 SetReadRequested(DemuxerStream::AUDIO, false);
331 SetIsEos(DemuxerStream::VIDEO, false);
332 SetShouldFeed(DemuxerStream::VIDEO, false);
333 SetIsValid(DemuxerStream::VIDEO, false);
334 SetReadRequested(DemuxerStream::VIDEO, false);
336 esplusplayer_set_ready_to_prepare_cb(esplayer_, nullptr, this);
337 esplusplayer_set_prepare_async_done_cb(esplayer_, nullptr, this);
338 esplusplayer_set_eos_cb(esplayer_, nullptr, this);
339 esplusplayer_set_media_packet_video_decoded_cb(esplayer_, nullptr, this);
340 esplusplayer_set_flush_done_cb(esplayer_, nullptr, this);
341 esplusplayer_set_ready_to_seek_cb(esplayer_, nullptr, this);
342 esplusplayer_set_seek_done_cb(esplayer_, nullptr, this);
343 esplusplayer_set_resource_conflicted_cb(esplayer_, nullptr, this);
344 esplusplayer_set_error_cb(esplayer_, nullptr, this);
346 buffer_observer_->ResetBufferStatus();
347 buffer_observer_->ResetBufferStatusCallbacks(esplayer_);
350 playback_rate_ = 0.0;
351 is_prepared_ = false;
352 is_preparing_ = false;
354 is_buffering_ = false;
355 current_position_ = base::TimeDelta();
356 is_flushing_ = false;
358 seek_position_ = base::TimeDelta();
359 pending_seek_ = false;
360 pending_seek_position_ = base::TimeDelta();
361 should_set_playback_rate_ = false;
363 GetBufferQueue(DemuxerStream::VIDEO).clear();
364 GetBufferQueue(DemuxerStream::AUDIO).clear();
368 if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE) {
369 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
370 << " Release called on invalid state : "
371 << GetString(GetPlayerState());
375 esplusplayer_close(esplayer_);
378 void MediaPlayerESPlusPlayer::Play() {
379 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
380 int error = ESPLUSPLAYER_ERROR_TYPE_NONE;
381 esplusplayer_state state = GetPlayerState();
384 if (state < ESPLUSPLAYER_STATE_READY || !is_prepared_ || is_seeking_) {
385 LOG(INFO) << "state : " << GetString(state)
386 << " is_prepared : " << is_prepared_
387 << " is_seeking : " << is_seeking_
388 << " is_buffering : " << is_buffering_;
393 LOG(INFO) << "state : " << GetString(state) << " is_paused : " << is_paused_
394 << " is_buffering : " << is_buffering_;
399 if (should_set_playback_rate_)
400 SetRate(playback_rate_);
402 if (state == ESPLUSPLAYER_STATE_READY)
403 error = esplusplayer_start(esplayer_);
404 else if (state == ESPLUSPLAYER_STATE_PAUSED ||
405 state == ESPLUSPLAYER_STATE_PLAYING)
406 error = esplusplayer_resume(esplayer_);
408 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
409 LOG(ERROR) << "player play failed! state #" << GetString(state)
411 << esplusplayer_get_error_string(
412 static_cast<esplusplayer_error_type>(error));
413 // TODO: handle error!
418 void MediaPlayerESPlusPlayer::Pause(bool is_media_related_action) {
420 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
421 << " already paused";
425 if (!is_media_related_action)
428 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
429 << " is_buffering : " << is_buffering_
430 << " is_media_action : " << is_media_related_action;
431 esplusplayer_state state = GetPlayerState();
432 if (state != ESPLUSPLAYER_STATE_PLAYING) {
433 LOG(WARNING) << "Cannot pause in " << GetString(state) << " state";
437 int error = esplusplayer_pause(esplayer_);
438 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
439 LOG(ERROR) << "player pause failed! error #"
440 << esplusplayer_get_error_string(
441 static_cast<esplusplayer_error_type>(error));
442 // TODO: handle error!
447 void MediaPlayerESPlusPlayer::SetRate(double rate) {
448 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " : "
450 if (playback_rate_ == rate)
453 playback_rate_ = rate;
454 if (GetPlayerState() < ESPLUSPLAYER_STATE_READY) {
455 should_set_playback_rate_ = true;
459 bool should_mute = rate >= 2.0;
461 esplusplayer_set_playback_rate(esplayer_, playback_rate_, should_mute);
462 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
463 LOG(ERROR) << "player set playback rate failed! error #"
464 << esplusplayer_get_error_string(
465 static_cast<esplusplayer_error_type>(error));
468 should_set_playback_rate_ = false;
471 void MediaPlayerESPlusPlayer::Seek(base::TimeDelta time) {
472 // Ignore seek to 0 during initialization.
473 if (GetPlayerState() < ESPLUSPLAYER_STATE_READY && time.InSecondsF() == 00) {
474 LOG(INFO) << __func__ << " Ignore seek to 0 during initialization.";
478 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " :"
480 if (GetPlayerState() < ESPLUSPLAYER_STATE_READY || !is_prepared_ ||
482 LOG(INFO) << "Add to pending seek ("
483 << ") state: " << GetString(GetPlayerState())
484 << " is_prepared : " << is_prepared_
485 << " is_seeking : " << is_seeking_;
486 pending_seek_ = true;
487 pending_seek_position_ = time;
491 last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
492 last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
494 UpdateBufferedDtsDifference();
496 SetShouldFeed(DemuxerStream::AUDIO, false);
497 SetShouldFeed(DemuxerStream::VIDEO, false);
498 GetBufferQueue(DemuxerStream::VIDEO).clear();
499 GetBufferQueue(DemuxerStream::AUDIO).clear();
500 buffer_observer_->ResetBufferStatus();
502 LOG(INFO) << __func__ << " : " << time;
503 int error = esplusplayer_seek(esplayer_, time.InMilliseconds());
504 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
505 LOG(ERROR) << "Seek failed. Current time : " << time.InSecondsF()
507 << esplusplayer_get_error_string(
508 static_cast<esplusplayer_error_type>(error));
513 seek_position_ = time;
514 pending_seek_ = false;
515 pending_seek_position_ = base::TimeDelta();
518 void MediaPlayerESPlusPlayer::Flush(base::OnceClosure flush_cb) {
519 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
520 last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
521 last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
523 UpdateBufferedDtsDifference();
526 std::move(flush_cb).Run();
529 void MediaPlayerESPlusPlayer::SetVolume(double volume) {
530 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " :"
533 if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE)
536 int error = esplusplayer_set_volume(esplayer_, 100 * volume_);
537 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
538 LOG(ERROR) << "esplusplayer_set_volume failed, error #"
539 << esplusplayer_get_error_string(
540 static_cast<esplusplayer_error_type>(error));
543 base::TimeDelta MediaPlayerESPlusPlayer::GetCurrentTime() {
545 return pending_seek_position_;
548 return seek_position_;
550 // Seek can be called before PLAY / PAUSE. Return last known time.
551 if (GetPlayerState() < ESPLUSPLAYER_STATE_PLAYING)
552 return current_position_;
554 uint64_t time = 0; // In milliseconds.
555 int error = esplusplayer_get_playing_time(esplayer_, &time);
556 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
557 LOG(ERROR) << "esplusplayer_get_playing_time failed. error #"
558 << esplusplayer_get_error_string(
559 static_cast<esplusplayer_error_type>(error));
560 return base::TimeDelta();
563 current_position_ = base::Milliseconds(time);
564 return current_position_;
567 #if defined(TIZEN_TBM_SUPPORT)
568 void MediaPlayerESPlusPlayer::DestroyMediaPacket(void* media_packet) {
569 if (!task_runner_->BelongsToCurrentThread()) {
570 task_runner_->PostTask(
571 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::DestroyMediaPacket,
572 weak_factory_.GetWeakPtr(), media_packet));
576 esplusplayer_decoded_buffer_destroy(
577 esplayer_, static_cast<esplusplayer_decoded_video_packet*>(media_packet));
581 esplusplayer_state MediaPlayerESPlusPlayer::GetPlayerState() {
582 return (esplayer_ ? esplusplayer_get_state(esplayer_)
583 : ESPLUSPLAYER_STATE_NONE);
586 void MediaPlayerESPlusPlayer::InitializeStreamConfig(DemuxerStream::Type type) {
587 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
588 DemuxerStream* stream = GetDemuxerStream(type);
591 if (type == DemuxerStream::AUDIO) {
592 media::AudioDecoderConfig audio_config = stream->audio_decoder_config();
593 if (!audio_config.IsValidConfig()) {
594 LOG(INFO) << "Invalid audio config";
598 LOG(INFO) << "Audio config : " << audio_config.AsHumanReadableString();
599 esplusplayer_audio_stream_info audio_stream_info;
600 memset(&audio_stream_info, 0, sizeof(esplusplayer_audio_stream_info));
602 audio_stream_info.mime_type =
603 ConvertToESPlusAudioMimeType(audio_config.codec());
604 audio_stream_info.bitrate = audio_config.bytes_per_channel() *
605 audio_config.samples_per_second() * 8;
606 audio_stream_info.channels =
607 media::ChannelLayoutToChannelCount(audio_config.channel_layout());
608 audio_stream_info.sample_rate = audio_config.samples_per_second();
609 audio_stream_info.codec_data_length = audio_config.extra_data().size();
611 if (audio_stream_info.codec_data_length > 0) {
612 audio_stream_info.codec_data =
613 (char*)(const_cast<unsigned char*>(audio_config.extra_data().data()));
615 audio_stream_info.codec_data = NULL;
619 if (!IsValid(type)) {
620 error = esplusplayer_set_audio_stream_info(esplayer_, &audio_stream_info);
621 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
622 LOG(ERROR) << "esplusplayer_set_audio_stream_info failed. error code "
624 GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
627 buffer_observer_->SetMediaStreamStatusCallback(
628 esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO);
631 espp_buffer_size_t max_buffer_size = GetMaxAudioBufferSize();
632 buffer_observer_->SetBufferSize(type, max_buffer_size);
633 LOG(INFO) << "Audio Max buffer size " << max_buffer_size;
634 error = esplusplayer_set_buffer_size(
635 esplayer_, ESPLUSPLAYER_BUFFER_AUDIO_MAX_BYTE_SIZE, max_buffer_size);
636 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
637 LOG(WARNING) << "Failed to set audio buffer to " << max_buffer_size / 1024
640 SetIsValid(type, true);
641 GetRendererClient(type)->OnAudioConfigChange(audio_config);
644 if (type == DemuxerStream::VIDEO) {
645 media::VideoDecoderConfig video_config = stream->video_decoder_config();
646 if (!video_config.IsValidConfig()) {
647 LOG(ERROR) << "Invalid video config.";
651 LOG(INFO) << "Video config : " << video_config.AsHumanReadableString();
652 esplusplayer_video_stream_info video_stream_info;
653 memset(&video_stream_info, 0, sizeof(esplusplayer_video_stream_info));
655 video_stream_info.width = video_config.coded_size().width();
656 video_stream_info.height = video_config.coded_size().height();
657 video_stream_info.mime_type =
658 ConvertToESPlusVideoMimeType(video_config.codec());
660 // TODO: Fetch frame rate from demuxer?
661 video_stream_info.framerate_num = kVideoFramerateNum;
662 video_stream_info.framerate_den = kVideoFramerateDen;
663 video_stream_info.codec_data_length = video_config.extra_data().size();
664 if (video_stream_info.codec_data_length > 0) {
665 video_stream_info.codec_data =
666 (char*)(const_cast<unsigned char*>(video_config.extra_data().data()));
668 video_stream_info.codec_data = NULL;
670 auto max_resolution =
671 GetMaxCodecResolution(video_stream_info.mime_type, is_video_hole_);
673 video_stream_info.max_width = max_resolution.width();
674 video_stream_info.max_height = max_resolution.height();
677 if (!IsValid(type)) {
678 error = esplusplayer_set_video_stream_info(esplayer_, &video_stream_info);
679 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
680 LOG(ERROR) << "esplusplayer_set_video_stream_info failed. error code "
682 GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
685 buffer_observer_->SetMediaStreamStatusCallback(
686 esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
689 espp_buffer_size_t max_buffer_size =
690 GetMaxVideoBufferSize(video_config.coded_size());
691 buffer_observer_->SetBufferSize(type, max_buffer_size);
693 LOG(INFO) << "Video Max buffer size " << max_buffer_size;
694 error = esplusplayer_set_buffer_size(
695 esplayer_, ESPLUSPLAYER_BUFFER_VIDEO_MAX_BYTE_SIZE, max_buffer_size);
696 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
697 LOG(WARNING) << "Failed to set video buffer to " << max_buffer_size / 1024
700 SetIsValid(type, true);
701 GetRendererClient(type)->OnVideoConfigChange(video_config);
705 void MediaPlayerESPlusPlayer::ReadBuffer(DemuxerStream::Type type) {
706 if (!ReadFromBufferQueue(type))
709 // Avoid unnecessary or redundant read requests.
710 if (!ShouldFeed(type) || ReadRequested(type) || IsEos(type))
713 SetReadRequested(type, true);
714 GetDemuxerStream(type)->Read(
715 base::BindOnce(&MediaPlayerESPlusPlayer::OnBufferReady,
716 weak_factory_.GetWeakPtr(), type));
719 void MediaPlayerESPlusPlayer::OnBufferReady(
720 DemuxerStream::Type type,
721 DemuxerStream::Status status,
722 scoped_refptr<DecoderBuffer> buffer) {
724 case DemuxerStream::kAborted:
725 case DemuxerStream::kError:
726 GetBufferQueue(type).clear();
728 case DemuxerStream::kNeedBuffer:
730 case DemuxerStream::kConfigChanged:
731 // Clear pending buffer of older config
732 GetBufferQueue(type).clear();
733 InitializeStreamConfig(type);
735 case DemuxerStream::kOk: {
736 GetBufferQueue(type).push_back(buffer);
741 SetReadRequested(type, false);
745 bool MediaPlayerESPlusPlayer::ReadFromBufferQueue(DemuxerStream::Type type) {
746 if (!GetBufferQueue(type).size())
749 esplusplayer_submit_status status = ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS;
750 scoped_refptr<DecoderBuffer> buffer = GetBufferQueue(type).front();
751 if (buffer.get()->end_of_stream())
752 status = SubmitEosPacket(type);
754 status = SubmitEsPacket(type, buffer);
756 if (status == ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED ||
757 status == ESPLUSPLAYER_SUBMIT_STATUS_OUT_OF_MEMORY ||
758 status == ESPLUSPLAYER_SUBMIT_STATUS_FULL) {
762 UpdateBufferedDtsDifference();
763 GetBufferQueue(type).pop_front();
767 esplusplayer_submit_status MediaPlayerESPlusPlayer::SubmitEosPacket(
768 DemuxerStream::Type type) {
770 return ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS;
772 last_frames_[type].first = base::TimeDelta::Max();
774 esplusplayer_submit_status status = esplusplayer_submit_eos_packet(
775 esplayer_, GetESPlusPlayerStreamType(type));
776 if (status != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
777 LOG(ERROR) << "Submit Eos (" << DemuxerStream::GetTypeName(type)
778 << ") Packet failed, ret:" << GetString(status);
781 buffer_observer_->SetEos(type);
782 SetIsEos(type, true);
786 esplusplayer_submit_status MediaPlayerESPlusPlayer::SubmitEsPacket(
787 DemuxerStream::Type type,
788 scoped_refptr<DecoderBuffer> buffer) {
789 esplusplayer_es_packet packet;
790 memset(&packet, 0, sizeof(esplusplayer_es_packet));
791 packet.type = GetESPlusPlayerStreamType(type);
793 packet.buffer = (char*)(const_cast<unsigned char*>(buffer->data()));
794 packet.buffer_size = buffer->data_size();
795 packet.pts = buffer->timestamp().InMilliseconds();
796 packet.duration = buffer->duration().InMilliseconds();
798 // This filed only set when PushMediaPacket
799 packet.matroska_color_info = nullptr;
800 esplusplayer_submit_status status =
801 esplusplayer_submit_packet(esplayer_, &packet);
802 if (status != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
803 LOG(WARNING) << "submit " << DemuxerStream::GetTypeName(type)
804 << " packet : " << GetString(status);
807 last_frames_[type].first = base::Milliseconds(packet.pts);
808 last_frames_[type].second = base::Milliseconds(packet.duration);
812 void MediaPlayerESPlusPlayer::UpdateBufferedDtsDifference() {
813 // Ignore unless audio and video streams are valid.
814 if (!IsValid(DemuxerStream::AUDIO) || !IsValid(DemuxerStream::VIDEO))
817 const auto& audio_ts = last_frames_.get<DemuxerStream::AUDIO>().first;
818 const auto& video_ts = last_frames_.get<DemuxerStream::VIDEO>().first;
820 if ((audio_ts != media::kNoTimestamp) && (video_ts != media::kNoTimestamp) &&
821 (audio_ts != base::TimeDelta::Max()) &&
822 (video_ts != base::TimeDelta::Max())) {
823 const auto av_diff = (audio_ts - video_ts).InMilliseconds();
824 buffer_observer_->SetAudioVideoDtsDifference(av_diff);
826 buffer_observer_->SetAudioVideoDtsDifference(0);
830 void MediaPlayerESPlusPlayer::OnBufferingStatusChanged(DemuxerStream::Type type,
831 BufferStatus status) {
832 LOG(INFO) << __func__ << " " << DemuxerStream::GetTypeName(type) << " : "
833 << GetString(status);
834 const auto RequestStateChange = [this](esplusplayer_state state) {
835 LOG(INFO) << __func__ << " req. change state : " << GetString(state);
837 case ESPLUSPLAYER_STATE_PLAYING:
840 case ESPLUSPLAYER_STATE_PAUSED:
848 SetBufferStatus(type, status);
850 case kBufferUnderrun:
851 // RequestStateChange(ESPLUSPLAYER_STATE_PAUSED);
853 case kBufferMinThreshold:
855 is_buffering_ = true;
856 SetShouldFeed(type, true);
859 case kBufferMaxThreshold:
860 case kBufferOverflow:
863 is_buffering_ = false;
864 SetShouldFeed(type, false);
866 // RequestStateChange(ESPLUSPLAYER_STATE_PLAYING);
872 // TODO: Check if controller can control underflow. Currently buffering
873 // related state changes are commented for the same (in Play and
874 // RequestStateChange).
875 if (status != kBufferNone) {
876 GetRendererClient(type)->OnBufferingStateChange(
877 BUFFERING_HAVE_ENOUGH, BUFFERING_CHANGE_REASON_UNKNOWN);
881 void MediaPlayerESPlusPlayer::OnReadyToPrepare(
882 const esplusplayer_stream_type stream_type) {
883 if (!task_runner_->BelongsToCurrentThread()) {
884 task_runner_->PostTask(
885 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnReadyToPrepare,
886 weak_factory_.GetWeakPtr(), stream_type));
890 LOG(INFO) << "OnReadyToPrepare : "
891 << DemuxerStream::GetTypeName(GetDemuxerStreamType(stream_type));
892 if (stream_type != ESPLUSPLAYER_STREAM_TYPE_AUDIO &&
893 stream_type != ESPLUSPLAYER_STREAM_TYPE_VIDEO)
896 DemuxerStream::Type type = GetDemuxerStreamType(stream_type);
898 SetShouldFeed(type, true);
903 void MediaPlayerESPlusPlayer::OnPrepareComplete(bool result) {
904 if (!task_runner_->BelongsToCurrentThread()) {
905 task_runner_->PostTask(
906 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnPrepareComplete,
907 weak_factory_.GetWeakPtr(), result));
912 LOG(ERROR) << "OnPrepareComplete prepare_async failed.";
913 if (IsValid(DemuxerStream::AUDIO))
914 GetRendererClient(DemuxerStream::AUDIO)
915 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
916 else if (IsValid(DemuxerStream::VIDEO))
917 GetRendererClient(DemuxerStream::VIDEO)
918 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
922 if (GetPlayerState() != ESPLUSPLAYER_STATE_READY) {
923 LOG(ERROR) << "Invalid state (" << GetString(GetPlayerState())
924 << ") change during prepare. Returning.";
928 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
929 << " is_paused_ : " << is_paused_
930 << " seek_position : " << seek_position_
931 << " pending_seek_ : " << pending_seek_
932 << " pending_seek_position_ : " << pending_seek_position_;
934 #if defined(TIZEN_VIDEO_HOLE)
936 video_plane_controller_->ResetMediaGeometry();
941 Seek(pending_seek_position_);
942 } else if (!is_paused_) {
947 void MediaPlayerESPlusPlayer::OnEos() {
948 if (!task_runner_->BelongsToCurrentThread()) {
949 task_runner_->PostTask(FROM_HERE,
950 base::BindOnce(&MediaPlayerESPlusPlayer::OnEos,
951 weak_factory_.GetWeakPtr()));
955 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
956 if (IsValid(DemuxerStream::VIDEO))
957 GetRendererClient(DemuxerStream::VIDEO)->OnEnded();
958 else if (IsValid(DemuxerStream::AUDIO))
959 GetRendererClient(DemuxerStream::AUDIO)->OnEnded();
963 void MediaPlayerESPlusPlayer::OnFrameReady(
964 const esplusplayer_decoded_video_packet* packet) {
965 if (!task_runner_->BelongsToCurrentThread()) {
966 task_runner_->PostTask(
967 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnFrameReady,
968 weak_factory_.GetWeakPtr(), packet));
971 tbm_surface_info_s suf_info = {
974 tbm_surface_h tbm_surface = static_cast<tbm_surface_h>(packet->surface_data);
976 if (TBM_SURFACE_ERROR_NONE != tbm_surface_get_info(tbm_surface, &suf_info)) {
977 LOG(ERROR) << "|tbm_surface_get_info| failed";
981 int width = static_cast<int>(suf_info.width);
982 int height = static_cast<int>(suf_info.height);
983 gfx::Size size(width, height);
985 base::TimeDelta timestamp = base::Milliseconds(packet->pts);
986 DLOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
987 << " size:" << size.ToString()
988 << ", timestamp:" << timestamp.InMilliseconds()
989 << ", duration:" << packet->duration << ", Player(" << esplayer_
990 << ", state:" << GetString(GetPlayerState());
992 #if defined(TIZEN_TBM_SUPPORT)
993 gfx::TbmBufferHandle tbm_handle;
994 tbm_handle.tbm_surface = reinterpret_cast<uint64_t>(tbm_surface);
995 tbm_handle.media_packet = reinterpret_cast<uint64_t>(packet);
996 tbm_handle.player_id = player_id_;
997 tbm_handle.width = width;
998 tbm_handle.height = height;
999 data_cb_.Run(0, tbm_handle, timestamp);
1001 base::UnsafeSharedMemoryRegion shared_memory;
1002 uint32_t shared_memory_size =
1003 suf_info.planes[0].size + (suf_info.planes[0].size / 2);
1004 shared_memory = base::UnsafeSharedMemoryRegion::Create(shared_memory_size);
1005 if (!shared_memory.IsValid()) {
1006 LOG(ERROR) << "Shared Memory creation failed.";
1010 base::WritableSharedMemoryMapping memory_mapping;
1011 memory_mapping = shared_memory.Map();
1012 if (!memory_mapping.IsValid()) {
1013 LOG(ERROR) << "Shared Memory handle could not be obtained";
1017 unsigned char* y_ptr = static_cast<unsigned char*>(memory_mapping.memory());
1019 // Video format will always be converted to I420
1020 switch (suf_info.format) {
1021 case TBM_FORMAT_NV12: {
1022 unsigned char* u_ptr = y_ptr + suf_info.planes[0].size;
1023 unsigned char* v_ptr = u_ptr + (suf_info.planes[0].size / 4);
1024 libyuv::NV12ToI420(suf_info.planes[0].ptr, suf_info.planes[0].stride,
1025 suf_info.planes[1].ptr, suf_info.planes[1].stride,
1026 y_ptr, suf_info.planes[0].stride, u_ptr,
1027 suf_info.planes[1].stride / 2, v_ptr,
1028 suf_info.planes[1].stride / 2, suf_info.width,
1032 case TBM_FORMAT_YUV420: {
1033 unsigned char* u_ptr = y_ptr + suf_info.planes[0].size;
1034 unsigned char* v_ptr = u_ptr + suf_info.planes[1].size;
1036 suf_info.planes[0].ptr, suf_info.planes[0].stride,
1037 suf_info.planes[1].ptr, suf_info.planes[1].stride,
1038 suf_info.planes[2].ptr, suf_info.planes[2].stride, y_ptr,
1039 suf_info.planes[0].stride, u_ptr, suf_info.planes[1].stride, v_ptr,
1040 suf_info.planes[2].stride, suf_info.width, suf_info.height);
1045 LOG(WARNING) << "Not supported format";
1050 esplusplayer_decoded_buffer_destroy(
1051 esplayer_, const_cast<esplusplayer_decoded_video_packet*>(packet));
1052 data_cb_.Run(0, std::move(shared_memory), shared_memory_size, timestamp,
1055 uint8_t* const yuv_buffer = static_cast<uint8_t*>(memory_mapping.memory());
1056 scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
1057 media::PIXEL_FORMAT_I420, size, gfx::Rect(size), size, timestamp);
1059 uint8_t* video_buf = yuv_buffer;
1060 const uint c_frm_size = shared_memory_size / 6;
1061 const uint y_frm_size = c_frm_size << 2; // * 4;
1064 uint8_t* video_buf_u = video_buf + y_frm_size;
1067 uint8_t* video_buf_v = video_buf_u + c_frm_size;
1070 video_buf, video_frame.get()->stride(VideoFrame::kYPlane), video_buf_u,
1071 video_frame.get()->stride(VideoFrame::kYPlane) / 2, video_buf_v,
1072 video_frame.get()->stride(VideoFrame::kYPlane) / 2,
1073 video_frame.get()->GetWritableVisibleData(VideoFrame::kYPlane),
1074 video_frame.get()->stride(VideoFrame::kYPlane),
1075 video_frame.get()->GetWritableVisibleData(VideoFrame::kUPlane),
1076 video_frame.get()->stride(VideoFrame::kUPlane),
1077 video_frame.get()->GetWritableVisibleData(VideoFrame::kVPlane),
1078 video_frame.get()->stride(VideoFrame::kVPlane), width, height);
1079 esplusplayer_decoded_buffer_destroy(
1080 esplayer_, const_cast<esplusplayer_decoded_video_packet*>(packet));
1082 sink_->PaintSingleFrame(video_frame);
1087 void MediaPlayerESPlusPlayer::OnFlushComplete() {
1091 void MediaPlayerESPlusPlayer::OnReadyToSeek(
1092 const esplusplayer_stream_type stream_type,
1093 const uint64_t seek_time) {
1094 if (!task_runner_->BelongsToCurrentThread()) {
1095 task_runner_->PostTask(
1097 base::BindOnce(&MediaPlayerESPlusPlayer::OnReadyToSeek,
1098 weak_factory_.GetWeakPtr(), stream_type, seek_time));
1101 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " : "
1102 << DemuxerStream::GetTypeName(GetDemuxerStreamType(stream_type))
1103 << " : " << seek_time;
1105 SetShouldFeed(GetDemuxerStreamType(stream_type), true);
1106 SetIsEos(GetDemuxerStreamType(stream_type), false);
1107 ReadBuffer(GetDemuxerStreamType(stream_type));
1110 void MediaPlayerESPlusPlayer::OnSeekComplete() {
1111 if (!task_runner_->BelongsToCurrentThread()) {
1112 task_runner_->PostTask(
1113 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnSeekComplete,
1114 weak_factory_.GetWeakPtr()));
1118 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
1119 << " is_paused:" << is_paused_;
1121 current_position_ = seek_position_;
1122 is_seeking_ = false;
1123 seek_position_ = base::TimeDelta();
1124 if (pending_seek_) {
1125 Seek(pending_seek_position_);
1126 pending_seek_position_ = base::TimeDelta();
1134 void MediaPlayerESPlusPlayer::OnResourceConflict() {
1135 if (!task_runner_->BelongsToCurrentThread()) {
1136 task_runner_->PostTask(
1137 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnResourceConflict,
1138 weak_factory_.GetWeakPtr()));
1142 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
1146 void MediaPlayerESPlusPlayer::OnError(const esplusplayer_error_type error) {
1147 if (!task_runner_->BelongsToCurrentThread()) {
1148 task_runner_->PostTask(FROM_HERE,
1149 base::BindOnce(&MediaPlayerESPlusPlayer::OnError,
1150 weak_factory_.GetWeakPtr(), error));
1154 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " : "
1155 << esplusplayer_get_error_string(
1156 static_cast<esplusplayer_error_type>(error));
1158 if (IsValid(DemuxerStream::VIDEO))
1159 GetRendererClient(DemuxerStream::VIDEO)->OnError(GetPipelineError(error));
1160 else if (IsValid(DemuxerStream::AUDIO))
1161 GetRendererClient(DemuxerStream::AUDIO)->OnError(GetPipelineError(error));
1165 MediaPlayerESPlusPlayer::ElementryStream&
1166 MediaPlayerESPlusPlayer::GetElementryStream(DemuxerStream::Type type) {
1167 return elementry_stream_[GetElementryStreamIndex(type)];
1170 const MediaPlayerESPlusPlayer::ElementryStream&
1171 MediaPlayerESPlusPlayer::GetElementryStream(DemuxerStream::Type type) const {
1172 return elementry_stream_[GetElementryStreamIndex(type)];
1175 bool MediaPlayerESPlusPlayer::IsValid(DemuxerStream::Type type) const {
1176 return GetElementryStream(type).is_valid_;
1179 void MediaPlayerESPlusPlayer::SetIsValid(DemuxerStream::Type type, bool value) {
1180 GetElementryStream(type).is_valid_ = value;
1183 bool MediaPlayerESPlusPlayer::IsEos(DemuxerStream::Type type) const {
1184 return GetElementryStream(type).is_eos_;
1187 void MediaPlayerESPlusPlayer::SetIsEos(DemuxerStream::Type type, bool value) {
1188 GetElementryStream(type).is_eos_ = value;
1191 bool MediaPlayerESPlusPlayer::ShouldFeed(DemuxerStream::Type type) const {
1192 return GetElementryStream(type).should_feed_;
1195 void MediaPlayerESPlusPlayer::SetShouldFeed(DemuxerStream::Type type,
1197 GetElementryStream(type).should_feed_ = value;
1200 bool MediaPlayerESPlusPlayer::ReadRequested(DemuxerStream::Type type) const {
1201 return GetElementryStream(type).read_requested_;
1204 void MediaPlayerESPlusPlayer::SetReadRequested(DemuxerStream::Type type,
1206 GetElementryStream(type).read_requested_ = value;
1209 BufferStatus MediaPlayerESPlusPlayer::GetBufferStatus(
1210 DemuxerStream::Type type) {
1211 return GetElementryStream(type).buffer_status_;
1214 void MediaPlayerESPlusPlayer::SetBufferStatus(DemuxerStream::Type type,
1215 BufferStatus status) {
1216 GetElementryStream(type).buffer_status_ = status;
1219 DemuxerStream* MediaPlayerESPlusPlayer::GetDemuxerStream(
1220 DemuxerStream::Type type) const {
1221 return GetElementryStream(type).input_stream_;
1224 void MediaPlayerESPlusPlayer::SetDemuxerStream(DemuxerStream::Type type,
1225 DemuxerStream* stream) {
1226 GetElementryStream(type).input_stream_ = stream;
1229 RendererClient* MediaPlayerESPlusPlayer::GetRendererClient(
1230 DemuxerStream::Type type) const {
1231 return GetElementryStream(type).renderer_client_;
1234 void MediaPlayerESPlusPlayer::SetRendererClient(DemuxerStream::Type type,
1235 RendererClient* client) {
1236 GetElementryStream(type).renderer_client_ = client;
1239 Queue& MediaPlayerESPlusPlayer::GetBufferQueue(DemuxerStream::Type type) {
1240 return GetElementryStream(type).pending_buffers_;
1243 void MediaPlayerESPlusPlayer::SetFrameAvailableCallback(
1244 const DataRequestCB& datacb) {
1248 #if defined(TIZEN_VIDEO_HOLE)
1249 void MediaPlayerESPlusPlayer::SetVideoHole(bool is_video_hole) {
1250 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
1251 << " is_video_hole : " << is_video_hole;
1252 is_video_hole_ = is_video_hole;
1253 if (is_video_hole_ && esplayer_ && !video_plane_controller_) {
1254 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
1255 << " pended set video_plane_controller";
1256 video_plane_controller_.reset(
1257 new VideoPlaneControllerESPlusPlayer(esplayer_));
1261 void MediaPlayerESPlusPlayer::SetMediaGeometry(const gfx::Rect& viewport_rect,
1262 const gfx::RectF& rect) {
1263 if (!is_video_hole_)
1266 LOG(INFO) << __func__ << " viewport_rect: " << viewport_rect.ToString()
1267 << " rect : " << rect.ToString();
1268 video_plane_controller_->SetMediaGeometry(viewport_rect, rect);
1273 } // namespace media