[HBBTV] Porting TA feature from OSU 31/314631/5
authorMichal Jurkiewicz/Web Solutions (VD) /SRPOL <m.jurkiewicz@samsung.com>
Fri, 17 May 2024 10:20:17 +0000 (11:20 +0100)
committerBot Blink <blinkbot@samsung.com>
Tue, 16 Jul 2024 15:29:43 +0000 (15:29 +0000)
HBBTV-TA Implementation

Jobs: DF240513-00729
[git-p4: depot-paths = "//TIZEN/[Product2023]/[OSU_Trunk2023_T80_Prj]/[INT]/PLATFORM/COMMON/Profile/platform/framework/web/chromium-efl/": change = 12084875]

Bug: https://jira-eu.sec.samsung.net/browse/WPMEDMAIN-3149
Signed-off-by: Kajetan Brzuszczak <k.brzuszczak@partner.samsung.com>
Change-Id: Ie131046a05e8ca39885bbc6b14d2393b5d4267df

24 files changed:
media/base/pipeline.h
media/base/pipeline_impl.cc
media/base/pipeline_impl.h
media/base/renderer_client.h
media/mojo/mojom/renderer_extensions.mojom
third_party/blink/public/platform/web_media_player.h
third_party/blink/renderer/platform/media/web_media_player_impl.cc
third_party/blink/renderer/platform/media/web_media_player_impl.h
tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.cc
tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.h
tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.cc
tizen_src/chromium_impl/content/renderer/media/tizen/media_player_renderer_client.h
tizen_src/chromium_impl/media/blink/renderer/tizen_esplusplayer_renderer.h
tizen_src/chromium_impl/media/filters/hardware_resource_helper.cc
tizen_src/chromium_impl/media/filters/hardware_resource_helper.h
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc
tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc
tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.h
tizen_src/chromium_impl/media/filters/media_player_tizen.h
tizen_src/chromium_impl/media/filters/media_player_tizen_client.h
tizen_src/ewk/efl_integration/eweb_view.cc
tizen_src/ewk/efl_integration/eweb_view.h
tizen_src/ewk/efl_integration/public/ewk_view.cc
tizen_src/ewk/efl_integration/public/ewk_view_product.h

index 29e037cd6669c25e0e26e5343404fdb82ef9faa0..ba6845b4e538d6e69b8299cc0868b9c5ee97069a 100644 (file)
@@ -114,6 +114,10 @@ class MEDIA_EXPORT Pipeline {
     virtual void OnMrsUrlChange(const std::string& url){};
     virtual void OnContentIdChange(const std::string& id){};
     virtual void OnInitData(const std::vector<unsigned char>& init_data) = 0;
+
+    virtual void RequestPlay(){}
+    virtual void RequestPause(){}
+    virtual void RequestResume(){}
 #endif
 
     // Executed whenever the presentation duration changes.
index 24a7055dcc133d4f8715e44298af4c6de8b9ac62..9636043b1dce178393a92c57bf37ededa24f5809 100644 (file)
@@ -137,6 +137,10 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
   void SetDecryptorHandle(eme::eme_decryptor_t decryptor);
   void SetHasEncryptedListenerOrCdm(bool value);
   void SetVideoVisibility(bool visible);
+
+  void RequestPlay() override;
+  void RequestPause() override;
+  void RequestResume() override;
 #endif
 
   // |enabled_track_ids| contains track ids of enabled audio tracks.
@@ -1206,6 +1210,24 @@ void PipelineImpl::RendererWrapper::SetVideoVisibility(bool visible) {
   if (shared_state_.renderer)
     shared_state_.renderer->SetVideoVisibility(visible);
 }
+
+void PipelineImpl::RendererWrapper::RequestPlay() {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  main_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&PipelineImpl::RequestPlay, weak_pipeline_));
+}
+
+void PipelineImpl::RendererWrapper::RequestPause() {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  main_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&PipelineImpl::RequestPause, weak_pipeline_));
+}
+
+void PipelineImpl::RendererWrapper::RequestResume() {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  main_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&PipelineImpl::RequestResume, weak_pipeline_));
+}
 #endif
 
 void PipelineImpl::RendererWrapper::CreateRendererInternal(
@@ -2486,6 +2508,21 @@ void PipelineImpl::SetVideoVisibility(bool visible) {
       base::BindOnce(&RendererWrapper::SetVideoVisibility,
                      base::Unretained(renderer_wrapper_.get()), visible));
 }
+
+void PipelineImpl::RequestPlay() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  client_->RequestPlay();
+}
+
+void PipelineImpl::RequestPause() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  client_->RequestPause();
+}
+
+void PipelineImpl::RequestResume() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  client_->RequestResume();
+}
 #endif
 
 #if defined(TIZEN_MULTIMEDIA)
index a3d7c9ee784e1b1c30d4ec4f8888a3bb5cd48dd7..d4b0e8a649380698e4686c2c0e6e0d1799bd11a1 100644 (file)
@@ -210,6 +210,10 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
   void OnInitData(const std::vector<unsigned char>& init_data);
   void SetHasEncryptedListenerOrCdm(bool value) override;
   void SetVideoVisibility(bool visible) override;
+
+  void RequestPlay();
+  void RequestPause();
+  void RequestResume();
 #endif
   void OnBufferingStateChange(BufferingState state,
                               BufferingStateChangeReason reason);
