[HBBTV] Handle double seek - pause content until second seek 89/315789/6
authorKajetan Brzuszczak <k.brzuszczak@partner.samsung.com>
Wed, 31 Jul 2024 10:40:38 +0000 (12:40 +0200)
committerj.gajownik2 <j.gajownik2@samsung.com>
Wed, 7 Aug 2024 17:47:50 +0000 (19:47 +0200)
[KONA*] DF240624-01142 [PreCert][SCL][TV][24_OSU_TV(23_KantSU2e)][Italy][TivuSat][SelfTC]The beginning of the advertisement(mid roll) is re-played while playback live content and DRM VOD.

[Problem]
Double seek impacts a playback behavior. On low-end devices, such
  KantSU2e, it is possible for user to observe gap between seeks
  and eventually playing the same frames twice

[Solution]
Track double seeks, and pause player until second seeks is recepted.

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

tizen_src/chromium_impl/media/filters/media_player_bridge_capi.h
tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.cc
tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.h

index cbf128205cf20f144ce5838a9c69a52f67641458..e90eda2bc7493d66b3606e17a4da2da7500150a6 100644 (file)
@@ -182,7 +182,7 @@ class MEDIA_EXPORT MediaPlayerBridgeCapi : public MediaPlayerTizen {
   virtual void OnResumeComplete(bool success);
   virtual void HandleBufferingStatus(int percent);
 
-  void SeekInternal(base::TimeDelta time);
+  virtual void SeekInternal(base::TimeDelta time);
   void StartBufferingUpdateTimer();
   void StopCurrentTimeUpdateTimer();
 
index 82607964f8e7304ff8d1dd42d9f76d906107f1ad..23fe9650b2e9263b6b733ce85d029cc78ca7d3f0 100644 (file)
@@ -6,6 +6,7 @@
 #include "base/command_line.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_split.h"
+#include "base/time/time.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "ewk/efl_integration/common/content_switches_efl.h"
 #include "media/base/efl/media_player_util_efl.h"
@@ -403,6 +404,7 @@ void MediaPlayerBridgeCapiTV::Resume() {
 }
 
 void MediaPlayerBridgeCapiTV::Release() {
+  was_paused_before_.reset();
   is_preloaded_ = false;
   player_prepared_ = false;
   if (player_released_) {
@@ -487,11 +489,84 @@ void MediaPlayerBridgeCapiTV::Release() {
   }
 }
 
+void MediaPlayerBridgeCapiTV::TrackDoubleSeek(base::TimeDelta pts) {
+  if (!blink::IsHbbTV()) {
+    return;
+  }
+
+  const bool is_paused = is_paused_;
+  switch (seek_state_) {
+    case SeekState::kNone:
+    case SeekState::kSecondSeekComplete:
+      Pause(false);
+      was_paused_before_ = is_paused;
+      seek_state_pts_ = pts;
+      seek_state_ = SeekState::kFirstSeek;
+      break;
+    case SeekState::kFirstSeekComplete:
+      if (seek_state_pts_.has_value() && seek_state_pts_.value() == pts) {
+        seek_state_ = SeekState::kSecondSeek;
+        break;
+      }
+      LOG_ID(ERROR, player_id_)
+          << "Unexpected flow for double seek, wrong pts=" << pts;
+      RestorePlaybackSeekState();
+      seek_state_ = SeekState::kNone;
+      break;
+    case SeekState::kFirstSeek:
+    case SeekState::kSecondSeek:
+      LOG_ID(ERROR, player_id_) << "Unexpected flow for double seek";
+      RestorePlaybackSeekState();
+      seek_state_ = SeekState::kNone;
+      break;
+  }
+}
+
+void MediaPlayerBridgeCapiTV::TrackDoubleSeekCompleted() {
+  if (!blink::IsHbbTV()) {
+    return;
+  }
+
+  switch (seek_state_) {
+    case SeekState::kNone:
+    case SeekState::kSecondSeekComplete:
+    case SeekState::kFirstSeekComplete:
+      LOG_ID(ERROR, player_id_) << "Unexpected flow for double seek";
+      RestorePlaybackSeekState();
+      seek_state_ = SeekState::kNone;
+      break;
+    case SeekState::kFirstSeek:
+      seek_state_ = SeekState::kFirstSeekComplete;
+      break;
+    case SeekState::kSecondSeek:
+      RestorePlaybackSeekState();
+      seek_state_ = SeekState::kSecondSeekComplete;
+      break;
+  }
+}
+
+void MediaPlayerBridgeCapiTV::RestorePlaybackSeekState() {
+  if (!blink::IsHbbTV()) {
+    return;
+  }
+
+  if (!was_paused_before_.value_or(true)) {
+    Play();
+  }
+  seek_state_pts_.reset();
+  was_paused_before_.reset();
+}
+
+void MediaPlayerBridgeCapiTV::SeekInternal(base::TimeDelta time) {
+  TrackDoubleSeek(time);
+  MediaPlayerBridgeCapi::SeekInternal(time);
+}
+
 bool MediaPlayerBridgeCapiTV::Play() {
   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
                            << __func__
                            << ",current_time:" << GetCurrentTime().InSecondsF();
-
+  was_paused_before_.reset();
   if (IsPlayerSuspended()) {
     is_play_pending_ = true;
     LOG_ID(INFO, GetPlayerId()) << "Player is suspended";
@@ -621,6 +696,7 @@ bool MediaPlayerBridgeCapiTV::Play() {
 }
 
 void MediaPlayerBridgeCapiTV::Pause(bool is_media_related_action) {
+  was_paused_before_.reset();
   if (!player_prepared_ || is_resuming_) {
     delayed_player_state_ = PLAYER_STATE_DELAYED_PAUSE;
     return;
@@ -660,6 +736,7 @@ void MediaPlayerBridgeCapiTV::RequestSuspend(bool resource_conflicted) {
     return;
   }
 
+  RestorePlaybackSeekState();
   if (GetMediaPlayerClient())
     GetMediaPlayerClient()->OnRequestSuspend(resource_conflicted);
   MediaPlayerBridgeCapi::Suspend();
@@ -713,6 +790,10 @@ void MediaPlayerBridgeCapiTV::Seek(base::TimeDelta time,
         << "(" << static_cast<void*>(this) << ") "
         << " stashing pending seek - " << time.InSecondsF() << "s";
 
+    // NOTE: Stashing seek prevents double seek. This would require to use
+    //      a queue to store seeks and handle them one after another.
+    RestorePlaybackSeekState();
+
     if(delayed_player_state_ == PLAYER_STATE_DELAYED_PLAY ||
        delayed_player_state_ == PLAYER_STATE_DELAYED_SEEK_THEN_PLAY)
       delayed_player_state_ = PLAYER_STATE_DELAYED_SEEK_THEN_PLAY;
@@ -734,7 +815,7 @@ void MediaPlayerBridgeCapiTV::Seek(base::TimeDelta time,
   }
 
   LOG_ID(INFO, player_id_) << "SeekInternal";
-  MediaPlayerBridgeCapi::SeekInternal(time);
+  SeekInternal(time);
 
   LOG_ID(INFO, player_id_) << "NotifySubtitleState seek start";
   NotifySubtitleState(blink::WebMediaPlayer::kSubtitleSeekStart,
@@ -929,6 +1010,7 @@ void MediaPlayerBridgeCapiTV::OnTimeUpdate(int player_id,
 }
 
 void MediaPlayerBridgeCapiTV::SeekCompleteUpdate() {
+  TrackDoubleSeekCompleted();
   MediaPlayerBridgeCapi::SeekCompleteUpdate();
   NotifySubtitleState(blink::WebMediaPlayer::kSubtitleSeekComplete);
 
@@ -3922,5 +4004,6 @@ bool MediaPlayerBridgeCapiTV::CompleteDrmInit(int& drmhandle) {
   waiting_for_drm_init_complete_ = false;
   return (decryptor_ != 0);
 }
+
 #endif
 }  // namespace media
index b3cc10b11e80df1a584c9b200515577185a63357..a379698998654b6c270ed398c260d6d09d4d4ea1 100644 (file)
@@ -7,8 +7,10 @@
 
 #include <emeCDM/IEME.h>
 #include <player_product.h>
+#include <string>
 
 #include "base/synchronization/condition_variable.h"
+#include "base/time/time.h"
 #include "media/filters/hardware_resource_helper.h"
 #include "media/filters/media_player_bridge_capi.h"
 #include "tizen_src/chromium_impl/build/tizen_version.h"
@@ -50,6 +52,14 @@ enum TrackAction {
   DEL_INBAND_TEXT_TRACK,
 };
 
+enum class SeekState {
+  kNone,
+  kFirstSeek,
+  kFirstSeekComplete,
+  kSecondSeek,
+  kSecondSeekComplete
+};
+
 #if defined(TIZEN_VD_NGA)
 struct AudioPreselectionInfos {
   std::string id;
@@ -207,6 +217,11 @@ class MEDIA_EXPORT MediaPlayerBridgeCapiTV : public MediaPlayerBridgeCapi {
     return is_player_reload_by_mixer_;
   };
 
+  void TrackDoubleSeek(base::TimeDelta pts);
+  void TrackDoubleSeekCompleted();
+  void RestorePlaybackSeekState();
+
+  void SeekInternal(base::TimeDelta time) override;
   bool ActivateAudioStreamIfNeeded();
   bool DeactivateAudioStreamIfNeeded();
   bool ActivateAudioStream();
@@ -381,6 +396,10 @@ class MEDIA_EXPORT MediaPlayerBridgeCapiTV : public MediaPlayerBridgeCapi {
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<MediaPlayerBridgeCapiTV> weak_factory_;
 
+  SeekState seek_state_ = SeekState::kNone;
+  absl::optional<bool> was_paused_before_;
+  absl::optional<base::TimeDelta> seek_state_pts_;
+
   bool has_encrypted_listener_or_cdm_{false};
   // Flag indicating that has_encrypted_listener_or_cdm_ has been changed.
   bool encrypted_listener_or_cdm_has_changed_{false};