Index: chromecast/media/cma/backend/media_sink_default.cc |
diff --git a/chromecast/media/cma/backend/media_sink_default.cc b/chromecast/media/cma/backend/media_sink_default.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..61d58c62d7c602bc896c46013172c73af5277e4b |
--- /dev/null |
+++ b/chromecast/media/cma/backend/media_sink_default.cc |
@@ -0,0 +1,89 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chromecast/media/cma/backend/media_sink_default.h" |
+ |
+#include "base/bind.h" |
+#include "base/location.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "chromecast/public/media/cast_decoder_buffer.h" |
+#include "media/base/timestamp_constants.h" |
+ |
+namespace chromecast { |
+namespace media { |
+ |
+MediaSinkDefault::MediaSinkDefault( |
+ MediaPipelineBackend::Decoder::Delegate* delegate, |
+ base::TimeDelta start_pts) |
+ : delegate_(delegate), |
+ time_interpolator_(&tick_clock_), |
+ playback_rate_(1.0f), |
+ last_frame_pts_(start_pts), |
+ received_eos_(false) { |
+ DCHECK(delegate_); |
+ time_interpolator_.SetPlaybackRate(playback_rate_); |
+ time_interpolator_.SetBounds(start_pts, start_pts, tick_clock_.NowTicks()); |
+ time_interpolator_.StartInterpolating(); |
+} |
+ |
+MediaSinkDefault::~MediaSinkDefault() {} |
+ |
+void MediaSinkDefault::SetPlaybackRate(float rate) { |
+ DCHECK_GE(rate, 0.0f); |
+ playback_rate_ = rate; |
+ time_interpolator_.SetPlaybackRate(playback_rate_); |
+ |
+ // Changing the playback rate affects the delay after which EOS callback |
+ // should run. Reschedule the task according to the new delay. |
+ if (received_eos_) { |
+ eos_task_.Cancel(); |
+ ScheduleEndOfStreamTask(); |
+ } |
+} |
+ |
+base::TimeDelta MediaSinkDefault::GetCurrentPts() { |
+ return time_interpolator_.GetInterpolatedTime(); |
+} |
+ |
+MediaPipelineBackend::BufferStatus MediaSinkDefault::PushBuffer( |
+ CastDecoderBuffer* buffer) { |
+ if (buffer->end_of_stream()) { |
+ received_eos_ = true; |
+ ScheduleEndOfStreamTask(); |
+ return MediaPipelineBackend::kBufferSuccess; |
+ } |
+ |
+ // This is wrong on several levels. |
+ // 1. The correct PTS should be buffer->timestamp() + buffer->duration(). |
+ // But CastDecoderBuffer does not expose duration unlike |
+ // ::media::DecoderBuffer. |
+ // 2. The PTS reported by GetCurrentPts should not move backwards. |
+ // It should be clamped in the range [start_pts, last_frame_pts_]. |
+ // But doing so makes several AudioVideoPipelineDeviceTest cases fail. |
+ // Those tests are wrong should be fixed. |
+ // TODO(alokp): Fix these issues when the next version of CMA backend is |
+ // scheduled to roll out. crbug.com/678394 |
+ last_frame_pts_ = base::TimeDelta::FromMicroseconds(buffer->timestamp()); |
+ time_interpolator_.SetUpperBound(last_frame_pts_); |
+ return MediaPipelineBackend::kBufferSuccess; |
+} |
+ |
+void MediaSinkDefault::ScheduleEndOfStreamTask() { |
+ DCHECK(received_eos_); |
+ DCHECK(eos_task_.IsCancelled()); |
+ |
+ // Do not schedule if playback is paused. |
+ if (playback_rate_ == 0.0f) |
+ return; |
+ |
+ eos_task_.Reset( |
+ base::Bind(&MediaPipelineBackend::Decoder::Delegate::OnEndOfStream, |
+ base::Unretained(delegate_))); |
+ base::TimeDelta delay = (last_frame_pts_ - GetCurrentPts()) / playback_rate_; |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, eos_task_.callback(), delay); |
+} |
+ |
+} // namespace media |
+} // namespace chromecast |