blob: a43ddab64283cbb22c8e5fa36a0fb34574861967 [file] [log] [blame]
[email protected]cc3933d2013-11-26 03:41:021// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]2041cf342010-02-19 03:15:592// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
[email protected]ce553ab2009-02-24 01:25:144
servolkf54f5c8f2015-02-24 20:32:395#include "media/renderers/video_renderer_impl.h"
[email protected]f7c0ada02012-07-23 08:42:506
[email protected]c369bb82011-04-27 22:45:437#include "base/bind.h"
[email protected]2041cf342010-02-19 03:15:598#include "base/callback.h"
[email protected]1192339c2012-03-24 20:37:279#include "base/callback_helpers.h"
[email protected]b639a832013-12-20 21:12:3910#include "base/location.h"
11#include "base/single_thread_task_runner.h"
[email protected]f214f8792011-01-01 02:17:0812#include "base/threading/platform_thread.h"
dalecurtis5755042e2015-03-26 20:31:2213#include "base/time/default_tick_clock.h"
ssid9525f4672015-01-28 12:13:1514#include "base/trace_event/trace_event.h"
xhwangbe9da702014-08-23 21:44:5515#include "media/base/bind_to_current_loop.h"
[email protected]ce553ab2009-02-24 01:25:1416#include "media/base/buffers.h"
[email protected]34d148482010-09-02 00:15:5517#include "media/base/limits.h"
[email protected]d399866c2012-01-18 09:30:3218#include "media/base/pipeline.h"
[email protected]34f993562010-03-23 22:34:2419#include "media/base/video_frame.h"
[email protected]ce553ab2009-02-24 01:25:1420
21namespace media {
22
[email protected]cc3933d2013-11-26 03:41:0223VideoRendererImpl::VideoRendererImpl(
[email protected]b639a832013-12-20 21:12:3924 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
[email protected]ddbc6ff2013-04-19 15:28:3325 ScopedVector<VideoDecoder> decoders,
xhwangff459d4e2014-09-09 04:55:4726 bool drop_frames,
27 const scoped_refptr<MediaLog>& media_log)
[email protected]b639a832013-12-20 21:12:3928 : task_runner_(task_runner),
xhwang97de4202014-11-25 08:44:0129 video_frame_stream_(
30 new VideoFrameStream(task_runner, decoders.Pass(), media_log)),
[email protected]a29fd9b2014-05-02 17:43:3731 low_delay_(false),
[email protected]6eda4e42013-02-28 21:59:5432 received_end_of_stream_(false),
[email protected]2267bfe82014-05-09 18:03:5833 rendered_end_of_stream_(false),
[email protected]1276cc162012-12-07 21:55:3334 frame_available_(&lock_),
[email protected]35458972009-07-25 02:12:1135 state_(kUninitialized),
[email protected]54e6ff82013-05-22 00:01:3836 thread_(),
[email protected]f23676a2011-11-04 02:04:0937 pending_read_(false),
[email protected]b3c471792012-03-17 01:34:2638 drop_frames_(drop_frames),
[email protected]28bc175c2014-07-01 19:39:1739 buffering_state_(BUFFERING_HAVE_NOTHING),
[email protected]f54e7682013-10-10 21:58:2640 frames_decoded_(0),
[email protected]de39b022014-03-18 21:36:2241 frames_dropped_(0),
[email protected]47affc72014-07-23 01:49:1542 is_shutting_down_(false),
dalecurtis5755042e2015-03-26 20:31:2243 tick_clock_(new base::DefaultTickClock()),
[email protected]de39b022014-03-18 21:36:2244 weak_factory_(this) {
[email protected]ce553ab2009-02-24 01:25:1445}
46
[email protected]cc3933d2013-11-26 03:41:0247VideoRendererImpl::~VideoRendererImpl() {
[email protected]47affc72014-07-23 01:49:1548 DCHECK(task_runner_->BelongsToCurrentThread());
49
50 {
51 base::AutoLock auto_lock(lock_);
52 is_shutting_down_ = true;
53 frame_available_.Signal();
54 }
55
56 if (!thread_.is_null())
57 base::PlatformThread::Join(thread_);
[email protected]5a10c792014-07-23 09:52:2058
59 if (!init_cb_.is_null())
60 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
61
62 if (!flush_cb_.is_null())
63 base::ResetAndReturn(&flush_cb_).Run();
[email protected]30ef6b3942013-02-05 00:56:2764}
65
[email protected]cc3933d2013-11-26 03:41:0266void VideoRendererImpl::Flush(const base::Closure& callback) {
scherkusa62dfabc62014-09-03 06:46:2067 DVLOG(1) << __FUNCTION__;
[email protected]b639a832013-12-20 21:12:3968 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]20305ec2011-01-21 04:55:5269 base::AutoLock auto_lock(lock_);
[email protected]28bc175c2014-07-01 19:39:1770 DCHECK_EQ(state_, kPlaying);
[email protected]a4dae8e2012-03-15 23:35:3171 flush_cb_ = callback;
[email protected]971db8c2013-07-12 01:52:3672 state_ = kFlushing;
[email protected]3d54fc62010-08-11 23:24:5873
[email protected]971db8c2013-07-12 01:52:3674 // This is necessary if the |video_frame_stream_| has already seen an end of
75 // stream and needs to drain it before flushing it.
[email protected]f8b47342013-03-27 12:20:2176 ready_frames_.clear();
[email protected]28bc175c2014-07-01 19:39:1777 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
78 buffering_state_ = BUFFERING_HAVE_NOTHING;
79 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
80 }
[email protected]f8b47342013-03-27 12:20:2181 received_end_of_stream_ = false;
[email protected]2267bfe82014-05-09 18:03:5882 rendered_end_of_stream_ = false;
[email protected]28bc175c2014-07-01 19:39:1783
[email protected]4beec402014-07-17 08:32:5284 video_frame_stream_->Reset(
[email protected]de39b022014-03-18 21:36:2285 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone,
86 weak_factory_.GetWeakPtr()));
[email protected]35458972009-07-25 02:12:1187}
88
scherkusb6f074ea2014-09-16 03:51:3289void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
90 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")";
[email protected]b639a832013-12-20 21:12:3991 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]e1d69d762011-12-13 05:12:1892 base::AutoLock auto_lock(lock_);
[email protected]28bc175c2014-07-01 19:39:1793 DCHECK_EQ(state_, kFlushed);
94 DCHECK(!pending_read_);
95 DCHECK(ready_frames_.empty());
96 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
[email protected]4b6e4a9e2013-12-04 01:11:1097
[email protected]28bc175c2014-07-01 19:39:1798 state_ = kPlaying;
scherkusb6f074ea2014-09-16 03:51:3299 start_timestamp_ = timestamp;
[email protected]e1d69d762011-12-13 05:12:18100 AttemptRead_Locked();
[email protected]ce553ab2009-02-24 01:25:14101}
102
xhwang97de4202014-11-25 08:44:01103void VideoRendererImpl::Initialize(
104 DemuxerStream* stream,
105 const PipelineStatusCB& init_cb,
106 const SetDecryptorReadyCB& set_decryptor_ready_cb,
107 const StatisticsCB& statistics_cb,
108 const BufferingStateCB& buffering_state_cb,
109 const PaintCB& paint_cb,
110 const base::Closure& ended_cb,
111 const PipelineStatusCB& error_cb,
dalecurtis5755042e2015-03-26 20:31:22112 const WallClockTimeCB& wall_clock_time_cb,
jrummell74fc4f942015-03-02 22:48:27113 const base::Closure& waiting_for_decryption_key_cb) {
[email protected]b639a832013-12-20 21:12:39114 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]20305ec2011-01-21 04:55:52115 base::AutoLock auto_lock(lock_);
[email protected]873da262012-08-10 22:02:47116 DCHECK(stream);
[email protected]873da262012-08-10 22:02:47117 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
[email protected]f7c0ada02012-07-23 08:42:50118 DCHECK(!init_cb.is_null());
[email protected]ad8b08d2012-03-10 00:38:57119 DCHECK(!statistics_cb.is_null());
[email protected]28bc175c2014-07-01 19:39:17120 DCHECK(!buffering_state_cb.is_null());
xhwang94c0bd32014-11-13 20:49:31121 DCHECK(!paint_cb.is_null());
[email protected]f7c0ada02012-07-23 08:42:50122 DCHECK(!ended_cb.is_null());
dalecurtis5755042e2015-03-26 20:31:22123 DCHECK(!wall_clock_time_cb.is_null());
[email protected]35458972009-07-25 02:12:11124 DCHECK_EQ(kUninitialized, state_);
[email protected]1f500f52009-06-22 22:23:19125
xhwang2f7e4aca2014-11-14 18:37:36126 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE);
[email protected]a29fd9b2014-05-02 17:43:37127
xhwangbe9da702014-08-23 21:44:55128 // Always post |init_cb_| because |this| could be destroyed if initialization
129 // failed.
130 init_cb_ = BindToCurrentLoop(init_cb);
131
[email protected]ad8b08d2012-03-10 00:38:57132 statistics_cb_ = statistics_cb;
[email protected]28bc175c2014-07-01 19:39:17133 buffering_state_cb_ = buffering_state_cb;
xhwang94c0bd32014-11-13 20:49:31134 paint_cb_ = paint_cb,
[email protected]f7c0ada02012-07-23 08:42:50135 ended_cb_ = ended_cb;
136 error_cb_ = error_cb;
dalecurtis5755042e2015-03-26 20:31:22137 wall_clock_time_cb_ = wall_clock_time_cb;
[email protected]a1f7ace2013-02-22 06:14:07138 state_ = kInitializing;
[email protected]4c51bc662011-02-16 02:03:16139
[email protected]4beec402014-07-17 08:32:52140 video_frame_stream_->Initialize(
xhwang97de4202014-11-25 08:44:01141 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
142 weak_factory_.GetWeakPtr()),
jrummell74fc4f942015-03-02 22:48:27143 set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
[email protected]873da262012-08-10 22:02:47144}
145
xhwangdc965d92014-12-18 23:21:11146void VideoRendererImpl::CreateVideoThread() {
147 // This may fail and cause a crash if there are too many threads created in
148 // the current process. See http://crbug.com/443291
149 CHECK(base::PlatformThread::Create(0, this, &thread_));
150
151#if defined(OS_WIN)
152 // Bump up our priority so our sleeping is more accurate.
153 // TODO(scherkus): find out if this is necessary, but it seems to help.
154 ::SetThreadPriority(thread_.platform_handle(), THREAD_PRIORITY_ABOVE_NORMAL);
155#endif // defined(OS_WIN)
156}
157
[email protected]75e145a2014-04-15 17:44:32158void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
[email protected]b639a832013-12-20 21:12:39159 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]873da262012-08-10 22:02:47160 base::AutoLock auto_lock(lock_);
[email protected]a1f7ace2013-02-22 06:14:07161 DCHECK_EQ(state_, kInitializing);
162
[email protected]84fb5a062013-03-24 04:06:44163 if (!success) {
[email protected]7004b732012-12-17 23:07:06164 state_ = kUninitialized;
165 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
[email protected]873da262012-08-10 22:02:47166 return;
167 }
168
[email protected]34d148482010-09-02 00:15:55169 // We're all good! Consider ourselves flushed. (ThreadMain() should never
[email protected]35458972009-07-25 02:12:11170 // see us in the kUninitialized state).
[email protected]de8e9b62012-07-24 19:25:17171 // Since we had an initial Preroll(), we consider ourself flushed, because we
[email protected]34d148482010-09-02 00:15:55172 // have not populated any buffers yet.
173 state_ = kFlushed;
[email protected]35458972009-07-25 02:12:11174
xhwangdc965d92014-12-18 23:21:11175 CreateVideoThread();
[email protected]1f500f52009-06-22 22:23:19176
[email protected]873da262012-08-10 22:02:47177 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
178}
179
[email protected]1f500f52009-06-22 22:23:19180// PlatformThread::Delegate implementation.
[email protected]cc3933d2013-11-26 03:41:02181void VideoRendererImpl::ThreadMain() {
[email protected]f214f8792011-01-01 02:17:08182 base::PlatformThread::SetName("CrVideoRenderer");
[email protected]3ad9d5b2011-12-22 16:43:26183
184 // The number of milliseconds to idle when we do not have anything to do.
185 // Nothing special about the value, other than we're being more OS-friendly
186 // than sleeping for 1 millisecond.
187 //
[email protected]971db8c2013-07-12 01:52:36188 // TODO(scherkus): switch to pure event-driven frame timing instead of this
[email protected]3ad9d5b2011-12-22 16:43:26189 // kIdleTimeDelta business http://crbug.com/106874
190 const base::TimeDelta kIdleTimeDelta =
191 base::TimeDelta::FromMilliseconds(10);
[email protected]d3d048772010-07-14 21:00:25192
[email protected]e58c5e332014-08-15 04:43:52193 // If we have no frames and haven't painted any frame for certain amount of
194 // time, declare BUFFERING_HAVE_NOTHING.
195 const base::TimeDelta kTimeToDeclareHaveNothing =
196 base::TimeDelta::FromSeconds(3);
197
[email protected]1f500f52009-06-22 22:23:19198 for (;;) {
[email protected]d957e432012-12-21 00:35:33199 base::AutoLock auto_lock(lock_);
200
201 // Thread exit condition.
[email protected]47affc72014-07-23 01:49:15202 if (is_shutting_down_)
[email protected]d957e432012-12-21 00:35:33203 return;
204
[email protected]3ad9d5b2011-12-22 16:43:26205 // Remain idle as long as we're not playing.
[email protected]bd22a7e2014-07-14 23:14:45206 if (state_ != kPlaying || buffering_state_ != BUFFERING_HAVE_ENOUGH) {
[email protected]f54e7682013-10-10 21:58:26207 UpdateStatsAndWait_Locked(kIdleTimeDelta);
[email protected]3ad9d5b2011-12-22 16:43:26208 continue;
[email protected]1f500f52009-06-22 22:23:19209 }
[email protected]ce553ab2009-02-24 01:25:14210
dalecurtis5755042e2015-03-26 20:31:22211 base::TimeTicks now = tick_clock_->NowTicks();
[email protected]e58c5e332014-08-15 04:43:52212
[email protected]3ad9d5b2011-12-22 16:43:26213 // Remain idle until we have the next frame ready for rendering.
214 if (ready_frames_.empty()) {
[email protected]5f60f9102014-07-16 21:05:21215 if (received_end_of_stream_) {
216 if (!rendered_end_of_stream_) {
217 rendered_end_of_stream_ = true;
[email protected]9dc5c0b2014-07-31 13:16:38218 task_runner_->PostTask(FROM_HERE, ended_cb_);
[email protected]5f60f9102014-07-16 21:05:21219 }
dalecurtis5755042e2015-03-26 20:31:22220 } else if (!last_painted_time_.is_null() &&
221 now - last_painted_time_ >= kTimeToDeclareHaveNothing) {
[email protected]5f60f9102014-07-16 21:05:21222 buffering_state_ = BUFFERING_HAVE_NOTHING;
223 task_runner_->PostTask(
224 FROM_HERE, base::Bind(buffering_state_cb_, BUFFERING_HAVE_NOTHING));
[email protected]6eda4e42013-02-28 21:59:54225 }
226
[email protected]f54e7682013-10-10 21:58:26227 UpdateStatsAndWait_Locked(kIdleTimeDelta);
[email protected]3ad9d5b2011-12-22 16:43:26228 continue;
229 }
[email protected]34d148482010-09-02 00:15:55230
dalecurtis5755042e2015-03-26 20:31:22231 base::TimeTicks target_paint_time =
232 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp());
233
234 // If media time has stopped, don't attempt to paint any more frames.
235 if (target_paint_time.is_null()) {
236 UpdateStatsAndWait_Locked(kIdleTimeDelta);
237 continue;
238 }
239
240 base::TimeTicks latest_possible_paint_time;
[email protected]dfb28d82014-07-14 02:48:56241
[email protected]bd22a7e2014-07-14 23:14:45242 // Deadline is defined as the duration between this frame and the next
[email protected]e0025862013-02-05 00:35:16243 // frame, using the delta between this frame and the previous frame as the
244 // assumption for frame duration.
[email protected]3ad9d5b2011-12-22 16:43:26245 //
[email protected]e0025862013-02-05 00:35:16246 // TODO(scherkus): This can be vastly improved. Use a histogram to measure
247 // the accuracy of our frame timing code. http://crbug.com/149829
dalecurtis5755042e2015-03-26 20:31:22248 if (last_media_time_.is_null()) {
249 latest_possible_paint_time = now;
[email protected]bd22a7e2014-07-14 23:14:45250 } else {
dalecurtis5755042e2015-03-26 20:31:22251 base::TimeDelta duration = target_paint_time - last_media_time_;
252 latest_possible_paint_time = target_paint_time + duration;
[email protected]bd22a7e2014-07-14 23:14:45253 }
[email protected]3ad9d5b2011-12-22 16:43:26254
[email protected]bd22a7e2014-07-14 23:14:45255 // Remain idle until we've reached our target paint window.
dalecurtis5755042e2015-03-26 20:31:22256 if (now < target_paint_time) {
lionel.g.landwerlinf5096612015-03-25 00:09:59257 UpdateStatsAndWait_Locked(
dalecurtis5755042e2015-03-26 20:31:22258 std::min(target_paint_time - now, kIdleTimeDelta));
[email protected]bd22a7e2014-07-14 23:14:45259 continue;
260 }
261
dalecurtis5755042e2015-03-26 20:31:22262 if (ready_frames_.size() > 1 && now > latest_possible_paint_time &&
lionel.g.landwerlinf5096612015-03-25 00:09:59263 drop_frames_) {
[email protected]bd22a7e2014-07-14 23:14:45264 DropNextReadyFrame_Locked();
265 continue;
[email protected]e5bd91e32011-08-25 06:31:32266 }
[email protected]119ec3ec2011-11-04 00:07:47267
268 // Congratulations! You've made it past the video frame timing gauntlet.
269 //
[email protected]e0025862013-02-05 00:35:16270 // At this point enough time has passed that the next frame that ready for
271 // rendering.
272 PaintNextReadyFrame_Locked();
[email protected]ce553ab2009-02-24 01:25:14273 }
274}
275
dalecurtis5755042e2015-03-26 20:31:22276void VideoRendererImpl::SetTickClockForTesting(
277 scoped_ptr<base::TickClock> tick_clock) {
278 tick_clock_.swap(tick_clock);
279}
280
[email protected]cc3933d2013-11-26 03:41:02281void VideoRendererImpl::PaintNextReadyFrame_Locked() {
[email protected]e0025862013-02-05 00:35:16282 lock_.AssertAcquired();
283
284 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
[email protected]e4ee49112012-08-02 22:42:52285 ready_frames_.pop_front();
[email protected]f54e7682013-10-10 21:58:26286 frames_decoded_++;
[email protected]e4ee49112012-08-02 22:42:52287
dalecurtis5755042e2015-03-26 20:31:22288 last_media_time_ = last_painted_time_ =
289 wall_clock_time_cb_.Run(next_frame->timestamp());
[email protected]e0025862013-02-05 00:35:16290
[email protected]e0025862013-02-05 00:35:16291 paint_cb_.Run(next_frame);
292
[email protected]de39b022014-03-18 21:36:22293 task_runner_->PostTask(
294 FROM_HERE,
295 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
[email protected]e4ee49112012-08-02 22:42:52296}
297
[email protected]cc3933d2013-11-26 03:41:02298void VideoRendererImpl::DropNextReadyFrame_Locked() {
299 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
[email protected]33972162013-11-12 19:06:52300
[email protected]e0025862013-02-05 00:35:16301 lock_.AssertAcquired();
[email protected]5e838262010-06-24 19:15:07302
dalecurtis5755042e2015-03-26 20:31:22303 last_media_time_ =
304 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp());
305
[email protected]e0025862013-02-05 00:35:16306 ready_frames_.pop_front();
[email protected]f54e7682013-10-10 21:58:26307 frames_decoded_++;
308 frames_dropped_++;
[email protected]b3766a22010-12-22 17:34:13309
[email protected]de39b022014-03-18 21:36:22310 task_runner_->PostTask(
311 FROM_HERE,
312 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
[email protected]6cac5e0d2012-05-18 21:37:04313}
314
[email protected]cc3933d2013-11-26 03:41:02315void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
[email protected]1da0dae2012-06-20 17:11:08316 const scoped_refptr<VideoFrame>& frame) {
xhwangbe9da702014-08-23 21:44:55317 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]20305ec2011-01-21 04:55:52318 base::AutoLock auto_lock(lock_);
[email protected]119ec3ec2011-11-04 00:07:47319 DCHECK_NE(state_, kUninitialized);
[email protected]971db8c2013-07-12 01:52:36320 DCHECK_NE(state_, kFlushed);
[email protected]34d148482010-09-02 00:15:55321
[email protected]f1399732012-04-10 23:56:38322 CHECK(pending_read_);
[email protected]f23676a2011-11-04 02:04:09323 pending_read_ = false;
[email protected]34d148482010-09-02 00:15:55324
[email protected]e835f5332013-07-26 13:36:31325 if (status == VideoFrameStream::DECODE_ERROR ||
326 status == VideoFrameStream::DECRYPT_ERROR) {
[email protected]5b7ca4282013-06-03 00:19:16327 DCHECK(!frame.get());
[email protected]647f1a42013-07-17 22:21:36328 PipelineStatus error = PIPELINE_ERROR_DECODE;
[email protected]e835f5332013-07-26 13:36:31329 if (status == VideoFrameStream::DECRYPT_ERROR)
[email protected]647f1a42013-07-17 22:21:36330 error = PIPELINE_ERROR_DECRYPT;
xhwangbe9da702014-08-23 21:44:55331 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
[email protected]8d1e8fb2012-04-28 03:12:46332 return;
333 }
334
[email protected]971db8c2013-07-12 01:52:36335 // Already-queued VideoFrameStream ReadCB's can fire after various state
336 // transitions have happened; in that case just drop those frames immediately.
[email protected]47affc72014-07-23 01:49:15337 if (state_ == kFlushing)
[email protected]f1399732012-04-10 23:56:38338 return;
339
[email protected]28bc175c2014-07-01 19:39:17340 DCHECK_EQ(state_, kPlaying);
[email protected]ddb5e562013-03-20 12:07:10341
[email protected]28bc175c2014-07-01 19:39:17342 // Can happen when demuxers are preparing for a new Seek().
dchengd048bd272014-08-27 02:25:08343 if (!frame.get()) {
[email protected]28bc175c2014-07-01 19:39:17344 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
[email protected]b7f5fe962012-01-31 04:48:33345 return;
346 }
347
[email protected]876937d2013-11-08 05:32:29348 if (frame->end_of_stream()) {
[email protected]ddb5e562013-03-20 12:07:10349 DCHECK(!received_end_of_stream_);
350 received_end_of_stream_ = true;
[email protected]28bc175c2014-07-01 19:39:17351 } else {
352 // Maintain the latest frame decoded so the correct frame is displayed after
353 // prerolling has completed.
354 if (frame->timestamp() <= start_timestamp_)
355 ready_frames_.clear();
356 AddReadyFrame_Locked(frame);
[email protected]930c7472010-07-28 00:07:54357 }
[email protected]1f500f52009-06-22 22:23:19358
[email protected]28bc175c2014-07-01 19:39:17359 // Signal buffering state if we've met our conditions for having enough data.
360 if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked())
361 TransitionToHaveEnough_Locked();
[email protected]f23676a2011-11-04 02:04:09362
363 // Always request more decoded video if we have capacity. This serves two
364 // purposes:
365 // 1) Prerolling while paused
366 // 2) Keeps decoding going if video rendering thread starts falling behind
[email protected]ddb5e562013-03-20 12:07:10367 AttemptRead_Locked();
[email protected]ce553ab2009-02-24 01:25:14368}
369
[email protected]28bc175c2014-07-01 19:39:17370bool VideoRendererImpl::HaveEnoughData_Locked() {
371 DCHECK_EQ(state_, kPlaying);
372 return received_end_of_stream_ ||
[email protected]4beec402014-07-17 08:32:52373 !video_frame_stream_->CanReadWithoutStalling() ||
[email protected]28bc175c2014-07-01 19:39:17374 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) ||
375 (low_delay_ && ready_frames_.size() > 0);
376}
377
378void VideoRendererImpl::TransitionToHaveEnough_Locked() {
[email protected]9dc5c0b2014-07-31 13:16:38379 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]28bc175c2014-07-01 19:39:17380 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
381
[email protected]28bc175c2014-07-01 19:39:17382 if (!ready_frames_.empty()) {
[email protected]28bc175c2014-07-01 19:39:17383 // Because the clock might remain paused in for an undetermined amount
384 // of time (e.g., seeking while paused), paint the first frame.
385 PaintNextReadyFrame_Locked();
386 }
387
388 buffering_state_ = BUFFERING_HAVE_ENOUGH;
389 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
[email protected]4b6e4a9e2013-12-04 01:11:10390}
391
[email protected]cc3933d2013-11-26 03:41:02392void VideoRendererImpl::AddReadyFrame_Locked(
[email protected]61b52d12013-02-28 05:28:22393 const scoped_refptr<VideoFrame>& frame) {
[email protected]9dc5c0b2014-07-31 13:16:38394 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]61b52d12013-02-28 05:28:22395 lock_.AssertAcquired();
[email protected]876937d2013-11-08 05:32:29396 DCHECK(!frame->end_of_stream());
[email protected]61b52d12013-02-28 05:28:22397
[email protected]ddb5e562013-03-20 12:07:10398 ready_frames_.push_back(frame);
399 DCHECK_LE(ready_frames_.size(),
400 static_cast<size_t>(limits::kMaxVideoFrames));
401
[email protected]15f96db2013-02-28 18:54:52402 // Avoid needlessly waking up |thread_| unless playing.
403 if (state_ == kPlaying)
404 frame_available_.Signal();
[email protected]23f720d2012-07-31 21:10:55405}
406
[email protected]cc3933d2013-11-26 03:41:02407void VideoRendererImpl::AttemptRead() {
[email protected]1276cc162012-12-07 21:55:33408 base::AutoLock auto_lock(lock_);
409 AttemptRead_Locked();
410}
411
[email protected]cc3933d2013-11-26 03:41:02412void VideoRendererImpl::AttemptRead_Locked() {
[email protected]b639a832013-12-20 21:12:39413 DCHECK(task_runner_->BelongsToCurrentThread());
[email protected]35458972009-07-25 02:12:11414 lock_.AssertAcquired();
[email protected]f23676a2011-11-04 02:04:09415
[email protected]6eda4e42013-02-28 21:59:54416 if (pending_read_ || received_end_of_stream_ ||
417 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) {
[email protected]8d1e8fb2012-04-28 03:12:46418 return;
419 }
[email protected]f23676a2011-11-04 02:04:09420
[email protected]7f0456c2012-12-17 23:31:22421 switch (state_) {
[email protected]7f0456c2012-12-17 23:31:22422 case kPlaying:
423 pending_read_ = true;
[email protected]4beec402014-07-17 08:32:52424 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
425 weak_factory_.GetWeakPtr()));
[email protected]7f0456c2012-12-17 23:31:22426 return;
427
428 case kUninitialized:
[email protected]a1f7ace2013-02-22 06:14:07429 case kInitializing:
[email protected]971db8c2013-07-12 01:52:36430 case kFlushing:
[email protected]7f0456c2012-12-17 23:31:22431 case kFlushed:
[email protected]7f0456c2012-12-17 23:31:22432 return;
433 }
[email protected]d3d048772010-07-14 21:00:25434}
435
[email protected]cc3933d2013-11-26 03:41:02436void VideoRendererImpl::OnVideoFrameStreamResetDone() {
[email protected]d5c64442012-04-25 19:39:49437 base::AutoLock auto_lock(lock_);
[email protected]f23676a2011-11-04 02:04:09438 DCHECK_EQ(kFlushing, state_);
[email protected]971db8c2013-07-12 01:52:36439 DCHECK(!pending_read_);
[email protected]f8b47342013-03-27 12:20:21440 DCHECK(ready_frames_.empty());
441 DCHECK(!received_end_of_stream_);
[email protected]2267bfe82014-05-09 18:03:58442 DCHECK(!rendered_end_of_stream_);
[email protected]28bc175c2014-07-01 19:39:17443 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
[email protected]34d148482010-09-02 00:15:55444
[email protected]e0025862013-02-05 00:35:16445 state_ = kFlushed;
dalecurtis5755042e2015-03-26 20:31:22446 last_media_time_ = last_painted_time_ = base::TimeTicks();
[email protected]e0025862013-02-05 00:35:16447 base::ResetAndReturn(&flush_cb_).Run();
[email protected]1f500f52009-06-22 22:23:19448}
449
[email protected]cc3933d2013-11-26 03:41:02450void VideoRendererImpl::UpdateStatsAndWait_Locked(
[email protected]f54e7682013-10-10 21:58:26451 base::TimeDelta wait_duration) {
452 lock_.AssertAcquired();
453 DCHECK_GE(frames_decoded_, 0);
454 DCHECK_LE(frames_dropped_, frames_decoded_);
455
456 if (frames_decoded_) {
457 PipelineStatistics statistics;
458 statistics.video_frames_decoded = frames_decoded_;
459 statistics.video_frames_dropped = frames_dropped_;
[email protected]9dc5c0b2014-07-31 13:16:38460 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics));
[email protected]f54e7682013-10-10 21:58:26461
462 frames_decoded_ = 0;
463 frames_dropped_ = 0;
464 }
465
466 frame_available_.TimedWait(wait_duration);
467}
468
[email protected]1f500f52009-06-22 22:23:19469} // namespace media