index d42ad5630cea60f436eb9f13c76b11e4204d483f..8bdb79926d426cefe0f7b2cb316fdd6ec19430c4 100644 (file)
@@ -51,6 +51,10 @@ class MEDIA_EXPORT RendererClient {
   virtual void OnMrsUrlChange(const std::string& url){};
   virtual void OnContentIdChange(const std::string& id){};
   virtual void OnInitData(const std::vector<unsigned char>& init_data){};
+
+  virtual void RequestPlay(){}
+  virtual void RequestPause(){}
+  virtual void RequestResume(){}
 #endif
 
   // Executed when buffering state is changed. |reason| indicates the cause of
index 4184d33e32c245df5ab571fed0159f5add141664..1f74e6bfa88b05f97c6d14c30b6998e503086595 100644 (file)
@@ -113,6 +113,15 @@ interface MediaPlayerRendererClientExtension {
 
   [EnableIf=is_tizen_tv]
   OnContentIdChange(string id);
+
+  [EnableIf=is_tizen_tv]
+  RequestPlay();
+
+  [EnableIf=is_tizen_tv]
+  RequestPause();
+
+  [EnableIf=is_tizen_tv]
+  RequestResume();
 };
 
 // Extension of the mojo::Renderer communication layer for HLS and Android
index 72c9c43a09f576638cf144af1afd3d75c55002e9..fa4200069adc06abdb5a8653b80afa135af15a2c 100644 (file)
@@ -419,7 +419,6 @@ class WebMediaPlayer {
   virtual void SetActiveAudioTrack(int) {}
   virtual void SetActiveVideoTrack(int) {}
   virtual void SetPreferTextLanguage(const std::string&) {}
-  virtual int GetVideoId() { return 0; }
   virtual bool RegisterTimeline(const std::string& timeline_selector) {
     return false;
   }
index fd3c23ebb5bf2ef59f25cce2950a8ad837c3dd17..d05ed91b1b55c0c3d03b917124419ed9323805a9 100644 (file)
@@ -2943,6 +2943,23 @@ void WebMediaPlayerImpl::OnInitData(
   OnEncryptedMediaInitData(media::EmeInitDataType::CENC, init_data);
 }
 
+void WebMediaPlayerImpl::RequestPlay() {
+  client_->ResumePlayback();
+}
+
+void WebMediaPlayerImpl::RequestPause() {
+  client_->PausePlayback(WebMediaPlayerClient::PauseReason::kUnknown);
+}
+
+void WebMediaPlayerImpl::RequestResume() {
+  if (!pipeline_controller_->IsSuspended()) {
+    LOG(INFO) << __func__ << " Already resumed.";
+    return;
+  }
+  was_suspended_by_player_ = false;
+  Resume();
+}
+
 void WebMediaPlayerImpl::SetVideoVisibility(bool visible) {
   return pipeline_controller_->SetVideoVisibility(visible);
 }
@@ -3247,6 +3264,10 @@ void WebMediaPlayerImpl::OnRequestSuspend(bool resource_conflicted) {
 #endif
   client_->PausePlayback(WebMediaPlayerClient::PauseReason::kUnknown);
   client_->SuspendPlayer();
+
+#if BUILDFLAG(IS_TIZEN_TV)
+  UpdatePlayState();
+#endif
 }
 
 void WebMediaPlayerImpl::FullscreenModeToggled() {
@@ -4022,6 +4043,9 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(
 
   LOG(INFO) << __func__ << ": must_suspend=" << must_suspend
             << ", idle_suspended=" << idle_suspended
+#if defined(TIZEN_MULTIMEDIA)
+            << ", was_suspended_by_player_=" << was_suspended_by_player_
+#endif
             << ", background_suspended=" << background_suspended
             << ", can_stay_suspended=" << can_stay_suspended
             << ", is_stale=" << is_stale
index 33459cd01f54907b7cc47470ef3ecd19443e0750..0f243554c0a1edfb359327ba62bb048bcf668e6d 100644 (file)
@@ -250,6 +250,10 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   void OnMrsUrlChange(const std::string& url) override;
   void OnContentIdChange(const std::string& id) override;
   void OnInitData(const std::vector<unsigned char>& init_data) override;
+
+  void RequestPlay() override;
+  void RequestPause() override;
+  void RequestResume() override;
 #endif
 
 #if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
index bda799c1fc82f6401a9df76be099a5585ce44067..0a1241601f3a1e67cef30ffe23e97f466fbf411e 100644 (file)
@@ -1008,6 +1008,30 @@ void TizenRendererImpl::OnInitData(
   if (client_)
     client_->OnInitData(init_data);
 }
+
+void TizenRendererImpl::RequestPlay() {
+  if (client_extension_) {
+    client_extension_->RequestPlay();
+  }
+}
+
+void TizenRendererImpl::RequestPause() {
+  if (client_extension_) {
+    client_extension_->RequestPause();
+  }
+}
+
+void TizenRendererImpl::RequestResume() {
+  if (client_extension_) {
+    client_extension_->RequestResume();
+  }
+  media_player_->SetVolume(volume_);
+}
+
+void TizenRendererImpl::OnVideoRect(const gfx::RectF& video_rect) {
+  SetMediaGeometry(video_rect, media::VIDEO_ROTATION_0);
+}
+
 #endif
 
 void TizenRendererImpl::OnSeekableTimeChange(base::TimeDelta min_time,
index 834bd203bb74375c0bd15189fa2520f69edd1ef9..df713ecf5a2c3c9588a0109460836a80ff5033bd 100644 (file)
@@ -154,6 +154,11 @@ class CONTENT_EXPORT TizenRendererImpl
   void OnLivePlaybackComplete() override;
   content::WebContentsDelegate* GetWebContentsDelegate() const override;
   void OnInitData(const std::vector<unsigned char>& init_data) override;
+
+  void RequestPlay() override;
+  void RequestPause() override;
+  void RequestResume() override;
+  void OnVideoRect(const gfx::RectF& video_rect) override;
 #endif
 #if defined(TIZEN_TBM_SUPPORT)
   void OnNewTbmFrameAvailable(uint32_t player_id,
index 2ff171c7fe5b20e624949eefd899c838051500ff..5b59cc3d733c9776bf7d4e719ef41422875e3bde 100644 (file)
@@ -206,6 +206,21 @@ void MediaPlayerRendererClient::OnContentIdChange(const std::string& id) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
   client_->OnContentIdChange(id);
 }
+
+void MediaPlayerRendererClient::RequestPlay() {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  client_->RequestPlay();
+}
+
+void MediaPlayerRendererClient::RequestPause() {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  client_->RequestPause();
+}
+
+void MediaPlayerRendererClient::RequestResume() {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  client_->RequestResume();
+}
 #endif
 
 void MediaPlayerRendererClient::OnNewFrameAvailable(
index 1b1a7792f54c113349eb3ec543278ea98c9016b5..a68fe5fc89f5f639268c6ff5f53412d703699561 100644 (file)
@@ -81,6 +81,10 @@ class CONTENT_EXPORT MediaPlayerRendererClient
                             int sync) override;
   void OnMrsUrlChange(const std::string& url) override;
   void OnContentIdChange(const std::string& id) override;
+
+  void RequestPlay() override;
+  void RequestPause() override;
+  void RequestResume() override;
 #endif
   void OnVideoSizeChange(const gfx::Size& size) override;
   void OnBufferUpdate(base::TimeDelta time) override;
index 8567710a101a6ebecf4d48f400dcc0bad1f2b449..470a662b194fa3bf6e7eea56e0cce9ce85555bc2 100644 (file)
@@ -175,6 +175,9 @@ class TizenEsPlusPlayerRenderer final
                             int sync) override {}
   void OnMrsUrlChange(const std::string& url) override {}
   void OnContentIdChange(const std::string& id) override {}
+  void RequestPlay() override {}
+  void RequestPause() override {}
+  void RequestResume() override {}
 #if defined(ENABLE_AUTO_ZOOM)
   void SetAiZoomSettings(const media::TizenAiZoomSettings& settings);
 #endif  // defined(ENABLE_AUTO_ZOOM)
index a06da314b17086a8a55d6a2c1930d294363bbf6a..1dd3be5ed645b5315fb9710949ac32ebb767f3cb 100644 (file)
 
 #include "base/logging.h"
 #include "base/no_destructor.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "media/base/efl/media_player_util_efl.h"
 #include "media/base/video_codecs.h"
+#include "media/filters/hardware_resource_types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "tizen_src/chromium_impl/media/filters/esplusplayer_util.h"
 #include "tizen_src/chromium_impl/tizen/tizen_tv_platform.h"
 
@@ -87,7 +88,6 @@ DecoderStatePtr HardwareResourceHelper::GetSuitableResource(
   }
   std::vector<DecoderStatePtr> available_states;
   std::string chipset = GetTVChipset();
-  absl::optional<DecoderType> override_last_decoder;
   for (auto& state : decoder_states_) {
     const auto decoder_descriptor = state->GetVideoDescriptor();
     if(!decoder_descriptor) {
@@ -148,7 +148,6 @@ DecoderStatePtr HardwareResourceHelper::GetSuitableResource(
       if(fps > 60) {
         if (state->GetDecoderType(kMainDecoder)) {
           state->SetRequiresBothDecoders(true);
-          override_last_decoder = kSubDecoder;
           available_states.clear();
           available_states.push_back(state);
           LOG(INFO) << "HFR on Pontus/NikeM2 does not support dual decode for > 60FPS";
@@ -194,7 +193,6 @@ DecoderStatePtr HardwareResourceHelper::GetSuitableResource(
         LOG(INFO) << "Previous last used decoder "
                   << DecoderTypeToString(last_used_decoder_) << " new decoder "
                   << DecoderTypeToString(state->GetDecoderType());
-        last_used_decoder_ = override_last_decoder.value_or(state->GetDecoderType(kDecoders));
         return state;
       }
       LOG(INFO) << "Broadcast in use ? " << broadcast_in_use;
@@ -213,7 +211,6 @@ DecoderStatePtr HardwareResourceHelper::GetSuitableResource(
         LOG(INFO) << "Previous last used decoder "
                   << DecoderTypeToString(last_used_decoder_) << " new decoder "
                   << DecoderTypeToString(state->GetDecoderType());
-        last_used_decoder_ = override_last_decoder.value_or(state->GetDecoderType(kDecoders));
         return state;
       }
       if (!available_states.empty()) {
@@ -225,7 +222,6 @@ DecoderStatePtr HardwareResourceHelper::GetSuitableResource(
     default:
       for (auto& state : available_states) {
         if (state->IsAcquired() == false) {
-          last_used_decoder_ = override_last_decoder.value_or(state->GetDecoderType(kDecoders));
           return state;
         }
       }
@@ -236,7 +232,6 @@ DecoderStatePtr HardwareResourceHelper::GetSuitableResource(
 DecoderStatePtr HardwareResourceHelper::GetResource(DecoderType type) {
   for (auto& state : decoder_states_) {
     if (state->GetDecoderType(type) == type) {
-      last_used_decoder_ = state->GetDecoderType();
       return state;
     }
   }
@@ -267,13 +262,18 @@ void HardwareResourceHelper::SetReleased(DecoderStatePtr state,
   }
 }
 
-void HardwareResourceHelper::SetAcquired(DecoderType dec,
+void HardwareResourceHelper::SetAcquired(DecoderType dec_flag,
                                          DecoderOwner new_owner) {
-  for (auto& state : decoder_states_) {
-    if (state->GetDecoderType(kDecoders) == (dec & kDecoders)) {
-      LOG(INFO) << "Set acquired on decoder: " << DecoderTypeToString(dec);
-      SetAcquired(state, new_owner);
-      return;
+  for (auto dec : {kMainDecoder, kSubDecoder}) {
+    if ((dec & dec_flag) == 0)
+      continue;
+
+    for (auto& state : decoder_states_) {
+      if (state->GetDecoderType(kDecoders) == dec) {
+        LOG(INFO) << "Set acquired on decoder: " << DecoderTypeToString(dec);
+        SetAcquired(state, new_owner);
+        break;
+      }
     }
   }
 }
@@ -288,6 +288,10 @@ void HardwareResourceHelper::SetAcquired(DecoderStatePtr state,
       state->Owner().Suspend();
     }
     state->Acquire(true, new_owner);
+
+    if (!new_owner.IsOwnerTheSame(DecoderOwner(BroadcastOwnsDecoder()))) {
+      last_used_decoder_ = state->GetDecoderType(kDecoders);
+    }
   }
 }
 
@@ -301,6 +305,10 @@ bool HardwareResourceHelper::IsDualDecoding() {
   return (decoder_states_.size() == 2);
 }
 
+bool HardwareResourceHelper::IsAnyDecoderAcquiredByBroadcast() const {
+  return broadcast_decoder_ != kNoneDecoder;
+}
+
 DecoderStatePtr HardwareResourceHelper::GetFHDDecoder(DecoderType type) {
   return DecoderStatePtr(new DecoderState(new VideoDecoderDescriptor(
       type | kFHDDecoder, kFHDWidth, kFHDHeight, kMaxFPS,
index 2d5919a0f8d24a1034e636c12bcb4c548243ba42..d50675a7974b79830b957fd9240bb677e0e58edf 100644 (file)
@@ -140,6 +140,8 @@ class HardwareResourceHelper {
   void HandleBroadcastDecoder(int broadcast_decoder);
   bool IsDualDecoding();
 
+  bool IsAnyDecoderAcquiredByBroadcast() const;
+
   static DecoderStatePtr GetUHDDecoder(DecoderType type);
   static DecoderStatePtr GetFHDDecoder(DecoderType type);
   static DecoderStatePtr GetFHDDecoderKantSU2e(DecoderType type);
index 398b10fbcb85f8874176a07efceffd56668e5509..c2d46903f915c08ecc8fb3c3e878ba77d9e399f4 100644 (file)
@@ -1083,7 +1083,9 @@ void MediaPlayerESPlusPlayer::PerformOperationForData() {
   switch (operation) {
     case OperationForData::PLAY:
       is_paused_by_buffering_ = false;
-      Play();
+      if (!is_paused_) {
+        Play();
+      }
       break;
     case OperationForData::PAUSE:
       is_paused_by_buffering_ = true;
@@ -1189,12 +1191,6 @@ void MediaPlayerESPlusPlayer::OnPrepareComplete(bool result) {
     return;
   }
 
-  if (!result) {
-    LOG_ID(ERROR, player_id_) << "OnPrepareComplete prepare_async failed.";
-    GetMediaPlayerClient()->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
-    return;
-  }
-
   if (GetPlayerState() != ESPLUSPLAYER_STATE_READY) {
     LOG_ID(ERROR, player_id_)
         << "Invalid state (" << GetString(GetPlayerState())
@@ -1202,6 +1198,12 @@ void MediaPlayerESPlusPlayer::OnPrepareComplete(bool result) {
     return;
   }
 
+  if (!result) {
+    LOG_ID(ERROR, player_id_) << "OnPrepareComplete prepare_async failed.";
+    GetMediaPlayerClient()->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
+    return;
+  }
+
   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
                            << __func__ << " is_paused_ : " << is_paused_
                            << " seek_position : " << seek_position_
index c5c367868a6d03a240ec923ebfd0935392b43eee..0aebd9ea0eae7658f1468deb4770c4882d84b6d9 100644 (file)
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_switches.h"
 #include "media/base/renderer_client.h"
+#include "media/filters/hardware_resource_types.h"
+#include "third_party/blink/public/platform/web_application_type.h"
 #include "tizen/system_info.h"
 #include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h"
 
 #include <drmdecrypt_api.h>
 #include <malloc.h>
 #include <player_internal.h>
+#include <array>
 #include <ivideo-dp-control.hpp>
 
 // define constant for mse timeline.
 #define TIMELINESTATE 3
 #define TIMELINEPAUSED true
 
+namespace {
+
+std::pair<uint32_t, uint32_t> GetHBBTvTAResolution(uint32_t width,
+                                                   uint32_t height) {
+  // NOTE: HBBTV TA requires to play two videos on two different scalers at the
+  //        same time. To achive this behavior we limit maximal resolution to
+  //        the value which always allow two HW decoder playbacks.
+  return {std::min(static_cast<uint32_t>(kFHDVideoMaxWidth), width),
+          std::min(static_cast<uint32_t>(kFHDVideoMaxHeight), height)};
+}
+
 // malloc_trim(0) will be called every 2 minutes.
 const base::TimeDelta kMallocTrimInterval = base::TimeDelta::FromSeconds(120);
 
+// Only for HBBTV TA
+// Estimated pulling ZOrder interval time, to proceed a fastswitch.
+const base::TimeDelta kHbbTVZorderCheckInterval = base::Milliseconds(500);
+}  // namespace
+
 namespace media {
+
 // Limit of platform player's total (audio and video) buffer size
 // for encrypted content in bytes
 const media::player_buffer_size_t kDRMPlayerTotalBufferSize = 10 * 1024 * 1024;
@@ -124,7 +144,7 @@ void MediaPlayerESPlusPlayerTV::InitializeStreamConfig(
     return;
   }
 
-  if (type == DemuxerStream::AUDIO && use_sw_audio_decoder_) {
+  if (type == DemuxerStream::AUDIO && UseSwAudioDecoding()) {
     SetSwAudioDecoder();
   }
 
@@ -132,9 +152,20 @@ void MediaPlayerESPlusPlayerTV::InitializeStreamConfig(
 }
 
 bool MediaPlayerESPlusPlayerTV::Play() {
-  auto td_ptr = suitable_decoder_.lock();
   auto dec_name = content::kNoneDecoder;
+
+  auto td_ptr = suitable_decoder_.lock();
   if (td_ptr) {
+    if (blink::IsHbbTV() /* && decoder_conflict_ */ && !IsPrepared()) {
+      DemuxerStream* stream = GetDemuxerStream(media::DemuxerStream::VIDEO);
+      if (stream) {
+        VideoDecoderConfig video_config = stream->video_decoder_config();
+        ChooseDecoderIfNeeded(video_config.codec(), true /* ignore_conflict */);
+        MediaPlayerESPlusPlayer::Prepare();
+        MediaPlayerESPlusPlayer::Play();
+        return true;
+      }
+    }
     dec_name = td_ptr->GetDecoderType();
     SetDecoderAcquired(td_ptr->GetDecoderType());
   }
@@ -217,19 +248,120 @@ void MediaPlayerESPlusPlayerTV::Prepare() {
   PrepareAIZoom();
 #endif  // defined(ENABLE_AUTO_ZOOM)
 
-  if (blink::IsHbbTV() && !decoder_assigned_) {
+  if (blink::IsHbbTV()) {
+    // 1. Check if main decoder might be prepared without conflicting.
+    // 2. If 4K cannot be allocated, just delay preparing when |Play|
+    //    or |PrepareToMediaSwitch| is called.
     DemuxerStream* stream = GetDemuxerStream(media::DemuxerStream::VIDEO);
     if (stream) {
       VideoDecoderConfig video_config = stream->video_decoder_config();
       ChooseDecoderIfNeeded(video_config.codec());
-      if (auto td_ptr = suitable_decoder_.lock()) {
-        decoder_assigned_ = true;
-      }
+    }
+
+    if (IsHbbTvTaAllowed() && GetMediaPlayerClient()) {
+      GetMediaPlayerClient()->OnBufferingStateChange(
+          BUFFERING_HAVE_ENOUGH, BUFFERING_CHANGE_REASON_UNKNOWN);
+    }
+
+    const bool has_suitable_decoder = suitable_decoder_.lock() != nullptr;
+    if (!has_suitable_decoder || decoder_conflict_) {
+      LOG_ID(WARNING, player_id_)
+          << "Delaying |Prepare| to avoid resource conflict";
+      return;
     }
   }
+
   MediaPlayerESPlusPlayer::Prepare();
 }
 
+void MediaPlayerESPlusPlayerTV::PrepareToMediaSwitch() {
+  if (!IsHbbTvTaAllowed()) {
+    LOG_ID(ERROR, player_id_) << "HbbTV-TA is not allowed";
+    return;
+  }
+
+  LOG_ID(INFO, player_id_);
+  is_for_ta_ = true;
+
+  if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE) {
+    LOG_ID(INFO, player_id_)
+        << "Initialization order was wrong, request resume.";
+    should_trigger_ta_zorder_checking_ = true;
+    GetMediaPlayerClient()->RequestResume();
+    return;
+  }
+
+  bool has_suitable_decoder = (suitable_decoder_.lock() != nullptr);
+  if (has_suitable_decoder && !decoder_conflict_ && !CanPrepare()) {
+    LOG_ID(INFO, player_id_)
+        << "Already prepared (or still preparing), continue.";
+    StartCheckingHbbTVZOrder();
+    return;
+  }
+
+  LOG_ID(INFO, player_id_) << "Not prepared, choose decoder again and prepare.";
+  DemuxerStream* stream = GetDemuxerStream(media::DemuxerStream::VIDEO);
+  if (stream) {
+    VideoDecoderConfig video_config = stream->video_decoder_config();
+    ChooseDecoderIfNeeded(video_config.codec(), true /* ignore_conflict */);
+    auto td_ptr = suitable_decoder_.lock();
+    if (!td_ptr) {
+      LOG_ID(ERROR, player_id_) << "No decoder assigned!";
+      return;
+    }
+  }
+
+  should_trigger_ta_zorder_checking_ = true;
+  MediaPlayerESPlusPlayer::Prepare();
+}
+
+void MediaPlayerESPlusPlayerTV::RequestPlay() {
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ")";
+  if (!is_for_ta_) {
+    LOG_ID(ERROR, player_id_)
+        << "This method should be called for HbbTV-TA only";
+    return;
+  }
+
+  if (!GetMediaPlayerClient()) {
+    LOG_ID(ERROR, player_id_)
+        << "(" << static_cast<void*>(this) << ") No media player client";
+    return;
+  }
+  Play();
+  should_trigger_ta_zorder_checking_ = false;
+  StopCheckingHbbTVZOrder();
+  if (!is_ta_geometry_set_) {
+    // Setting geometry if prepare was significantly delayed.
+    is_ta_geometry_set_ = true;
+    GetMediaPlayerClient()->OnVideoRect(video_rect_);
+  }
+  ForceVideoOrder(VideoOrder::kOnTop);
+  GetMediaPlayerClient()->RequestPlay();
+}
+
+void MediaPlayerESPlusPlayerTV::RequestPause() {
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ")";
+  if (!is_for_ta_) {
+    LOG_ID(ERROR, player_id_)
+        << "This method should be called for HbbTV-TA only";
+    return;
+  }
+
+  if (!GetMediaPlayerClient()) {
+    LOG_ID(ERROR, player_id_)
+        << "(" << static_cast<void*>(this) << ") No media player client";
+    return;
+  }
+  GetMediaPlayerClient()->RequestPause();
+  ForceVideoOrder(VideoOrder::kOnBottom);
+}
+
+void MediaPlayerESPlusPlayerTV::SetVideoRect(const gfx::RectF& video_rect) {
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ")";
+  video_rect_ = video_rect;
+}
+
 void MediaPlayerESPlusPlayerTV::Release() {
   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
                            << __func__;
@@ -361,6 +493,11 @@ int MediaPlayerESPlusPlayerTV::SetVideoStreamInfo(
     }
   }
 
+  if (is_for_ta_) {
+    std::tie(video_stream_info.max_width, video_stream_info.max_height) =
+        GetHBBTvTAResolution(video_stream_info.width, video_stream_info.height);
+  }
+
   video_codec_ = video_config.codec();
   if (hdr_info_.compare(video_config.hdr_info()) != 0) {
     is_hdr_changed_ = true;
@@ -465,7 +602,8 @@ void MediaPlayerESPlusPlayerTV::SetTbmCallbackPolicy(
     policy = ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE;
   }
 #endif  // defined(TIZEN_MULTIMEDIA_MJPEG_SUPPORT)
-  LOG_ID(INFO, player_id_) << " Set RM policy for Tbm:" << static_cast<int>(policy);
+  LOG_ID(INFO, player_id_) << " Set RM policy for Tbm:"
+                           << static_cast<int>(policy);
 
   auto error = esplusplayer_set_resource_allocate_policy(esplayer_, policy);
   if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
@@ -919,6 +1057,11 @@ void MediaPlayerESPlusPlayerTV::OnPrepareComplete(bool result) {
     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
 
   MediaPlayerESPlusPlayer::OnPrepareComplete(result);
+
+  if (is_for_ta_ && result && should_trigger_ta_zorder_checking_) {
+    should_trigger_ta_zorder_checking_ = false;
+    StartCheckingHbbTVZOrder();
+  }
 }
 
 void MediaPlayerESPlusPlayerTV::OnError(
@@ -1243,37 +1386,32 @@ void MediaPlayerESPlusPlayerTV::PrepareAIZoom() {
 }
 #endif  // defined(ENABLE_AUTO_ZOOM)
 
-void MediaPlayerESPlusPlayerTV::SetAudioPreloading() {
-  if (!content::HardwareResourceHelper::IsAudioPreloadingSupported()) {
-    LOG_ID(INFO, GetPlayerId())
-        << "Audio preloading not available at this board";
-    return;
+void MediaPlayerESPlusPlayerTV::SetSwAudioDecoder() {
+  auto player_error = esplusplayer_set_audio_codec_type(
+      esplayer_, ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW);
+  if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+    LOG_ID(ERROR, GetPlayerId())
+        << "esplusplayer_set_audio_codec_type failed, error code "
+        << player_error;
   }
-#if TIZEN_VERSION_AT_LEAST(6, 5, 0)
-  // Setting virtual main out for SW decoder
-  const auto player_error = esplusplayer_set_audio_preloading(esplayer_);
 
+#if TIZEN_VERSION_AT_LEAST(6, 5, 0)
+  player_error = esplusplayer_set_alternative_audio_resource(
+      esplayer_, ESPLUSPLAYER_AUDIO_RESOURCE_SIMPLE_MIX_OUT);
   if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
-    LOG_ID(ERROR, GetPlayerId())
-        << "esplusplayer_set_audio_preloading failed, error code "
+    LOG_ID(INFO, GetPlayerId())
+        << "esplusplayer_set_alternative_audio_resource failed, error code: "
         << player_error;
-    return;
   }
-  audio_preloading_set_ = true;
-#else
-  LOG_ID(INFO, GetPlayerId())
-      << "Audio preloading not available at this Tizen version";
-#endif
-}
 
-void MediaPlayerESPlusPlayerTV::SetSwAudioDecoder() {
-  auto player_error = esplusplayer_set_audio_codec_type(
-      esplayer_, ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW);
+  player_error = esplusplayer_set_simple_mix_out_buffer_level(
+      esplayer_, ESPLUSPLAYER_SIMPLE_MIX_OUT_BUFFER_HIGH);
   if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
-    LOG_ID(ERROR, GetPlayerId())
-        << "esplusplayer_set_audio_codec_type failed, error code "
+    LOG_ID(INFO, GetPlayerId())
+        << "esplusplayer_set_simple_mix_out_buffer_level failed, error code: "
         << player_error;
   }
+#endif
 }
 
 void MediaPlayerESPlusPlayerTV::SetHwAudioDecoder() {
@@ -1286,9 +1424,16 @@ void MediaPlayerESPlusPlayerTV::SetHwAudioDecoder() {
   }
 }
 
-void MediaPlayerESPlusPlayerTV::ChooseDecoderIfNeeded(VideoCodec codec) {
+void MediaPlayerESPlusPlayerTV::ChooseDecoderIfNeeded(VideoCodec codec,
+                                                      bool ignore_conflict) {
   if (!blink::IsHbbTV())
     return;
+  if (auto td_ptr = suitable_decoder_.lock())
+    SetDecoderReleased(td_ptr->GetDecoderType());
+
+  // Prevent checking ZOrder for invalid decoder.
+  StopCheckingHbbTVZOrder();
+
   content::WebContentsDelegate* contents_delegate =
       GetMediaPlayerClient()->GetWebContentsDelegate();
   if (contents_delegate != nullptr)
@@ -1300,59 +1445,77 @@ void MediaPlayerESPlusPlayerTV::ChooseDecoderIfNeeded(VideoCodec codec) {
   auto fps = static_cast<int>(framerate);
   const auto max_resolution =
       GetMaxResolution(capi_media_format_video_.mime_type, is_video_hole_);
-  const auto max_width = max_resolution.width();
-  const auto max_height = max_resolution.height();
+  auto max_width = max_resolution.width();
+  auto max_height = max_resolution.height();
+  if (is_for_ta_) {
+    std::tie(max_width, max_height) =
+        GetHBBTvTAResolution(max_width, max_height);
+  }
   suitable_decoder_ =
       content::HardwareResourceHelper::Get().GetSuitableResource(
           media::MediaType::Video, content::HWAquirePolicy::SWITCH, max_width,
           max_height, fps, codec);
-  if (auto td_ptr = suitable_decoder_.lock()) {
-    auto dec_name = td_ptr->GetDecoderType();
-#if TIZEN_VERSION_AT_LEAST(6, 0, 0)
-    if ((dec_name & content::kSubDecoder) == content::kSubDecoder) {
-      LOG_ID(INFO, player_id_) << "SUB decoder is used for this " << this;
-      // 1 = set all video resources(decoder/scaler) to sub resources
-      esplusplayer_set_alternative_video_resource(esplayer_, 1);
-      // Setting SW audio decoder for SUB video decoder content.
-      if (contents_delegate && contents_delegate->UseSwAudioDecoding()) {
-        LOG_ID(INFO, player_id_)
-            << "SW audio decoder is used for this " << this;
-        SetSwAudioDecoder();
-      }
-    } else if ((dec_name & content::kMainDecoder) == content::kMainDecoder) {
-      LOG_ID(INFO, player_id_) << "MAIN decoder is used for this " << this;
-      // 0 = set all video resources(decoder/scaler) to main resources
-      esplusplayer_set_alternative_video_resource(esplayer_, 0);
-      // If using SW audio decoding is possible. HW audio decoder
-      // should be explicitly used for MAIN decoder.
-      if (contents_delegate && contents_delegate->UseSwAudioDecoding()) {
-        LOG_ID(INFO, player_id_)
-            << "HW audio decoder is used for this " << this;
-        SetHwAudioDecoder();
-      }
-    } else {
-      LOG_ID(ERROR, GetPlayerId()) << "CANNOT USE ANY VIDEO DECODER";
-    }
-    // Setting virtual main out for both main and sub players.
-    if (contents_delegate && contents_delegate->UseSwAudioDecoding()) {
-      SetAudioPreloading();
+
+  auto td_ptr = suitable_decoder_.lock();
+
+  if (!td_ptr) {
+    LOG_ID(ERROR, GetPlayerId()) << "No suitable decoder found";
+    return;
+  }
+
+  // NOTE: Broadcast always uses HW, so we need to avoid also audio conflicts
+  const bool is_hw_audio_conflicted = GetMediaType() & MediaType::Audio &&
+                                      content::HardwareResourceHelper::Get()
+                                          .IsAnyDecoderAcquiredByBroadcast() &&
+                                      !UseSwAudioDecoding();
+  decoder_conflict_ = td_ptr->IsAcquired() || is_hw_audio_conflicted;
+  if (decoder_conflict_) {
+    LOG_ID(INFO, player_id_) << "Conflict:"
+                             << " audio_conflicted=" << is_hw_audio_conflicted
+                             << " video_conflicted=" << td_ptr->IsAcquired();
+    if (!ignore_conflict) {
+      LOG_ID(ERROR, player_id_)
+          << "Selected decoder but it's already acquired.";
+      return;
     }
+    LOG_ID(INFO, player_id_)
+        << "Selected decoder with conflict, but we're force to ignore it.";
+  }
+
+  auto dec_name = td_ptr->GetDecoderType();
+#if TIZEN_VERSION_AT_LEAST(6, 0, 0)
+  constexpr int kAllResourcesForMain = 0;
+  constexpr int kAllResourcesForSub = 1;
+  if ((dec_name & content::kSubDecoder) == content::kSubDecoder) {
+    LOG_ID(INFO, player_id_) << "SUB decoder is used for this " << this;
+    // 1 = set all video resources(decoder/scaler) to sub resources
+    esplusplayer_set_alternative_video_resource(esplayer_, kAllResourcesForSub);
+  } else if ((dec_name & content::kMainDecoder) == content::kMainDecoder) {
+    LOG_ID(INFO, player_id_) << "MAIN decoder is used for this " << this;
+    // 0 = set all video resources(decoder/scaler) to main resources
+    esplusplayer_set_alternative_video_resource(esplayer_,
+                                                kAllResourcesForMain);
+  } else {
+    LOG_ID(ERROR, GetPlayerId()) << "CANNOT USE ANY VIDEO DECODER";
+  }
+
+  // Setting SW audio decoder and audio output with mixer.
+  if (UseSwAudioDecoding()) {
+    LOG_ID(INFO, player_id_) << "SW audio decoder is used for this " << this;
+    SetSwAudioDecoder();
+  }
 #endif
-    decoder_conflict_ = td_ptr->IsAcquired();
-    if (!decoder_conflict_) {
-      // is_notification_playback_ready_delayed_ = true;
-      bool media_resource_acquired = false;
-      GetMediaPlayerClient()->NotifyPlaybackState(
-          kPlaybackVideoReady, GetPlayerId(), "", "", &media_resource_acquired,
-          NULL, NULL, dec_name);
-      if (!media_resource_acquired) {
-        LOG_ID(INFO, GetPlayerId()) << "HbbTV media resource was not acquired";
-        return;
-      }
 
-      SetDecoderAcquired(dec_name);
-    }
+  bool media_resource_acquired = false;
+  GetMediaPlayerClient()->NotifyPlaybackState(
+      kPlaybackVideoReady, GetPlayerId(), "", "", &media_resource_acquired,
+      NULL, NULL, dec_name);
+  if (!media_resource_acquired) {
+    LOG_ID(INFO, GetPlayerId()) << "HbbTV media resource was not acquired";
+    return;
   }
+
+  SetDecoderAcquired(dec_name);
 }
 
 void MediaPlayerESPlusPlayerTV::SetDecoderAcquired(
@@ -1405,8 +1568,7 @@ bool MediaPlayerESPlusPlayerTV::DeactivateAudioStreamIfNeeded() {
       player_error = esplusplayer_deactivate_audio(esplayer_);
       if (player_error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
         LOG_ID(ERROR, player_id_)
-          << "Deactivate audio failed, error code "
-          << player_error;
+            << "Deactivate audio failed, error code " << player_error;
         return false;
       }
       audio_stream_activated_ = false;
@@ -1451,16 +1613,44 @@ bool MediaPlayerESPlusPlayerTV::ActivateAudioStreamIfNeeded() {
 #endif
 }
 
+void MediaPlayerESPlusPlayerTV::ForceVideoOrder(VideoOrder videoOrder) {
+#if defined(TIZEN_VIDEO_HOLE) && TIZEN_VERSION_AT_LEAST(6, 0, 0)
+  auto decoder = suitable_decoder_.lock();
+  if (!decoder) {
+    return;
+  }
+
+  std::array<IVideoDpControl::PlaneZOrder, 2> order;
+  if (videoOrder == VideoOrder::kOnTop)
+    order = {IVideoDpControl::DP_PLANE_MSB, IVideoDpControl::DP_PLANE_SMB};
+  else
+    order = {IVideoDpControl::DP_PLANE_SMB, IVideoDpControl::DP_PLANE_MSB};
+
+  const auto dec_type = decoder->GetDecoderType(content::kDecoders);
+  errno_t ret{};
+  switch (dec_type) {
+    case content::kMainDecoder:
+      ret = IVideoDpControl::getInstance()->setZorder(order.at(0));
+      break;
+    case content::kSubDecoder:
+      ret = IVideoDpControl::getInstance()->setZorder(order.at(1));
+      break;
+    default:
+      LOG_ID(ERROR, player_id_) << "Decoder not distinguished:" << dec_type;
+  }
+  if (ret) {
+    LOG_ID(WARNING, player_id_) << "SetZOrder failed with error: " << ret;
+  }
+#endif
+}
+
 #if defined(TIZEN_VIDEO_HOLE)
 void MediaPlayerESPlusPlayerTV::SetVideoVisibility(bool visible) {
-  if (!blink::IsHbbTV() || !is_video_hole_)
+  if (!blink::IsHbbTV() || !is_video_hole_ || is_for_ta_)
     return;
 
 #if TIZEN_VERSION_AT_LEAST(6, 0, 0)
   if (auto td_ptr = suitable_decoder_.lock()) {
-    if (td_ptr->GetDecoderType(content::kDecoders) == content::kMainDecoder &&
-        td_ptr->GetDecoderType(content::kResolutions) == content::kFHDDecoder)
-      return;
     auto dec_type = td_ptr->GetDecoderType(content::kDecoders);
     const unsigned int kFullVisibility = 255;
     const unsigned int kNoVisibility = 0;
@@ -1482,4 +1672,97 @@ void MediaPlayerESPlusPlayerTV::SetVideoVisibility(bool visible) {
 }
 #endif
 
+bool MediaPlayerESPlusPlayerTV::IsHbbTvTaAllowed() const {
+  // HbbTV Targeted Advertisement is allowed only when SW audio decoding is set.
+  return blink::IsHbbTV() && UseSwAudioDecoding();
+}
+
+void MediaPlayerESPlusPlayerTV::StartCheckingHbbTVZOrder() {
+  if (!is_for_ta_) {
+    return;
+  }
+  if (hbbtv_zorder_checker_timer_.IsRunning())
+    return;
+
+  LOG_ID(INFO, player_id_) << __func__;
+  is_ta_geometry_set_ = false;
+  hbbtv_zorder_checker_timer_.Start(
+      FROM_HERE, kHbbTVZorderCheckInterval, this,
+      &MediaPlayerESPlusPlayerTV::OnCheckingHbbtvTVZorder);
+}
+
+void MediaPlayerESPlusPlayerTV::StopCheckingHbbTVZOrder() {
+  if (!hbbtv_zorder_checker_timer_.IsRunning())
+    return;
+
+  LOG_ID(INFO, player_id_) << __func__;
+  hbbtv_zorder_checker_timer_.Stop();
+}
+
+void MediaPlayerESPlusPlayerTV::OnCheckingHbbtvTVZorder() {
+  if (is_ta_geometry_set_)
+    return;
+
+  auto decoder = suitable_decoder_.lock();
+  if (!decoder) {
+    LOG_ID(WARNING, player_id_) << "No suitable decoder";
+    return;
+  }
+
+  constexpr int kMainPlane = 0;
+  constexpr int kSubPlane = 1;
+  int expected_zorder_on_top;
+  const auto dec_type = decoder->GetDecoderType(content::kDecoders);
+  if ((dec_type & content::kDecoders) == content::kSubDecoder) {
+    expected_zorder_on_top = kSubPlane;
+  } else if ((dec_type & content::kDecoders) == content::kMainDecoder) {
+    expected_zorder_on_top = kMainPlane;
+  } else {
+    LOG_ID(WARNING, player_id_)
+        << "Cannot understand a decoder type: " << dec_type;
+    return;
+  }
+
+  constexpr size_t kZOrderRawMinimalLength = 8;
+  unsigned char order[kZOrderRawMinimalLength];
+  auto error = IVideoDpControl::getInstance()->getZorderRaw(order);
+  if (error) {
+    LOG_ID(WARNING, player_id_) << "Cannot acquire ZORDER: " << strerror(error);
+    return;
+  }
+
+  auto ToText = [](int plane) -> std::string {
+    switch (plane) {
+      case kMainPlane:
+        return "MAIN-SUB-BG";
+      case kSubPlane:
+        return "SUB-MAIN-BG";
+      default:
+        return "UNACCEPTED";
+    }
+  };
+
+  LOG_ID(INFO, player_id_) << "ZOrder=" << ToText(order[0])
+                           << " expected=" << ToText(expected_zorder_on_top);
+
+  if (expected_zorder_on_top == order[0]) {
+    LOG_ID(INFO, player_id_)
+        << "ZOrder updated. Changing a geometry in advance.";
+    is_ta_geometry_set_ = true;
+    hbbtv_zorder_checker_timer_.Stop();
+    ForceVideoOrder(VideoOrder::kOnBottom);
+    GetMediaPlayerClient()->OnVideoRect(video_rect_);
+  }
+}
+
+bool MediaPlayerESPlusPlayerTV::UseSwAudioDecoding() const {
+  content::WebContentsDelegate* contents_delegate =
+      GetMediaPlayerClient()->GetWebContentsDelegate();
+  if (!contents_delegate) {
+    LOG_ID(ERROR, player_id_) << "Invalid web contents delegate";
+    return false;
+  }
+  return contents_delegate->UseSwAudioDecoding();
+}
+
 }  // namespace media
index e705c22cf34f5791424dc3686cceb543de7e667a..36733ef512305c1029e972439e5357b88ca26068 100644 (file)
@@ -87,13 +87,20 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer {
       const media::VideoDecoderConfig& video_config) override;
   void InitializeStreamConfig(DemuxerStream::Type type) override;
   bool SetBufferType(const media::VideoDecoderConfig&) override;
-  void SetAudioPreloading();
   void SetHwAudioDecoder();
   void SetSwAudioDecoder();
-  void ChooseDecoderIfNeeded(media::VideoCodec codec);
   void SetTbmCallbackPolicy(const media::VideoDecoderConfig& video_config);
+  void ChooseDecoderIfNeeded(media::VideoCodec codec,
+                             bool ignore_conflict = false);
+
+  void PrepareToMediaSwitch() override;
+  void RequestPlay() override;
+  void RequestPause() override;
+  void SetVideoRect(const gfx::RectF& video_rect) override;
 
  private:
+  enum class VideoOrder { kOnTop, kOnBottom };
+
 #if TIZEN_VERSION_AT_LEAST(6, 0, 0)
   class DrmInfo {
    public:
@@ -141,6 +148,14 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer {
   bool DeactivateAudioStreamIfNeeded();
   bool ActivateAudioStreamIfNeeded();
 
+  void ForceVideoOrder(VideoOrder videoOrder);
+  bool IsHbbTvTaAllowed() const;
+  bool UseSwAudioDecoding() const;
+
+  void StartCheckingHbbTVZOrder();
+  void StopCheckingHbbTVZOrder();
+  void OnCheckingHbbtvTVZorder();
+
 #if defined(ENABLE_AUTO_ZOOM)
   void PrepareAIZoom();
 #endif  // defined(ENABLE_AUTO_ZOOM)
@@ -150,9 +165,6 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer {
   media::PipelineStatistics stats_;
 
   bool enable_tbm_buffer_callback_{false};
-  bool use_sw_audio_decoder_{false};
-  bool use_sw_video_decoder_{false};
-  bool audio_preloading_set_{false};
   bool decoder_conflict_{true};
   int cb_frame_width_{0};
   int cb_frame_height_{0};
@@ -162,12 +174,17 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayerTV : public MediaPlayerESPlusPlayer {
   bool is_video_drm_eme_{false};
   media::VideoCodec video_codec_{media::VideoCodec::kUnknown};
   std::weak_ptr<content::DecoderState> suitable_decoder_;
-  bool decoder_assigned_{false};
   esplusplayer_video_stream_info capi_media_format_video_;
   base::RepeatingTimer current_time_update_timer_;
   base::RepeatingTimer malloc_trim_timer;
+  base::RepeatingTimer hbbtv_zorder_checker_timer_;
   bool audio_stream_activated_{true};
 
+  gfx::RectF video_rect_;
+  bool is_for_ta_{false};
+  bool is_ta_geometry_set_{false};
+  bool should_trigger_ta_zorder_checking_{false};
+
 #if defined(ENABLE_AUTO_ZOOM)
   std::unique_ptr<AIZoomManager> ai_zoom_manager_;
   std::optional<media::TizenAiZoomSettings> ai_zoom_settings_;
index 27e9b524696b019ee5b9be2b7a8d1eb1602d3320..c075e15a0931019bd0f11182b1b467799b304e7d 100644 (file)
@@ -195,6 +195,10 @@ class MEDIA_EXPORT MediaPlayerTizen
 #if BUILDFLAG(IS_TIZEN_TV)
   virtual void SetDecryptorHandle(eme::eme_decryptor_t decryptor) {}
   virtual void SetHasEncryptedListenerOrCdm(bool value) {}
+  virtual void PrepareToMediaSwitch() {}
+  virtual void RequestPlay() {}
+  virtual void RequestPause() {}
+  virtual void SetVideoRect(const gfx::RectF& video_rect) {}
   virtual void SetVideoVisibility(bool visible) {}
 #endif
 };
index 685c61718ff6c670556a951b41cd967e856b6b29..dbf77db5f602eadaefd29de0e862e10cafd6eff1 100644 (file)
@@ -93,6 +93,11 @@ class MEDIA_EXPORT MediaPlayerTizenClient {
   virtual void OnLivePlaybackComplete() = 0;
   virtual content::WebContentsDelegate* GetWebContentsDelegate() const = 0;
   virtual void OnInitData(const std::vector<unsigned char>& init_data) = 0;
+
+  virtual void RequestPlay();
+  virtual void RequestPause();
+  virtual void RequestResume();
+  virtual void OnVideoRect(const gfx::RectF& video_rect);
 #endif
 };
 
index 3d2260251bc048df76a573d32f7fd5b2276c04a3..3eec61c4ae6c307d2d866024432cc2be34a58fa6 100644 (file)
 #include "public/ewk_media_subtitle_info_product.h"
 #include "public/ewk_user_media_internal.h"
 #include "third_party/blink/public/platform/web_media_player.h"
+#include "tizen_src/chromium_impl/media/filters/hardware_resource_helper.h"
+#include "tizen_src/chromium_impl/media/filters/media_player_registry.h"
 #endif
 
 #if defined(TIZEN_PEPPER_EXTENSIONS)
@@ -141,6 +143,7 @@ const char kReplaceChars[] = " ";
 const char kReplaceWith[] = "_";
 #if BUILDFLAG(IS_TIZEN_TV)
 static const int kMousePressAndHoldTimeout = 500;  // long press: 500ms
+const int kBroadcastPlayerId = 0;
 #endif
 
 #if BUILDFLAG(IS_TIZEN_DA)
@@ -4271,9 +4274,9 @@ std::vector<std::string> EWebView::NotifyPlaybackState(
   Ewk_Media_Playback_Info* playback_info =
       ewkMediaPlaybackInfoCreate(player_id, url, mime_type, decoder);
 
-  LOG(INFO)
-      << "player_id:" << player_id << ",state: " << state
-      << "(0-load : 1-videoready : 2-ready : 3-start : 4-finish : 5-stop)";
+  LOG(INFO) << "player_id:" << player_id << ",state: " << state
+            << "(0-load : 1-videoready : 2-ready : 3-start : 4-finish : 5-stop)"
+            << ", decoder: " << static_cast<int>(decoder);
   switch (state) {
     case kPlaybackLoad:
       SmartCallback<EWebViewCallbacks::PlaybackLoad>().call(
@@ -4362,6 +4365,74 @@ void EWebView::NotifyMediaDeviceConnectionChanged(int device_type) {
   SmartCallback<EWebViewCallbacks::DeviceConnectionChanged>().call(
       &device_type);
 }
+
+void EWebView::SetNextPlayerForMediaSwitch(int player_id) {
+  LOG(INFO) << player_id;
+  if (!UseSwAudioDecoding()) {
+    LOG(ERROR) << "This method should be used for HbbTV-TA only";
+    return;
+  }
+
+  if (player_id == kBroadcastPlayerId) {
+    auto resource = content::HardwareResourceHelper::Get().GetResource(
+        content::kMainDecoder);
+    if (resource) {
+      resource->Owner().Suspend();
+    }
+    return;
+  }
+
+  auto player =
+      media::MediaPlayerRegistry::GetInstance()->GetMediaPlayer(player_id);
+  if (!player) {
+    LOG(ERROR) << "Player with id " << player_id << " is not found";
+    return;
+  }
+  player->PrepareToMediaSwitch();
+}
+
+void EWebView::VideoPlay(int player_id) {
+  LOG(INFO) << player_id;
+  if (!UseSwAudioDecoding()) {
+    LOG(ERROR) << "This method should be used for HbbTV-TA only";
+    return;
+  }
+
+  auto player =
+      media::MediaPlayerRegistry::GetInstance()->GetMediaPlayer(player_id);
+  if (!player) {
+    LOG(ERROR) << "Player with id " << player_id << " is not found";
+    return;
+  }
+  player->RequestPlay();
+}
+
+void EWebView::VideoPause(int player_id) {
+  LOG(INFO) << player_id;
+  if (!UseSwAudioDecoding()) {
+    LOG(ERROR) << "This method should be used for HbbTV-TA only";
+    return;
+  }
+
+  auto player =
+      media::MediaPlayerRegistry::GetInstance()->GetMediaPlayer(player_id);
+  if (!player) {
+    LOG(ERROR) << "Player with id " << player_id << " is not found";
+    return;
+  }
+  player->RequestPause();
+}
+
+void EWebView::SetVideoGeometry(int x, int y, int w, int h) {
+  if (!UseSwAudioDecoding()) {
+    LOG(ERROR) << "This method should be used for HbbTV-TA only";
+    return;
+  }
+
+  for (auto p : media::MediaPlayerRegistry::GetInstance()->GetMediaPlayers()) {
+    p.second->SetVideoRect(gfx::RectF(x, y, w, h));
+  }
+}
 #endif
 
 void EWebView::SetIMEWindow(void* window) {
index 632408d8b6afe3e3dd1f935314c038bcc2bfffb3..9c0220774fc8d60715b55f74e1d54c4ac2ba0d54 100644 (file)
@@ -911,6 +911,11 @@ class EWebView {
                                uint32_t previous,
                                uint32_t current);
   void NotifyMediaDeviceConnectionChanged(int device_type);
+
+  void SetNextPlayerForMediaSwitch(int player_id);
+  void VideoPlay(int player_id);
+  void VideoPause(int player_id);
+  void SetVideoGeometry(int x, int y, int w, int h);
 #endif  // IS_TIZEN_TV
 
   void SetScriptsCanOpenWindows(bool);
index da61610d603988334c7b3159435c3c8f6d9666d2..9421e476106be29f5945adebf950e7022b0ed811 100644 (file)
@@ -65,6 +65,9 @@
 #include "tizen_src/chromium_impl/base/tizen/resource_manager.h"
 #include "tizen_src/chromium_impl/ui/ozone/platform/efl/efl_window.h"
 #endif
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "tizen_src/chromium_impl/tizen/tizen_tv_platform.h"
+#endif
 
 static Eina_Bool _ewk_view_default_user_media_permission(
     Evas_Object*, Ewk_User_Media_Permission_Request*, void*);
@@ -1343,21 +1346,63 @@ Eina_Bool ewk_view_set_custom_device_pixel_ratio(Evas_Object* ewkView, Eina_Bool
 Ewk_Board_Decoding_Capabilities ewk_view_board_decoding_capabilities_get(
   const Evas_Object* view)
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  // This one should be moved into HbbTV code.
+  auto DecodingCapabilities = []() -> Ewk_Board_Decoding_Capabilities {
+    const std::string chipset = GetTVChipset();
+    const ResourceTableIndex rt_idx = GetResourceTableIndex();
+    // 1x FHD decoder: KantS2
+    // 1x UHD decoder: NikeL 1.5G
+    if (chipset == "KANTS2" || rt_idx == ResourceTableIndex::DTV_NIKEL_1_5G) {
+      LOG(INFO) << "It is low-end board, do not use dual decoding";
+      return EWK_BOARD_DECODING_CAPABILITIES_SINGLE;
+    }
+    // 2x FHD decoder: KantSU2E
+    if (chipset == "KANTSU2E") {
+      LOG(INFO) << "It is KantSU2e, use 2x FHD decoders";
+      return EWK_BOARD_DECODING_CAPABILITIES_DOUBLE_FHD;
+    }
+    // 1x UHD, 1x FHD decoder: other boards
+    LOG(INFO) << "It is " << chipset << ", rt idx is "
+              << static_cast<int>(rt_idx) << ", use both decoders";
+    return EWK_BOARD_DECODING_CAPABILITIES_FHD_AND_UHD;
+  };
+
+  static Ewk_Board_Decoding_Capabilities board_decoding_capabilities =
+      DecodingCapabilities();
+  return board_decoding_capabilities;
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
   return EWK_BOARD_DECODING_CAPABILITIES_UNKNOWN;
+#endif
 }
 
 void ewk_view_next_player_for_media_switch_set(
   Evas_Object* view,
   int player_id)
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  LOG(INFO) << "Notify about media switch, next player id: " << player_id;
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl);
+  impl->SetNextPlayerForMediaSwitch(player_id);
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
+#endif  // BUILDFLAG(IS_TIZEN_TV)
 }
 
-void ewk_view_sw_audio_decoding_set(
-  Evas_Object* view,
-  Eina_Bool use_sw_audio_decoder)
-{
+void ewk_view_sw_audio_decoding_set(Evas_Object* view,
+                                    Eina_Bool use_sw_audio_decoder) {
+#if BUILDFLAG(IS_TIZEN_TV)
+  LOG(INFO) << "Use sw audio decoding: "
+            << static_cast<bool>(use_sw_audio_decoder);
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl);
+  impl->SetUseSwAudioDecoding(use_sw_audio_decoder);
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
+#endif  // BUILDFLAG(IS_TIZEN_TV)
+}
+
+void ewk_view_sw_audio_volume(Evas_Object* view, double volume) {
   LOG_EWK_API_MOCKUP();
 }
 
@@ -1365,7 +1410,14 @@ void ewk_view_set_video_geometry(
   Evas_Object* view,
   Eina_Rectangle v_area)
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  LOG(INFO) << "Notify about geometry: " << v_area.x << ", " << v_area.y << " "
+            << v_area.w << "x" << v_area.h;
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl);
+  impl->SetVideoGeometry(v_area.x, v_area.y, v_area.w, v_area.h);
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
+#endif  // BUILDFLAG(IS_TIZEN_TV)
 }
 
 void ewk_view_release_players(
@@ -1399,14 +1451,26 @@ void ewk_view_player_play(
   Evas_Object* view,
   int video_id)
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  LOG(INFO) << "Video play: " << video_id;
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl);
+  impl->VideoPlay(video_id);
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
+#endif  // BUILDFLAG(IS_TIZEN_TV)
 }
 
 void ewk_view_player_pause(
   Evas_Object* view,
   int video_id)
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  LOG(INFO) << "Video pause: " << video_id;
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl);
+  impl->VideoPause(video_id);
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
+#endif  // BUILDFLAG(IS_TIZEN_TV)
 }
 
 
index 9c4b42635ce5686dec25c0a9442e73d0bd087926..7da7468a2ea2bdd81c1a085e7002375b08bba8f2 100644 (file)
@@ -831,6 +831,13 @@ EXPORT_API void ewk_view_broadcast_decoder_set(Evas_Object* view,
 EXPORT_API void ewk_view_sw_audio_decoding_set(Evas_Object* view,
   Eina_Bool use_sw_audio_decoder);
 
+/**
+ * Sets volume for player using sw decoder
+ * @param view View object
+ * @param volume value of volume level, range 0.0 - 1.0
+ */
+EXPORT_API void ewk_view_sw_audio_volume(Evas_Object* view, double volume);
+
 /**
  * Set visibility of video with player_id
  *