| Index: media/renderers/video_renderer_impl.cc
|
| diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
|
| index c6902976272cad8a0a1d0c3e88d49c994559e292..0f40607ce152e82e844d63b62dd14cbfea062dfd 100644
|
| --- a/media/renderers/video_renderer_impl.cc
|
| +++ b/media/renderers/video_renderer_impl.cc
|
| @@ -21,6 +21,7 @@
|
| #include "media/base/media_switches.h"
|
| #include "media/base/pipeline_status.h"
|
| #include "media/base/renderer_client.h"
|
| +#include "media/base/stream_position.h"
|
| #include "media/base/video_frame.h"
|
| #include "media/renderers/gpu_video_accelerator_factories.h"
|
| #include "media/video/gpu_memory_buffer_video_frame_pool.h"
|
| @@ -51,6 +52,7 @@ VideoRendererImpl::VideoRendererImpl(
|
| pending_read_(false),
|
| drop_frames_(drop_frames),
|
| buffering_state_(BUFFERING_HAVE_NOTHING),
|
| + start_rendering_from_first_frame_(false),
|
| frames_decoded_(0),
|
| frames_dropped_(0),
|
| tick_clock_(new base::DefaultTickClock()),
|
| @@ -116,8 +118,8 @@ void VideoRendererImpl::Flush(const base::Closure& callback) {
|
| algorithm_->Reset();
|
| }
|
|
|
| -void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
|
| - DVLOG(1) << __func__ << "(" << timestamp.InMicroseconds() << ")";
|
| +void VideoRendererImpl::StartPlayingFrom(StreamPosition position) {
|
| + DVLOG(1) << __func__ << "(" << ToString(position) << ")";
|
| DCHECK(task_runner_->BelongsToCurrentThread());
|
| base::AutoLock auto_lock(lock_);
|
| DCHECK_EQ(state_, kFlushed);
|
| @@ -125,7 +127,9 @@ void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
|
| DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
|
|
|
| state_ = kPlaying;
|
| - start_timestamp_ = timestamp;
|
| + start_timestamp_ = position.time;
|
| + start_rendering_from_first_frame_ =
|
| + position.kind == StreamPosition::Kind::KEY_FRAME_PRECEDING_TIME;
|
| AttemptRead_Locked();
|
| }
|
|
|
| @@ -237,10 +241,8 @@ void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
|
| return;
|
| }
|
|
|
| - // We're all good! Consider ourselves flushed. (ThreadMain() should never
|
| - // see us in the kUninitialized state).
|
| - // Since we had an initial Preroll(), we consider ourself flushed, because we
|
| - // have not populated any buffers yet.
|
| + // We're all good! Consider ourselves flushed because we have not populated
|
| + // any buffers yet.
|
| state_ = kFlushed;
|
|
|
| algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_));
|
| @@ -364,6 +366,11 @@ void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
|
| if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
|
| DCHECK(!received_end_of_stream_);
|
| received_end_of_stream_ = true;
|
| + } else if (start_rendering_from_first_frame_) {
|
| + start_timestamp_ = frame->timestamp();
|
| + start_rendering_from_first_frame_ = false;
|
| + client_->OnFirstVideoFrameTimestampKnown(frame->timestamp());
|
| + AddReadyFrame_Locked(frame);
|
| } else if ((low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) &&
|
| IsBeforeStartTime(frame->timestamp())) {
|
| // Don't accumulate frames that are earlier than the start time if we
|
| @@ -375,8 +382,9 @@ void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
|
| // If the sink hasn't been started, we still have time to release less
|
| // than ideal frames prior to startup. We don't use IsBeforeStartTime()
|
| // here since it's based on a duration estimate and we can be exact here.
|
| - if (!sink_started_ && frame->timestamp() <= start_timestamp_)
|
| + if (!sink_started_ && frame->timestamp() <= start_timestamp_) {
|
| algorithm_->Reset();
|
| + }
|
|
|
| AddReadyFrame_Locked(frame);
|
| }
|
| @@ -399,9 +407,6 @@ void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
|
| // enough frames to know it's definitely the first frame or (2) there may be
|
| // no more frames coming (sometimes unless we paint one of them).
|
| //
|
| - // For the first condition, we need at least two frames or the first frame
|
| - // must have a timestamp >= |start_timestamp_|, since otherwise we may be
|
| - // prerolling frames before the actual start time that will be dropped.
|
| if (algorithm_->frames_queued() > 1 || received_end_of_stream_ ||
|
| algorithm_->first_frame()->timestamp() >= start_timestamp_ ||
|
| low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) {
|
| @@ -415,10 +420,7 @@ void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
|
| if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked())
|
| TransitionToHaveEnough_Locked();
|
|
|
| - // Always request more decoded video if we have capacity. This serves two
|
| - // purposes:
|
| - // 1) Prerolling while paused
|
| - // 2) Keeps decoding going if video rendering thread starts falling behind
|
| + // Always request more decoded video if we have capacity.
|
| AttemptRead_Locked();
|
| }
|
|
|
| @@ -623,6 +625,8 @@ base::TimeTicks VideoRendererImpl::GetCurrentMediaTimeAsWallClockTime() {
|
| }
|
|
|
| bool VideoRendererImpl::IsBeforeStartTime(base::TimeDelta timestamp) {
|
| + if (start_rendering_from_first_frame_)
|
| + return false;
|
| return timestamp + video_frame_stream_->AverageDuration() < start_timestamp_;
|
| }
|
|
|
|
|