[M120 Migration][MM] Handle media playback with buffering state. 78/305478/3
authorSun-woo Nam <sunny.nam@samsung.com>
Fri, 2 Feb 2024 05:08:23 +0000 (21:08 -0800)
committerBot Blink <blinkbot@samsung.com>
Fri, 16 Feb 2024 09:37:07 +0000 (09:37 +0000)
This patch migrates patches to handle playback behaviors with buffering state.

- Pause video when buffered data is not enough.
Pause video when buffered data is not enough to play.
And play video again when enough data is pushed.
This patch fixes audio loss after network is disabled and reconnected.
https://review.tizen.org/gerrit/#/c/300705/
https://review.tizen.org/gerrit/#/c/301096/
https://review.tizen.org/gerrit/#/c/301303/

- Trigger waiting event to APP
Report kReadyStateHaveCurrentData when no data to decoder.
https://review.tizen.org/gerrit/#/c/303941/

Change-Id: I2b0c6161628dfb987b326f34e6b2539ab5b26f87
Signed-off-by: Sun-woo Nam <sunny.nam@samsung.com>
tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer_impl.cc
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h

index ea4e847..64a7f8b 100644 (file)
@@ -59,8 +59,8 @@ void ESPlusPlayerBufferObserverImpl::SetBufferSize(DemuxerStream::Type type,
 }
 
 void ESPlusPlayerBufferObserverImpl::SetBufferingCallback(
-    const BufferingCallback& handler) {
-  buffering_callback_ = handler;
+    const BufferingCallback& buffering_callback) {
+  buffering_callback_ = buffering_callback;
 }
 
 void ESPlusPlayerBufferObserverImpl::SetEos(DemuxerStream::Type type) {
@@ -85,6 +85,7 @@ void ESPlusPlayerBufferObserverImpl::UpdateBufferedSize(
               << GetBuffer(DemuxerStream::VIDEO).buffer_percent << "%"
               << "\tAUDIO: " << GetBuffer(DemuxerStream::AUDIO).buffer_percent
               << "%";
+
 #if BUILDFLAG(IS_TIZEN_TV)
   // The buffer is controlled in time domain, however we want to stop
   // pushing data in case of size overflow as well
index 2739d4a..605ceb9 100644 (file)
@@ -27,6 +27,10 @@ namespace media {
 // Wait until there is space in the buffer.
 const base::TimeDelta kBufferQueueReadDelay = base::Milliseconds(100);
 
+// The difference between the played timestamp and
+// the time stamp of the buffered data.
+const base::TimeDelta kMinWaitTimeForPlayback = base::Milliseconds(500);
+
 player_buffer_size_t GetMaxAudioBufferSize() {
   return kPlayerAudioBufferSize;
 }
@@ -726,6 +730,8 @@ void MediaPlayerESPlusPlayer::ReadBuffer(DemuxerStream::Type type) {
   if (!ReadFromBufferQueue(type))
     return;
 
+  PerformOperationForData();
+
   // Avoid unnecessary or redundant read requests.
   if (!ShouldFeed(type) || ReadRequested(type) || IsEos(type) ||
       (is_prepared_ && is_paused_ && !is_seeking_)) {
@@ -877,9 +883,8 @@ void MediaPlayerESPlusPlayer::UpdateBufferedDtsDifference() {
 
 void MediaPlayerESPlusPlayer::OnBufferingStatusChanged(DemuxerStream::Type type,
                                                        BufferStatus status) {
-  DVLOG(INFO) << __func__ << " " << DemuxerStream::GetTypeName(type) << " : "
-              << GetString(status);
-
+  LOG(INFO) << __func__ << " " << DemuxerStream::GetTypeName(type) << " : "
+            << GetString(status);
   if (expected_seek_ && is_prepared_) {
     LOG(INFO) << "Ignore the buffer updates while seek";
     return;
@@ -915,6 +920,87 @@ void MediaPlayerESPlusPlayer::OnBufferingStatusChanged(DemuxerStream::Type type,
   }
 }
 
+void MediaPlayerESPlusPlayer::PerformOperationForData() {
+  if (is_seeking_ || is_preparing_)
+    return;
+
+  OperationForData operation = GetOperationForData();
+  switch (operation) {
+    case OperationForData::PLAY:
+      is_paused_by_buffering_ = false;
+      Play();
+      break;
+    case OperationForData::PAUSE:
+      is_paused_by_buffering_ = true;
+      Pause(true);
+      break;
+  }
+}
+
+MediaPlayerESPlusPlayer::OperationForData
+MediaPlayerESPlusPlayer::GetOperationForData() {
+  bool has_video_media_type = GetMediaType() & MediaType::Video;
+  bool has_audio_media_type = GetMediaType() & MediaType::Audio;
+
+  bool has_video_data =
+      !has_video_media_type ||
+      (last_frames_.get<DemuxerStream::VIDEO>().first != media::kNoTimestamp);
+  bool has_audio_data =
+      !has_audio_media_type ||
+      (last_frames_.get<DemuxerStream::AUDIO>().first != media::kNoTimestamp);
+  if (!has_video_data || !has_audio_data) {
+    LOG(INFO) << __func__
+              << " Video or audio data has not yet been pushed. video "
+              << has_video_data << ", audio " << has_audio_data;
+    return OperationForData::NONE;
+  }
+
+  base::TimeDelta current_position = GetCurrentTime();
+
+  if (is_paused_by_buffering_) {
+    // Get the end position of pushed data.
+    base::TimeDelta pushed_end_position =
+        std::min(has_video_media_type
+                     ? last_frames_.get<DemuxerStream::VIDEO>().first +
+                           last_frames_.get<DemuxerStream::VIDEO>().second
+                     : base::TimeDelta::Max(),
+                 has_audio_media_type
+                     ? last_frames_.get<DemuxerStream::AUDIO>().first +
+                           last_frames_.get<DemuxerStream::AUDIO>().second
+                     : base::TimeDelta::Max());
+    base::TimeDelta time_diff = pushed_end_position - current_position;
+
+    // If data has been pushed enough (>= kMinWaitTimeForPlayback)
+    if (time_diff >= kMinWaitTimeForPlayback) {
+      LOG(INFO) << __func__ << " Data is enough to play,";
+      return OperationForData::PLAY;
+    }
+  } else {
+    bool should_pause = false;
+    if (has_video_media_type &&
+        current_position >= last_frames_.get<DemuxerStream::VIDEO>().first) {
+      SetBufferingState(DemuxerStream::VIDEO, BUFFERING_HAVE_NOTHING);
+      should_pause = true;
+    }
+    if (has_audio_media_type &&
+        current_position >= last_frames_.get<DemuxerStream::AUDIO>().first) {
+      SetBufferingState(DemuxerStream::AUDIO, BUFFERING_HAVE_NOTHING);
+      should_pause = true;
+    }
+
+    if (should_pause) {
+      LOG(INFO) << __func__ << " Not enough data to play.";
+      // If pushing pts smaller than current_position, should report
+      // BUFFERING_HAVE_NOTHING to replace BUFFERING_HAVE_ENOUGH
+      GetMediaPlayerClient()->OnBufferingStateChange(
+          BUFFERING_HAVE_NOTHING, BUFFERING_CHANGE_REASON_UNKNOWN);
+      return OperationForData::PAUSE;
+    }
+  }
+
+  return OperationForData::NONE;
+}
+
 void MediaPlayerESPlusPlayer::OnReadyToPrepare(
     const esplusplayer_stream_type stream_type) {
   if (!task_runner_->BelongsToCurrentThread()) {
index 40bf0d0..a8257f6 100644 (file)
@@ -40,6 +40,12 @@ const media::player_buffer_size_t kPlayerAudioBufferSize = 768 * 1024;
 // This class handles media source extensions for CAPI port.
 class MEDIA_EXPORT MediaPlayerESPlusPlayer : public MediaPlayerTizen {
  public:
+  enum class OperationForData {
+    NONE,
+    PAUSE,
+    PLAY,
+  };
+
   MediaPlayerESPlusPlayer();
   ~MediaPlayerESPlusPlayer() override;
 
@@ -164,6 +170,9 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayer : public MediaPlayerTizen {
   void SeekInternal(base::TimeDelta time);
   void UpdateBufferedDtsDifference();
 
+  void PerformOperationForData();
+  OperationForData GetOperationForData();
+
   ElementryStream& GetElementryStream(DemuxerStream::Type type);
   const ElementryStream& GetElementryStream(DemuxerStream::Type type) const;
   void SetReadRequested(DemuxerStream::Type type, bool value);
@@ -190,6 +199,8 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayer : public MediaPlayerTizen {
 
   bool should_set_playback_rate_ = false;
 
+  bool is_paused_by_buffering_ = false;
+
 #if defined(TIZEN_VIDEO_HOLE)
   gfx::Rect viewport_rect_;
   std::unique_ptr<VideoPlaneController> video_plane_controller_;