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 // The delay time before retrying ReadBuffer.
33 // Wait until there is space in the buffer.
34 const base::TimeDelta kBufferQueueReadDelay = base::Milliseconds(100);
36 espp_buffer_size_t GetMaxAudioBufferSize() {
37 return kPlayerAudioBufferSize;
40 espp_buffer_size_t GetMaxVideoBufferSize(gfx::Size size) {
41 return kPlayerTotalBufferSize - kPlayerAudioBufferSize;
44 void ReadyToPrepareCallback(const esplusplayer_stream_type stream_type,
46 MediaPlayerESPlusPlayer* player =
47 static_cast<MediaPlayerESPlusPlayer*>(user_data);
51 player->OnReadyToPrepare(stream_type);
54 void PrepareCompleteCallback(bool result, void* user_data) {
55 MediaPlayerESPlusPlayer* player =
56 static_cast<MediaPlayerESPlusPlayer*>(user_data);
60 player->OnPrepareComplete(result);
63 void EosCallback(void* user_data) {
64 MediaPlayerESPlusPlayer* player =
65 static_cast<MediaPlayerESPlusPlayer*>(user_data);
72 void FrameReadyCallback(const esplusplayer_decoded_video_packet* packet,
74 MediaPlayerESPlusPlayer* player =
75 static_cast<MediaPlayerESPlusPlayer*>(user_data);
79 player->OnFrameReady(packet);
82 void FlushCompleteCallback(void* user_data) {
83 MediaPlayerESPlusPlayer* player =
84 static_cast<MediaPlayerESPlusPlayer*>(user_data);
88 player->OnFlushComplete();
91 void ReadyToSeekCallback(const esplusplayer_stream_type stream_type,
92 const uint64_t seek_time,
94 MediaPlayerESPlusPlayer* player =
95 static_cast<MediaPlayerESPlusPlayer*>(user_data);
99 player->OnReadyToSeek(stream_type, seek_time);
102 void SeekCompleteCallback(void* user_data) {
103 MediaPlayerESPlusPlayer* player =
104 static_cast<MediaPlayerESPlusPlayer*>(user_data);
108 player->OnSeekComplete();
111 void ResourceConflictCallback(void* user_data) {
112 MediaPlayerESPlusPlayer* player =
113 static_cast<MediaPlayerESPlusPlayer*>(user_data);
117 player->OnResourceConflict();
120 void ErrorCallback(const esplusplayer_error_type error_type, void* user_data) {
121 MediaPlayerESPlusPlayer* player =
122 static_cast<MediaPlayerESPlusPlayer*>(user_data);
126 player->OnError(error_type);
129 MediaPlayerESPlusPlayer::MediaPlayerESPlusPlayer() {
130 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
131 player_id_ = MediaPlayerRegistry::GetInstance()->RegisterMediaPlayer(this);
134 MediaPlayerESPlusPlayer::~MediaPlayerESPlusPlayer() {
135 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
136 weak_factory_.InvalidateWeakPtrs();
138 MediaPlayerRegistry::GetInstance()->UnregisterMediaPlayer(player_id_);
140 // Player should be released before destroyed.
143 int error = esplusplayer_destroy(esplayer_);
144 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
145 LOG(ERROR) << "esplusplayer_destroy failed, error #"
146 << esplusplayer_get_error_string(
147 static_cast<esplusplayer_error_type>(error));
151 bool MediaPlayerESPlusPlayer::CreatePlayer() {
155 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
156 esplayer_ = esplusplayer_create();
158 LOG(ERROR) << "Cannot create esplus player!";
162 last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
163 last_frames_.get<DemuxerStream::AUDIO>().second = media::kNoTimestamp;
164 last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
165 last_frames_.get<DemuxerStream::VIDEO>().second = media::kNoTimestamp;
167 buffer_observer_.reset(BufferObserver::CreateBufferObserver());
169 #if defined(TIZEN_VIDEO_HOLE)
170 LOG(INFO) << __func__ << " is_video_hole_: " << is_video_hole_;
171 if (is_video_hole_) {
172 video_plane_controller_.reset(
173 new VideoPlaneControllerESPlusPlayer(esplayer_));
180 void MediaPlayerESPlusPlayer::Initialize(VideoRendererSink* sink) {
181 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
182 esplusplayer_set_ready_to_prepare_cb(esplayer_, &ReadyToPrepareCallback,
184 esplusplayer_set_prepare_async_done_cb(esplayer_, &PrepareCompleteCallback,
186 esplusplayer_set_eos_cb(esplayer_, &EosCallback, this);
187 esplusplayer_set_media_packet_video_decoded_cb(esplayer_, &FrameReadyCallback,
189 esplusplayer_set_flush_done_cb(esplayer_, &FlushCompleteCallback, this);
190 esplusplayer_set_ready_to_seek_cb(esplayer_, &ReadyToSeekCallback, this);
191 esplusplayer_set_seek_done_cb(esplayer_, &SeekCompleteCallback, this);
192 esplusplayer_set_resource_conflicted_cb(esplayer_, &ResourceConflictCallback,
194 esplusplayer_set_error_cb(esplayer_, &ErrorCallback, this);
195 buffer_observer_->SetBufferingCallback(
196 base::BindRepeating(&MediaPlayerESPlusPlayer::OnBufferingStatusChanged,
197 weak_factory_.GetWeakPtr()));
199 int error = esplusplayer_open(esplayer_);
200 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
201 LOG(ERROR) << "esplusplayer_open failed. error #"
202 << esplusplayer_get_error_string(
203 static_cast<esplusplayer_error_type>(error));
207 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
208 << " state:" << GetString(GetPlayerState());
210 esplusplayer_decoded_video_frame_buffer_type video_frame_buffer_type =
211 ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY;
212 #if defined(TIZEN_VIDEO_HOLE)
214 video_frame_buffer_type = ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE;
217 error = esplusplayer_set_video_frame_buffer_type(esplayer_,
218 video_frame_buffer_type);
219 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
220 LOG(ERROR) << "esplusplayer_set_video_frame_buffer_type failed. error #"
221 << esplusplayer_get_error_string(
222 static_cast<esplusplayer_error_type>(error));
229 bool MediaPlayerESPlusPlayer::IsInitialized() {
230 return (GetPlayerState() >= ESPLUSPLAYER_STATE_IDLE);
233 void MediaPlayerESPlusPlayer::SetTaskRunner(
234 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
235 task_runner_ = task_runner.get();
238 void MediaPlayerESPlusPlayer::SetStreamInfo(DemuxerStream::Type type,
239 DemuxerStream* stream,
240 RendererClient* client) {
242 LOG(ERROR) << "Invalid player handle. Send error to client.";
243 client->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
247 SetDemuxerStream(type, stream);
248 SetRendererClient(type, client);
249 InitializeStreamConfig(type);
252 void MediaPlayerESPlusPlayer::SetRendererClientExtension(
253 media::MediaPlayerTizenClientExtension* client_extension) {
257 void MediaPlayerESPlusPlayer::Prepare() {
258 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
259 if (is_prepared_ || is_preparing_)
262 if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) {
263 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
264 << " Prepare called on invalid state : "
265 << GetString(GetPlayerState());
269 #if defined(TIZEN_VIDEO_HOLE)
270 if (is_video_hole_ && video_plane_controller_) {
271 if (video_plane_controller_->Initialize() != TIZEN_ERROR_NONE) {
272 LOG(ERROR) << "video_plane_controller init error";
275 LOG(INFO) << __func__ << " set ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY";
276 int player_error = ESPLUSPLAYER_ERROR_TYPE_NONE;
277 if (video_plane_controller_->rendering_mode() ==
278 VideoPlaneController::RenderingMode::OFFSCREEN) {
279 player_error = esplusplayer_set_display(
280 esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
281 video_plane_controller_->GetVideoPlaneHandle());
283 int wl_w, wl_h, wl_x, wl_y;
284 ecore_wl2_window_geometry_get(
285 static_cast<Ecore_Wl2_Window*>(
286 video_plane_controller_->GetVideoPlaneHandle()),
287 &wl_x, &wl_y, &wl_w, &wl_h);
289 player_error = esplusplayer_set_ecore_display(
290 esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
291 static_cast<Ecore_Wl2_Window*>(
292 video_plane_controller_->GetVideoPlaneHandle()),
293 wl_x, wl_y, wl_w, wl_h);
295 if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
296 LOG(ERROR) << "player_error #"
297 << esplusplayer_get_error_string(
298 static_cast<esplusplayer_error_type>(player_error));
304 int error = esplusplayer_prepare_async(esplayer_);
305 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
306 LOG(ERROR) << "player prepare failed! error #"
307 << esplusplayer_get_error_string(
308 static_cast<esplusplayer_error_type>(error));
310 if (IsValid(DemuxerStream::AUDIO))
311 GetRendererClient(DemuxerStream::AUDIO)
312 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
313 else if (IsValid(DemuxerStream::VIDEO))
314 GetRendererClient(DemuxerStream::VIDEO)
315 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
318 is_preparing_ = true;
321 bool MediaPlayerESPlusPlayer::IsPrepared() {
322 return (GetPlayerState() >= ESPLUSPLAYER_STATE_READY);
325 void MediaPlayerESPlusPlayer::Release() {
329 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
330 SetIsEos(DemuxerStream::AUDIO, false);
331 SetShouldFeed(DemuxerStream::AUDIO, false);
332 SetIsValid(DemuxerStream::AUDIO, false);
333 SetReadRequested(DemuxerStream::AUDIO, false);
335 SetIsEos(DemuxerStream::VIDEO, false);
336 SetShouldFeed(DemuxerStream::VIDEO, false);
337 SetIsValid(DemuxerStream::VIDEO, false);
338 SetReadRequested(DemuxerStream::VIDEO, false);
340 esplusplayer_set_ready_to_prepare_cb(esplayer_, nullptr, this);
341 esplusplayer_set_prepare_async_done_cb(esplayer_, nullptr, this);
342 esplusplayer_set_eos_cb(esplayer_, nullptr, this);
343 esplusplayer_set_media_packet_video_decoded_cb(esplayer_, nullptr, this);
344 esplusplayer_set_flush_done_cb(esplayer_, nullptr, this);
345 esplusplayer_set_ready_to_seek_cb(esplayer_, nullptr, this);
346 esplusplayer_set_seek_done_cb(esplayer_, nullptr, this);
347 esplusplayer_set_resource_conflicted_cb(esplayer_, nullptr, this);
348 esplusplayer_set_error_cb(esplayer_, nullptr, this);
350 buffer_observer_->ResetBufferStatus();
351 buffer_observer_->ResetBufferStatusCallbacks(esplayer_);
354 playback_rate_ = 0.0;
355 is_prepared_ = false;
356 is_preparing_ = false;
358 is_buffering_ = false;
359 current_position_ = base::TimeDelta();
360 is_flushing_ = false;
362 seek_position_ = base::TimeDelta();
363 pending_seek_ = false;
364 pending_seek_position_ = base::TimeDelta();
365 should_set_playback_rate_ = false;
367 GetBufferQueue(DemuxerStream::VIDEO).clear();
368 GetBufferQueue(DemuxerStream::AUDIO).clear();
372 if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE) {
373 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
374 << " Release called on invalid state : "
375 << GetString(GetPlayerState());
379 esplusplayer_close(esplayer_);
382 void MediaPlayerESPlusPlayer::Play() {
383 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
384 int error = ESPLUSPLAYER_ERROR_TYPE_NONE;
385 esplusplayer_state state = GetPlayerState();
388 if (state < ESPLUSPLAYER_STATE_READY || !is_prepared_ || is_seeking_) {
389 LOG(INFO) << "state : " << GetString(state)
390 << " is_prepared : " << is_prepared_
391 << " is_seeking : " << is_seeking_
392 << " is_buffering : " << is_buffering_;
397 LOG(INFO) << "state : " << GetString(state) << " is_paused : " << is_paused_
398 << " is_buffering : " << is_buffering_;
403 if (should_set_playback_rate_)
404 SetRate(playback_rate_);
406 if (state == ESPLUSPLAYER_STATE_READY)
407 error = esplusplayer_start(esplayer_);
408 else if (state == ESPLUSPLAYER_STATE_PAUSED ||
409 state == ESPLUSPLAYER_STATE_PLAYING)
410 error = esplusplayer_resume(esplayer_);
412 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
413 LOG(ERROR) << "player play failed! state #" << GetString(state)
415 << esplusplayer_get_error_string(
416 static_cast<esplusplayer_error_type>(error));
417 // TODO: handle error!
422 void MediaPlayerESPlusPlayer::Pause(bool is_media_related_action) {
424 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
425 << " already paused";
429 if (!is_media_related_action)
432 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
433 << " is_buffering : " << is_buffering_
434 << " is_media_action : " << is_media_related_action;
435 esplusplayer_state state = GetPlayerState();
436 if (state != ESPLUSPLAYER_STATE_PLAYING) {
437 LOG(WARNING) << "Cannot pause in " << GetString(state) << " state";
441 int error = esplusplayer_pause(esplayer_);
442 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
443 LOG(ERROR) << "player pause failed! error #"
444 << esplusplayer_get_error_string(
445 static_cast<esplusplayer_error_type>(error));
446 // TODO: handle error!
451 void MediaPlayerESPlusPlayer::SetRate(double rate) {
452 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " : "
454 if (playback_rate_ == rate)
457 playback_rate_ = rate;
458 if (GetPlayerState() < ESPLUSPLAYER_STATE_READY) {
459 should_set_playback_rate_ = true;
463 bool should_mute = rate >= 2.0;
465 esplusplayer_set_playback_rate(esplayer_, playback_rate_, should_mute);
466 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
467 LOG(ERROR) << "player set playback rate failed! error #"
468 << esplusplayer_get_error_string(
469 static_cast<esplusplayer_error_type>(error));
472 should_set_playback_rate_ = false;
475 void MediaPlayerESPlusPlayer::Seek(base::TimeDelta time) {
476 // Ignore seek to 0 during initialization.
477 if (GetPlayerState() < ESPLUSPLAYER_STATE_READY && time.InSecondsF() == 00) {
478 LOG(INFO) << __func__ << " Ignore seek to 0 during initialization.";
482 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " :"
484 if (GetPlayerState() < ESPLUSPLAYER_STATE_READY || !is_prepared_ ||
486 LOG(INFO) << "Add to pending seek ("
487 << ") state: " << GetString(GetPlayerState())
488 << " is_prepared : " << is_prepared_
489 << " is_seeking : " << is_seeking_;
490 pending_seek_ = true;
491 pending_seek_position_ = time;
495 last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
496 last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
498 UpdateBufferedDtsDifference();
500 SetShouldFeed(DemuxerStream::AUDIO, false);
501 SetShouldFeed(DemuxerStream::VIDEO, false);
502 GetBufferQueue(DemuxerStream::VIDEO).clear();
503 GetBufferQueue(DemuxerStream::AUDIO).clear();
504 buffer_observer_->ResetBufferStatus();
506 LOG(INFO) << __func__ << " : " << time;
507 int error = esplusplayer_seek(esplayer_, time.InMilliseconds());
508 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
509 LOG(ERROR) << "Seek failed. Current time : " << time.InSecondsF()
511 << esplusplayer_get_error_string(
512 static_cast<esplusplayer_error_type>(error));
517 seek_position_ = time;
518 pending_seek_ = false;
519 pending_seek_position_ = base::TimeDelta();
522 void MediaPlayerESPlusPlayer::Flush(base::OnceClosure flush_cb) {
523 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
524 last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
525 last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
527 UpdateBufferedDtsDifference();
530 std::move(flush_cb).Run();
533 void MediaPlayerESPlusPlayer::SetVolume(double volume) {
534 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " :"
537 if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE)
540 int error = esplusplayer_set_volume(esplayer_, 100 * volume_);
541 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
542 LOG(ERROR) << "esplusplayer_set_volume failed, error #"
543 << esplusplayer_get_error_string(
544 static_cast<esplusplayer_error_type>(error));
547 base::TimeDelta MediaPlayerESPlusPlayer::GetCurrentTime() {
549 return pending_seek_position_;
552 return seek_position_;
554 // Seek can be called before PLAY / PAUSE. Return last known time.
555 if (GetPlayerState() < ESPLUSPLAYER_STATE_PLAYING)
556 return current_position_;
558 uint64_t time = 0; // In milliseconds.
559 int error = esplusplayer_get_playing_time(esplayer_, &time);
560 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
561 LOG(ERROR) << "esplusplayer_get_playing_time failed. error #"
562 << esplusplayer_get_error_string(
563 static_cast<esplusplayer_error_type>(error));
564 return base::TimeDelta();
567 current_position_ = base::Milliseconds(time);
568 return current_position_;
571 #if defined(TIZEN_TBM_SUPPORT)
572 void MediaPlayerESPlusPlayer::DestroyMediaPacket(void* media_packet) {
573 if (!task_runner_->BelongsToCurrentThread()) {
574 task_runner_->PostTask(
575 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::DestroyMediaPacket,
576 weak_factory_.GetWeakPtr(), media_packet));
580 esplusplayer_decoded_buffer_destroy(
581 esplayer_, static_cast<esplusplayer_decoded_video_packet*>(media_packet));
585 esplusplayer_state MediaPlayerESPlusPlayer::GetPlayerState() {
586 return (esplayer_ ? esplusplayer_get_state(esplayer_)
587 : ESPLUSPLAYER_STATE_NONE);
590 void MediaPlayerESPlusPlayer::InitializeStreamConfig(DemuxerStream::Type type) {
591 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
592 DemuxerStream* stream = GetDemuxerStream(type);
595 if (type == DemuxerStream::AUDIO) {
596 media::AudioDecoderConfig audio_config = stream->audio_decoder_config();
597 if (!audio_config.IsValidConfig()) {
598 LOG(INFO) << "Invalid audio config";
602 LOG(INFO) << "Audio config : " << audio_config.AsHumanReadableString();
603 esplusplayer_audio_stream_info audio_stream_info;
604 memset(&audio_stream_info, 0, sizeof(esplusplayer_audio_stream_info));
606 audio_stream_info.mime_type =
607 ConvertToESPlusAudioMimeType(audio_config.codec());
608 audio_stream_info.bitrate = audio_config.bytes_per_channel() *
609 audio_config.samples_per_second() * 8;
610 audio_stream_info.channels =
611 media::ChannelLayoutToChannelCount(audio_config.channel_layout());
612 audio_stream_info.sample_rate = audio_config.samples_per_second();
613 audio_stream_info.codec_data_length = audio_config.extra_data().size();
615 if (audio_stream_info.codec_data_length > 0) {
616 audio_stream_info.codec_data =
617 (char*)(const_cast<unsigned char*>(audio_config.extra_data().data()));
619 audio_stream_info.codec_data = NULL;
623 if (!IsValid(type)) {
624 error = esplusplayer_set_audio_stream_info(esplayer_, &audio_stream_info);
625 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
626 LOG(ERROR) << "esplusplayer_set_audio_stream_info failed. error code "
628 GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
631 buffer_observer_->SetMediaStreamStatusCallback(
632 esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO);
635 espp_buffer_size_t max_buffer_size = GetMaxAudioBufferSize();
636 buffer_observer_->SetBufferSize(type, max_buffer_size);
637 LOG(INFO) << "Audio Max buffer size " << max_buffer_size;
638 error = esplusplayer_set_buffer_size(
639 esplayer_, ESPLUSPLAYER_BUFFER_AUDIO_MAX_BYTE_SIZE, max_buffer_size);
640 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
641 LOG(WARNING) << "Failed to set audio buffer to " << max_buffer_size / 1024
644 SetIsValid(type, true);
645 GetRendererClient(type)->OnAudioConfigChange(audio_config);
648 if (type == DemuxerStream::VIDEO) {
649 media::VideoDecoderConfig video_config = stream->video_decoder_config();
650 if (!video_config.IsValidConfig()) {
651 LOG(ERROR) << "Invalid video config.";
655 LOG(INFO) << "Video config : " << video_config.AsHumanReadableString();
656 esplusplayer_video_stream_info video_stream_info;
657 memset(&video_stream_info, 0, sizeof(esplusplayer_video_stream_info));
659 video_stream_info.width = video_config.coded_size().width();
660 video_stream_info.height = video_config.coded_size().height();
661 video_stream_info.mime_type =
662 ConvertToESPlusVideoMimeType(video_config.codec());
664 // TODO: Fetch frame rate from demuxer?
665 video_stream_info.framerate_num = kVideoFramerateNum;
666 video_stream_info.framerate_den = kVideoFramerateDen;
667 video_stream_info.codec_data_length = video_config.extra_data().size();
668 if (video_stream_info.codec_data_length > 0) {
669 video_stream_info.codec_data =
670 (char*)(const_cast<unsigned char*>(video_config.extra_data().data()));
672 video_stream_info.codec_data = NULL;
674 auto max_resolution =
675 GetMaxCodecResolution(video_stream_info.mime_type, is_video_hole_);
677 video_stream_info.max_width = max_resolution.width();
678 video_stream_info.max_height = max_resolution.height();
681 if (!IsValid(type)) {
682 error = esplusplayer_set_video_stream_info(esplayer_, &video_stream_info);
683 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
684 LOG(ERROR) << "esplusplayer_set_video_stream_info failed. error code "
686 GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
689 buffer_observer_->SetMediaStreamStatusCallback(
690 esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
693 espp_buffer_size_t max_buffer_size =
694 GetMaxVideoBufferSize(video_config.coded_size());
695 buffer_observer_->SetBufferSize(type, max_buffer_size);
697 LOG(INFO) << "Video Max buffer size " << max_buffer_size;
698 error = esplusplayer_set_buffer_size(
699 esplayer_, ESPLUSPLAYER_BUFFER_VIDEO_MAX_BYTE_SIZE, max_buffer_size);
700 if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
701 LOG(WARNING) << "Failed to set video buffer to " << max_buffer_size / 1024
704 SetIsValid(type, true);
705 GetRendererClient(type)->OnVideoConfigChange(video_config);
709 void MediaPlayerESPlusPlayer::ReadBuffer(DemuxerStream::Type type) {
710 if (!ReadFromBufferQueue(type))
713 // Avoid unnecessary or redundant read requests.
714 if (!ShouldFeed(type) || ReadRequested(type) || IsEos(type))
717 SetReadRequested(type, true);
718 GetDemuxerStream(type)->Read(
719 base::BindOnce(&MediaPlayerESPlusPlayer::OnBufferReady,
720 weak_factory_.GetWeakPtr(), type));
723 void MediaPlayerESPlusPlayer::PostReadBuffer(DemuxerStream::Type type) {
724 task_runner_->PostDelayedTask(
726 base::BindOnce(&MediaPlayerESPlusPlayer::ReadBuffer,
727 weak_factory_.GetWeakPtr(), type),
728 kBufferQueueReadDelay);
731 void MediaPlayerESPlusPlayer::OnBufferReady(
732 DemuxerStream::Type type,
733 DemuxerStream::Status status,
734 scoped_refptr<DecoderBuffer> buffer) {
735 bool should_delay_read = false;
737 case DemuxerStream::kAborted:
738 case DemuxerStream::kError:
739 GetBufferQueue(type).clear();
741 case DemuxerStream::kNeedBuffer:
742 should_delay_read = true;
744 case DemuxerStream::kConfigChanged:
745 // Clear pending buffer of older config
746 GetBufferQueue(type).clear();
747 InitializeStreamConfig(type);
749 case DemuxerStream::kOk: {
750 GetBufferQueue(type).push_back(buffer);
755 SetReadRequested(type, false);
756 if (should_delay_read)
757 PostReadBuffer(type);
762 bool MediaPlayerESPlusPlayer::ReadFromBufferQueue(DemuxerStream::Type type) {
763 if (!GetBufferQueue(type).size())
766 esplusplayer_submit_status status = ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS;
767 scoped_refptr<DecoderBuffer> buffer = GetBufferQueue(type).front();
768 if (buffer.get()->end_of_stream())
769 status = SubmitEosPacket(type);
771 status = SubmitEsPacket(type, buffer);
773 if (status == ESPLUSPLAYER_SUBMIT_STATUS_FULL) {
774 // If buffer is full, try again after a while.
775 PostReadBuffer(type);
779 if (status == ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED ||
780 status == ESPLUSPLAYER_SUBMIT_STATUS_OUT_OF_MEMORY)
783 UpdateBufferedDtsDifference();
784 GetBufferQueue(type).pop_front();
788 esplusplayer_submit_status MediaPlayerESPlusPlayer::SubmitEosPacket(
789 DemuxerStream::Type type) {
791 return ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS;
793 last_frames_[type].first = base::TimeDelta::Max();
795 esplusplayer_submit_status status = esplusplayer_submit_eos_packet(
796 esplayer_, GetESPlusPlayerStreamType(type));
797 if (status != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
798 LOG(ERROR) << "Submit Eos (" << DemuxerStream::GetTypeName(type)
799 << ") Packet failed, ret:" << GetString(status);
802 buffer_observer_->SetEos(type);
803 SetIsEos(type, true);
807 esplusplayer_submit_status MediaPlayerESPlusPlayer::SubmitEsPacket(
808 DemuxerStream::Type type,
809 scoped_refptr<DecoderBuffer> buffer) {
810 esplusplayer_es_packet packet;
811 memset(&packet, 0, sizeof(esplusplayer_es_packet));
812 packet.type = GetESPlusPlayerStreamType(type);
814 packet.buffer = (char*)(const_cast<unsigned char*>(buffer->data()));
815 packet.buffer_size = buffer->data_size();
816 packet.pts = buffer->timestamp().InMilliseconds();
817 packet.duration = buffer->duration().InMilliseconds();
819 // This filed only set when PushMediaPacket
820 packet.matroska_color_info = nullptr;
821 esplusplayer_submit_status status =
822 esplusplayer_submit_packet(esplayer_, &packet);
823 if (status != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
824 LOG(WARNING) << "submit " << DemuxerStream::GetTypeName(type)
825 << " packet : " << GetString(status);
828 last_frames_[type].first = base::Milliseconds(packet.pts);
829 last_frames_[type].second = base::Milliseconds(packet.duration);
833 void MediaPlayerESPlusPlayer::UpdateBufferedDtsDifference() {
834 // Ignore unless audio and video streams are valid.
835 if (!IsValid(DemuxerStream::AUDIO) || !IsValid(DemuxerStream::VIDEO))
838 const auto& audio_ts = last_frames_.get<DemuxerStream::AUDIO>().first;
839 const auto& video_ts = last_frames_.get<DemuxerStream::VIDEO>().first;
841 if ((audio_ts != media::kNoTimestamp) && (video_ts != media::kNoTimestamp) &&
842 (audio_ts != base::TimeDelta::Max()) &&
843 (video_ts != base::TimeDelta::Max())) {
844 const auto av_diff = (audio_ts - video_ts).InMilliseconds();
845 buffer_observer_->SetAudioVideoDtsDifference(av_diff);
847 buffer_observer_->SetAudioVideoDtsDifference(0);
851 void MediaPlayerESPlusPlayer::OnBufferingStatusChanged(DemuxerStream::Type type,
852 BufferStatus status) {
853 LOG(INFO) << __func__ << " " << DemuxerStream::GetTypeName(type) << " : "
854 << GetString(status);
855 const auto RequestStateChange = [this](esplusplayer_state state) {
856 LOG(INFO) << __func__ << " req. change state : " << GetString(state);
858 case ESPLUSPLAYER_STATE_PLAYING:
861 case ESPLUSPLAYER_STATE_PAUSED:
869 SetBufferStatus(type, status);
871 case kBufferUnderrun:
872 // RequestStateChange(ESPLUSPLAYER_STATE_PAUSED);
874 case kBufferMinThreshold:
876 is_buffering_ = true;
877 SetShouldFeed(type, true);
880 case kBufferMaxThreshold:
881 case kBufferOverflow:
884 is_buffering_ = false;
885 SetShouldFeed(type, false);
887 // RequestStateChange(ESPLUSPLAYER_STATE_PLAYING);
893 // TODO: Check if controller can control underflow. Currently buffering
894 // related state changes are commented for the same (in Play and
895 // RequestStateChange).
896 if (status != kBufferNone) {
897 GetRendererClient(type)->OnBufferingStateChange(
898 BUFFERING_HAVE_ENOUGH, BUFFERING_CHANGE_REASON_UNKNOWN);
902 void MediaPlayerESPlusPlayer::OnReadyToPrepare(
903 const esplusplayer_stream_type stream_type) {
904 if (!task_runner_->BelongsToCurrentThread()) {
905 task_runner_->PostTask(
906 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnReadyToPrepare,
907 weak_factory_.GetWeakPtr(), stream_type));
911 LOG(INFO) << "OnReadyToPrepare : "
912 << DemuxerStream::GetTypeName(GetDemuxerStreamType(stream_type));
913 if (stream_type != ESPLUSPLAYER_STREAM_TYPE_AUDIO &&
914 stream_type != ESPLUSPLAYER_STREAM_TYPE_VIDEO)
917 DemuxerStream::Type type = GetDemuxerStreamType(stream_type);
919 SetShouldFeed(type, true);
924 void MediaPlayerESPlusPlayer::OnPrepareComplete(bool result) {
925 if (!task_runner_->BelongsToCurrentThread()) {
926 task_runner_->PostTask(
927 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnPrepareComplete,
928 weak_factory_.GetWeakPtr(), result));
933 LOG(ERROR) << "OnPrepareComplete prepare_async failed.";
934 if (IsValid(DemuxerStream::AUDIO))
935 GetRendererClient(DemuxerStream::AUDIO)
936 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
937 else if (IsValid(DemuxerStream::VIDEO))
938 GetRendererClient(DemuxerStream::VIDEO)
939 ->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
943 if (GetPlayerState() != ESPLUSPLAYER_STATE_READY) {
944 LOG(ERROR) << "Invalid state (" << GetString(GetPlayerState())
945 << ") change during prepare. Returning.";
949 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
950 << " is_paused_ : " << is_paused_
951 << " seek_position : " << seek_position_
952 << " pending_seek_ : " << pending_seek_
953 << " pending_seek_position_ : " << pending_seek_position_;
955 #if defined(TIZEN_VIDEO_HOLE)
957 video_plane_controller_->ResetMediaGeometry();
962 Seek(pending_seek_position_);
963 } else if (!is_paused_) {
968 void MediaPlayerESPlusPlayer::OnEos() {
969 if (!task_runner_->BelongsToCurrentThread()) {
970 task_runner_->PostTask(FROM_HERE,
971 base::BindOnce(&MediaPlayerESPlusPlayer::OnEos,
972 weak_factory_.GetWeakPtr()));
976 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
977 if (IsValid(DemuxerStream::VIDEO))
978 GetRendererClient(DemuxerStream::VIDEO)->OnEnded();
979 else if (IsValid(DemuxerStream::AUDIO))
980 GetRendererClient(DemuxerStream::AUDIO)->OnEnded();
984 void MediaPlayerESPlusPlayer::OnFrameReady(
985 const esplusplayer_decoded_video_packet* packet) {
986 if (!task_runner_->BelongsToCurrentThread()) {
987 task_runner_->PostTask(
988 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnFrameReady,
989 weak_factory_.GetWeakPtr(), packet));
992 tbm_surface_info_s suf_info = {
995 tbm_surface_h tbm_surface = static_cast<tbm_surface_h>(packet->surface_data);
997 if (TBM_SURFACE_ERROR_NONE != tbm_surface_get_info(tbm_surface, &suf_info)) {
998 LOG(ERROR) << "|tbm_surface_get_info| failed";
1002 int width = static_cast<int>(suf_info.width);
1003 int height = static_cast<int>(suf_info.height);
1004 gfx::Size size(width, height);
1006 base::TimeDelta timestamp = base::Milliseconds(packet->pts);
1007 DLOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
1008 << " size:" << size.ToString()
1009 << ", timestamp:" << timestamp.InMilliseconds()
1010 << ", duration:" << packet->duration << ", Player(" << esplayer_
1011 << ", state:" << GetString(GetPlayerState());
1013 #if defined(TIZEN_TBM_SUPPORT)
1014 gfx::TbmBufferHandle tbm_handle;
1015 tbm_handle.tbm_surface = reinterpret_cast<uint64_t>(tbm_surface);
1016 tbm_handle.media_packet = reinterpret_cast<uint64_t>(packet);
1017 tbm_handle.player_id = player_id_;
1018 tbm_handle.width = width;
1019 tbm_handle.height = height;
1020 data_cb_.Run(0, tbm_handle, timestamp);
1022 base::UnsafeSharedMemoryRegion shared_memory;
1023 uint32_t shared_memory_size =
1024 suf_info.planes[0].size + (suf_info.planes[0].size / 2);
1025 shared_memory = base::UnsafeSharedMemoryRegion::Create(shared_memory_size);
1026 if (!shared_memory.IsValid()) {
1027 LOG(ERROR) << "Shared Memory creation failed.";
1031 base::WritableSharedMemoryMapping memory_mapping;
1032 memory_mapping = shared_memory.Map();
1033 if (!memory_mapping.IsValid()) {
1034 LOG(ERROR) << "Shared Memory handle could not be obtained";
1038 unsigned char* y_ptr = static_cast<unsigned char*>(memory_mapping.memory());
1040 // Video format will always be converted to I420
1041 switch (suf_info.format) {
1042 case TBM_FORMAT_NV12: {
1043 unsigned char* u_ptr = y_ptr + suf_info.planes[0].size;
1044 unsigned char* v_ptr = u_ptr + (suf_info.planes[0].size / 4);
1045 libyuv::NV12ToI420(suf_info.planes[0].ptr, suf_info.planes[0].stride,
1046 suf_info.planes[1].ptr, suf_info.planes[1].stride,
1047 y_ptr, suf_info.planes[0].stride, u_ptr,
1048 suf_info.planes[1].stride / 2, v_ptr,
1049 suf_info.planes[1].stride / 2, suf_info.width,
1053 case TBM_FORMAT_YUV420: {
1054 unsigned char* u_ptr = y_ptr + suf_info.planes[0].size;
1055 unsigned char* v_ptr = u_ptr + suf_info.planes[1].size;
1057 suf_info.planes[0].ptr, suf_info.planes[0].stride,
1058 suf_info.planes[1].ptr, suf_info.planes[1].stride,
1059 suf_info.planes[2].ptr, suf_info.planes[2].stride, y_ptr,
1060 suf_info.planes[0].stride, u_ptr, suf_info.planes[1].stride, v_ptr,
1061 suf_info.planes[2].stride, suf_info.width, suf_info.height);
1066 LOG(WARNING) << "Not supported format";
1071 esplusplayer_decoded_buffer_destroy(
1072 esplayer_, const_cast<esplusplayer_decoded_video_packet*>(packet));
1073 data_cb_.Run(0, std::move(shared_memory), shared_memory_size, timestamp,
1076 uint8_t* const yuv_buffer = static_cast<uint8_t*>(memory_mapping.memory());
1077 scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
1078 media::PIXEL_FORMAT_I420, size, gfx::Rect(size), size, timestamp);
1080 uint8_t* video_buf = yuv_buffer;
1081 const uint c_frm_size = shared_memory_size / 6;
1082 const uint y_frm_size = c_frm_size << 2; // * 4;
1085 uint8_t* video_buf_u = video_buf + y_frm_size;
1088 uint8_t* video_buf_v = video_buf_u + c_frm_size;
1091 video_buf, video_frame.get()->stride(VideoFrame::kYPlane), video_buf_u,
1092 video_frame.get()->stride(VideoFrame::kYPlane) / 2, video_buf_v,
1093 video_frame.get()->stride(VideoFrame::kYPlane) / 2,
1094 video_frame.get()->GetWritableVisibleData(VideoFrame::kYPlane),
1095 video_frame.get()->stride(VideoFrame::kYPlane),
1096 video_frame.get()->GetWritableVisibleData(VideoFrame::kUPlane),
1097 video_frame.get()->stride(VideoFrame::kUPlane),
1098 video_frame.get()->GetWritableVisibleData(VideoFrame::kVPlane),
1099 video_frame.get()->stride(VideoFrame::kVPlane), width, height);
1100 esplusplayer_decoded_buffer_destroy(
1101 esplayer_, const_cast<esplusplayer_decoded_video_packet*>(packet));
1103 sink_->PaintSingleFrame(video_frame);
1108 void MediaPlayerESPlusPlayer::OnFlushComplete() {
1112 void MediaPlayerESPlusPlayer::OnReadyToSeek(
1113 const esplusplayer_stream_type stream_type,
1114 const uint64_t seek_time) {
1115 if (!task_runner_->BelongsToCurrentThread()) {
1116 task_runner_->PostTask(
1118 base::BindOnce(&MediaPlayerESPlusPlayer::OnReadyToSeek,
1119 weak_factory_.GetWeakPtr(), stream_type, seek_time));
1122 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " : "
1123 << DemuxerStream::GetTypeName(GetDemuxerStreamType(stream_type))
1124 << " : " << seek_time;
1126 SetShouldFeed(GetDemuxerStreamType(stream_type), true);
1127 SetIsEos(GetDemuxerStreamType(stream_type), false);
1128 ReadBuffer(GetDemuxerStreamType(stream_type));
1131 void MediaPlayerESPlusPlayer::OnSeekComplete() {
1132 if (!task_runner_->BelongsToCurrentThread()) {
1133 task_runner_->PostTask(
1134 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnSeekComplete,
1135 weak_factory_.GetWeakPtr()));
1139 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
1140 << " is_paused:" << is_paused_;
1142 current_position_ = seek_position_;
1143 is_seeking_ = false;
1144 seek_position_ = base::TimeDelta();
1145 if (pending_seek_) {
1146 Seek(pending_seek_position_);
1147 pending_seek_position_ = base::TimeDelta();
1155 void MediaPlayerESPlusPlayer::OnResourceConflict() {
1156 if (!task_runner_->BelongsToCurrentThread()) {
1157 task_runner_->PostTask(
1158 FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnResourceConflict,
1159 weak_factory_.GetWeakPtr()));
1163 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
1167 void MediaPlayerESPlusPlayer::OnError(const esplusplayer_error_type error) {
1168 if (!task_runner_->BelongsToCurrentThread()) {
1169 task_runner_->PostTask(FROM_HERE,
1170 base::BindOnce(&MediaPlayerESPlusPlayer::OnError,
1171 weak_factory_.GetWeakPtr(), error));
1175 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " : "
1176 << esplusplayer_get_error_string(
1177 static_cast<esplusplayer_error_type>(error));
1179 if (IsValid(DemuxerStream::VIDEO))
1180 GetRendererClient(DemuxerStream::VIDEO)->OnError(GetPipelineError(error));
1181 else if (IsValid(DemuxerStream::AUDIO))
1182 GetRendererClient(DemuxerStream::AUDIO)->OnError(GetPipelineError(error));
1186 MediaPlayerESPlusPlayer::ElementryStream&
1187 MediaPlayerESPlusPlayer::GetElementryStream(DemuxerStream::Type type) {
1188 return elementry_stream_[GetElementryStreamIndex(type)];
1191 const MediaPlayerESPlusPlayer::ElementryStream&
1192 MediaPlayerESPlusPlayer::GetElementryStream(DemuxerStream::Type type) const {
1193 return elementry_stream_[GetElementryStreamIndex(type)];
1196 bool MediaPlayerESPlusPlayer::IsValid(DemuxerStream::Type type) const {
1197 return GetElementryStream(type).is_valid_;
1200 void MediaPlayerESPlusPlayer::SetIsValid(DemuxerStream::Type type, bool value) {
1201 GetElementryStream(type).is_valid_ = value;
1204 bool MediaPlayerESPlusPlayer::IsEos(DemuxerStream::Type type) const {
1205 return GetElementryStream(type).is_eos_;
1208 void MediaPlayerESPlusPlayer::SetIsEos(DemuxerStream::Type type, bool value) {
1209 GetElementryStream(type).is_eos_ = value;
1212 bool MediaPlayerESPlusPlayer::ShouldFeed(DemuxerStream::Type type) const {
1213 return GetElementryStream(type).should_feed_;
1216 void MediaPlayerESPlusPlayer::SetShouldFeed(DemuxerStream::Type type,
1218 GetElementryStream(type).should_feed_ = value;
1221 bool MediaPlayerESPlusPlayer::ReadRequested(DemuxerStream::Type type) const {
1222 return GetElementryStream(type).read_requested_;
1225 void MediaPlayerESPlusPlayer::SetReadRequested(DemuxerStream::Type type,
1227 GetElementryStream(type).read_requested_ = value;
1230 BufferStatus MediaPlayerESPlusPlayer::GetBufferStatus(
1231 DemuxerStream::Type type) {
1232 return GetElementryStream(type).buffer_status_;
1235 void MediaPlayerESPlusPlayer::SetBufferStatus(DemuxerStream::Type type,
1236 BufferStatus status) {
1237 GetElementryStream(type).buffer_status_ = status;
1240 DemuxerStream* MediaPlayerESPlusPlayer::GetDemuxerStream(
1241 DemuxerStream::Type type) const {
1242 return GetElementryStream(type).input_stream_;
1245 void MediaPlayerESPlusPlayer::SetDemuxerStream(DemuxerStream::Type type,
1246 DemuxerStream* stream) {
1247 GetElementryStream(type).input_stream_ = stream;
1250 RendererClient* MediaPlayerESPlusPlayer::GetRendererClient(
1251 DemuxerStream::Type type) const {
1252 return GetElementryStream(type).renderer_client_;
1255 void MediaPlayerESPlusPlayer::SetRendererClient(DemuxerStream::Type type,
1256 RendererClient* client) {
1257 GetElementryStream(type).renderer_client_ = client;
1260 Queue& MediaPlayerESPlusPlayer::GetBufferQueue(DemuxerStream::Type type) {
1261 return GetElementryStream(type).pending_buffers_;
1264 void MediaPlayerESPlusPlayer::SetFrameAvailableCallback(
1265 const DataRequestCB& datacb) {
1269 #if defined(TIZEN_VIDEO_HOLE)
1270 void MediaPlayerESPlusPlayer::SetVideoHole(bool is_video_hole) {
1271 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
1272 << " is_video_hole : " << is_video_hole;
1273 is_video_hole_ = is_video_hole;
1274 if (is_video_hole_ && esplayer_ && !video_plane_controller_) {
1275 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
1276 << " pended set video_plane_controller";
1277 video_plane_controller_.reset(
1278 new VideoPlaneControllerESPlusPlayer(esplayer_));
1282 void MediaPlayerESPlusPlayer::SetMediaGeometry(const gfx::Rect& viewport_rect,
1283 const gfx::RectF& rect) {
1284 if (!is_video_hole_)
1287 LOG(INFO) << __func__ << " viewport_rect: " << viewport_rect.ToString()
1288 << " rect : " << rect.ToString();
1289 video_plane_controller_->SetMediaGeometry(viewport_rect, rect);
1294 } // namespace media