Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: media/renderers/video_renderer_impl.cc

Issue 1083383005: Connect the new video rendering path to the compositor. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@vra
Patch Set: Comments. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/renderers/video_renderer_impl.h" 5 #include "media/renderers/video_renderer_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/callback_helpers.h" 9 #include "base/callback_helpers.h"
10 #include "base/command_line.h"
10 #include "base/location.h" 11 #include "base/location.h"
11 #include "base/single_thread_task_runner.h" 12 #include "base/single_thread_task_runner.h"
12 #include "base/threading/platform_thread.h" 13 #include "base/threading/platform_thread.h"
13 #include "base/time/default_tick_clock.h" 14 #include "base/time/default_tick_clock.h"
14 #include "base/trace_event/trace_event.h" 15 #include "base/trace_event/trace_event.h"
15 #include "media/base/bind_to_current_loop.h" 16 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/buffers.h" 17 #include "media/base/buffers.h"
17 #include "media/base/limits.h" 18 #include "media/base/limits.h"
19 #include "media/base/media_switches.h"
18 #include "media/base/pipeline.h" 20 #include "media/base/pipeline.h"
19 #include "media/base/video_frame.h" 21 #include "media/base/video_frame.h"
20 22
21 namespace media { 23 namespace media {
22 24
25 // Wait a quarter of a second for Render() callbacks before starting background
26 // rendering to keep the decode pump moving.
27 const int kBackgroundRenderingTimeoutMs = 250;
28
23 VideoRendererImpl::VideoRendererImpl( 29 VideoRendererImpl::VideoRendererImpl(
24 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 30 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
25 VideoRendererSink* sink, 31 VideoRendererSink* sink,
26 ScopedVector<VideoDecoder> decoders, 32 ScopedVector<VideoDecoder> decoders,
27 bool drop_frames, 33 bool drop_frames,
28 const scoped_refptr<MediaLog>& media_log) 34 const scoped_refptr<MediaLog>& media_log)
29 : task_runner_(task_runner), 35 : task_runner_(task_runner),
36 use_new_video_renderering_path_(
37 base::CommandLine::ForCurrentProcess()->HasSwitch(
38 switches::kEnableNewVideoRenderer)),
30 sink_(sink), 39 sink_(sink),
40 sink_started_(false),
31 video_frame_stream_( 41 video_frame_stream_(
32 new VideoFrameStream(task_runner, decoders.Pass(), media_log)), 42 new VideoFrameStream(task_runner, decoders.Pass(), media_log)),
33 low_delay_(false), 43 low_delay_(false),
34 received_end_of_stream_(false), 44 received_end_of_stream_(false),
35 rendered_end_of_stream_(false), 45 rendered_end_of_stream_(false),
36 frame_available_(&lock_), 46 frame_available_(&lock_),
37 state_(kUninitialized), 47 state_(kUninitialized),
38 thread_(), 48 thread_(),
39 pending_read_(false), 49 pending_read_(false),
40 drop_frames_(drop_frames), 50 drop_frames_(drop_frames),
41 buffering_state_(BUFFERING_HAVE_NOTHING), 51 buffering_state_(BUFFERING_HAVE_NOTHING),
42 frames_decoded_(0), 52 frames_decoded_(0),
43 frames_dropped_(0), 53 frames_dropped_(0),
44 is_shutting_down_(false), 54 is_shutting_down_(false),
45 tick_clock_(new base::DefaultTickClock()), 55 tick_clock_(new base::DefaultTickClock()),
56 is_background_rendering_(false),
57 should_use_background_renderering_(true),
58 time_progressing_(false),
59 render_first_frame_and_stop_(false),
60 background_rendering_timeout_(
61 base::TimeDelta::FromMilliseconds(kBackgroundRenderingTimeoutMs)),
46 weak_factory_(this) { 62 weak_factory_(this) {
47 } 63 }
48 64
49 VideoRendererImpl::~VideoRendererImpl() { 65 VideoRendererImpl::~VideoRendererImpl() {
50 DCHECK(task_runner_->BelongsToCurrentThread()); 66 DCHECK(task_runner_->BelongsToCurrentThread());
51 67
52 { 68 if (!use_new_video_renderering_path_) {
53 base::AutoLock auto_lock(lock_); 69 base::AutoLock auto_lock(lock_);
54 is_shutting_down_ = true; 70 is_shutting_down_ = true;
55 frame_available_.Signal(); 71 frame_available_.Signal();
56 } 72 }
57 73
58 if (!thread_.is_null()) 74 if (!thread_.is_null())
59 base::PlatformThread::Join(thread_); 75 base::PlatformThread::Join(thread_);
60 76
61 if (!init_cb_.is_null()) 77 if (!init_cb_.is_null())
62 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); 78 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
63 79
64 if (!flush_cb_.is_null()) 80 if (!flush_cb_.is_null())
65 base::ResetAndReturn(&flush_cb_).Run(); 81 base::ResetAndReturn(&flush_cb_).Run();
82
83 if (use_new_video_renderering_path_ && sink_started_)
84 StopSink();
66 } 85 }
67 86
68 void VideoRendererImpl::Flush(const base::Closure& callback) { 87 void VideoRendererImpl::Flush(const base::Closure& callback) {
69 DVLOG(1) << __FUNCTION__; 88 DVLOG(1) << __FUNCTION__;
70 DCHECK(task_runner_->BelongsToCurrentThread()); 89 DCHECK(task_runner_->BelongsToCurrentThread());
90
91 if (use_new_video_renderering_path_ && sink_started_)
92 StopSink();
93
71 base::AutoLock auto_lock(lock_); 94 base::AutoLock auto_lock(lock_);
72 DCHECK_EQ(state_, kPlaying); 95 DCHECK_EQ(state_, kPlaying);
73 flush_cb_ = callback; 96 flush_cb_ = callback;
74 state_ = kFlushing; 97 state_ = kFlushing;
75 98
76 // This is necessary if the |video_frame_stream_| has already seen an end of 99 // This is necessary if the |video_frame_stream_| has already seen an end of
77 // stream and needs to drain it before flushing it. 100 // stream and needs to drain it before flushing it.
78 ready_frames_.clear(); 101 ready_frames_.clear();
79 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { 102 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
80 buffering_state_ = BUFFERING_HAVE_NOTHING; 103 buffering_state_ = BUFFERING_HAVE_NOTHING;
81 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING); 104 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
82 } 105 }
83 received_end_of_stream_ = false; 106 received_end_of_stream_ = false;
84 rendered_end_of_stream_ = false; 107 rendered_end_of_stream_ = false;
85 108
109 if (use_new_video_renderering_path_)
110 algorithm_->Reset();
111
86 video_frame_stream_->Reset( 112 video_frame_stream_->Reset(
87 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone, 113 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone,
88 weak_factory_.GetWeakPtr())); 114 weak_factory_.GetWeakPtr()));
89 } 115 }
90 116
91 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { 117 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
92 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; 118 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")";
93 DCHECK(task_runner_->BelongsToCurrentThread()); 119 DCHECK(task_runner_->BelongsToCurrentThread());
94 base::AutoLock auto_lock(lock_); 120 base::AutoLock auto_lock(lock_);
95 DCHECK_EQ(state_, kFlushed); 121 DCHECK_EQ(state_, kFlushed);
(...skipping 19 matching lines...) Expand all
115 DCHECK(task_runner_->BelongsToCurrentThread()); 141 DCHECK(task_runner_->BelongsToCurrentThread());
116 base::AutoLock auto_lock(lock_); 142 base::AutoLock auto_lock(lock_);
117 DCHECK(stream); 143 DCHECK(stream);
118 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); 144 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
119 DCHECK(!init_cb.is_null()); 145 DCHECK(!init_cb.is_null());
120 DCHECK(!statistics_cb.is_null()); 146 DCHECK(!statistics_cb.is_null());
121 DCHECK(!buffering_state_cb.is_null()); 147 DCHECK(!buffering_state_cb.is_null());
122 DCHECK(!ended_cb.is_null()); 148 DCHECK(!ended_cb.is_null());
123 DCHECK(!wall_clock_time_cb.is_null()); 149 DCHECK(!wall_clock_time_cb.is_null());
124 DCHECK_EQ(kUninitialized, state_); 150 DCHECK_EQ(kUninitialized, state_);
151 DCHECK(!render_first_frame_and_stop_);
152 DCHECK(!is_background_rendering_);
153 DCHECK(!time_progressing_);
125 154
126 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE); 155 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE);
127 156
128 // Always post |init_cb_| because |this| could be destroyed if initialization 157 // Always post |init_cb_| because |this| could be destroyed if initialization
129 // failed. 158 // failed.
130 init_cb_ = BindToCurrentLoop(init_cb); 159 init_cb_ = BindToCurrentLoop(init_cb);
131 160
132 statistics_cb_ = statistics_cb; 161 statistics_cb_ = statistics_cb;
133 buffering_state_cb_ = buffering_state_cb; 162 buffering_state_cb_ = buffering_state_cb;
134 paint_cb_ = base::Bind(&VideoRendererSink::PaintFrameUsingOldRenderingPath, 163 paint_cb_ = base::Bind(&VideoRendererSink::PaintFrameUsingOldRenderingPath,
135 base::Unretained(sink_)); 164 base::Unretained(sink_));
136 ended_cb_ = ended_cb; 165 ended_cb_ = ended_cb;
137 error_cb_ = error_cb; 166 error_cb_ = error_cb;
138 wall_clock_time_cb_ = wall_clock_time_cb; 167 wall_clock_time_cb_ = wall_clock_time_cb;
139 state_ = kInitializing; 168 state_ = kInitializing;
140 169
141 video_frame_stream_->Initialize( 170 video_frame_stream_->Initialize(
142 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized, 171 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
143 weak_factory_.GetWeakPtr()), 172 weak_factory_.GetWeakPtr()),
144 set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb); 173 set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
145 } 174 }
146 175
147 scoped_refptr<VideoFrame> VideoRendererImpl::Render( 176 scoped_refptr<VideoFrame> VideoRendererImpl::Render(
148 base::TimeTicks deadline_min, 177 base::TimeTicks deadline_min,
149 base::TimeTicks deadline_max) { 178 base::TimeTicks deadline_max) {
150 // TODO(dalecurtis): Hook this up to the new VideoRendererAlgorithm. 179 base::AutoLock auto_lock(lock_);
151 NOTIMPLEMENTED(); 180 DCHECK(use_new_video_renderering_path_);
152 return nullptr; 181 DCHECK_EQ(state_, kPlaying);
182 last_render_time_ = tick_clock_->NowTicks();
183
184 size_t frames_dropped = 0;
185 scoped_refptr<VideoFrame> result =
186 algorithm_->Render(deadline_min, deadline_max, &frames_dropped);
187
188 // Due to how the |algorithm_| holds frames, this should never be null if
189 // we've had a proper startup sequence.
190 DCHECK(result);
191
192 // See if it's time to fire the ended callback.
193 const size_t effective_frames = MaybeFireEndedCallback();
194
195 // Declare HAVE_NOTHING if we have no more effective frames.
196 if (!effective_frames && !rendered_end_of_stream_ &&
197 buffering_state_ == BUFFERING_HAVE_ENOUGH) {
198 buffering_state_ = BUFFERING_HAVE_NOTHING;
199 task_runner_->PostTask(
200 FROM_HERE, base::Bind(buffering_state_cb_, BUFFERING_HAVE_NOTHING));
201 }
202
203 // As we resume from background rendering, don't count the initial batch of
204 // dropped frames since they are likely just dropped due to being too old.
205 if (!is_background_rendering_) {
206 frames_dropped_ += frames_dropped;
207 UpdateStatsAndWait_Locked(base::TimeDelta());
208 }
209 is_background_rendering_ = false;
210
211 // After painting the first frame, if playback hasn't started, we request that
212 // the sink be stopped. OnTimeStateChanged() will clear this flag if time
213 // starts before we get here and MaybeStopSinkAfterFirstPaint() will ignore
214 // this request if time starts before the call executes.
215 if (render_first_frame_and_stop_) {
216 task_runner_->PostTask(
217 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
218 weak_factory_.GetWeakPtr()));
219 }
220
221 // Always post this task, it will acquire new frames if necessary, reset the
222 // background rendering timer, and more.
223 task_runner_->PostTask(FROM_HERE, base::Bind(&VideoRendererImpl::AttemptRead,
224 weak_factory_.GetWeakPtr()));
225
226 return result;
153 } 227 }
154 228
155 void VideoRendererImpl::OnFrameDropped() { 229 void VideoRendererImpl::OnFrameDropped() {
156 // TODO(dalecurtis): Hook this up to the new VideoRendererAlgorithm. 230 base::AutoLock auto_lock(lock_);
157 NOTIMPLEMENTED(); 231 DCHECK(use_new_video_renderering_path_);
232 algorithm_->OnLastFrameDropped();
233 }
234
235 void VideoRendererImpl::SetBackgroundRenderingForTesting(
236 bool enabled,
237 base::TimeDelta timeout) {
238 should_use_background_renderering_ = enabled;
239 background_rendering_timeout_ = timeout;
158 } 240 }
159 241
160 void VideoRendererImpl::CreateVideoThread() { 242 void VideoRendererImpl::CreateVideoThread() {
161 // This may fail and cause a crash if there are too many threads created in 243 // This may fail and cause a crash if there are too many threads created in
162 // the current process. See http://crbug.com/443291 244 // the current process. See http://crbug.com/443291
163 CHECK(base::PlatformThread::Create(0, this, &thread_)); 245 CHECK(base::PlatformThread::Create(0, this, &thread_));
164 246
165 #if defined(OS_WIN) 247 #if defined(OS_WIN)
166 // Bump up our priority so our sleeping is more accurate. 248 // Bump up our priority so our sleeping is more accurate.
167 // TODO(scherkus): find out if this is necessary, but it seems to help. 249 // TODO(scherkus): find out if this is necessary, but it seems to help.
(...skipping 11 matching lines...) Expand all
179 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); 261 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
180 return; 262 return;
181 } 263 }
182 264
183 // We're all good! Consider ourselves flushed. (ThreadMain() should never 265 // We're all good! Consider ourselves flushed. (ThreadMain() should never
184 // see us in the kUninitialized state). 266 // see us in the kUninitialized state).
185 // Since we had an initial Preroll(), we consider ourself flushed, because we 267 // Since we had an initial Preroll(), we consider ourself flushed, because we
186 // have not populated any buffers yet. 268 // have not populated any buffers yet.
187 state_ = kFlushed; 269 state_ = kFlushed;
188 270
189 CreateVideoThread(); 271 if (use_new_video_renderering_path_) {
272 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_));
273 if (!drop_frames_)
274 algorithm_->disable_frame_dropping();
275 } else {
276 CreateVideoThread();
277 }
190 278
191 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 279 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
192 } 280 }
193 281
194 // PlatformThread::Delegate implementation. 282 // PlatformThread::Delegate implementation.
195 void VideoRendererImpl::ThreadMain() { 283 void VideoRendererImpl::ThreadMain() {
284 DCHECK(!use_new_video_renderering_path_);
196 base::PlatformThread::SetName("CrVideoRenderer"); 285 base::PlatformThread::SetName("CrVideoRenderer");
197 286
198 // The number of milliseconds to idle when we do not have anything to do. 287 // The number of milliseconds to idle when we do not have anything to do.
199 // Nothing special about the value, other than we're being more OS-friendly 288 // Nothing special about the value, other than we're being more OS-friendly
200 // than sleeping for 1 millisecond. 289 // than sleeping for 1 millisecond.
201 // 290 //
202 // TODO(scherkus): switch to pure event-driven frame timing instead of this 291 // TODO(scherkus): switch to pure event-driven frame timing instead of this
203 // kIdleTimeDelta business http://crbug.com/106874 292 // kIdleTimeDelta business http://crbug.com/106874
204 const base::TimeDelta kIdleTimeDelta = 293 const base::TimeDelta kIdleTimeDelta =
205 base::TimeDelta::FromMilliseconds(10); 294 base::TimeDelta::FromMilliseconds(10);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 PaintNextReadyFrame_Locked(); 372 PaintNextReadyFrame_Locked();
284 } 373 }
285 } 374 }
286 375
287 void VideoRendererImpl::SetTickClockForTesting( 376 void VideoRendererImpl::SetTickClockForTesting(
288 scoped_ptr<base::TickClock> tick_clock) { 377 scoped_ptr<base::TickClock> tick_clock) {
289 tick_clock_.swap(tick_clock); 378 tick_clock_.swap(tick_clock);
290 } 379 }
291 380
292 void VideoRendererImpl::OnTimeStateChanged(bool time_progressing) { 381 void VideoRendererImpl::OnTimeStateChanged(bool time_progressing) {
293 // TODO(dalecurtis): Wire up to the VideoRendererSink once it's implemented. 382 DCHECK(task_runner_->BelongsToCurrentThread());
383 time_progressing_ = time_progressing;
384
385 // WARNING: Do not attempt to use |lock_| here as this may be a reentrant call
386 // in response to callbacks firing above.
387
388 if (!use_new_video_renderering_path_ || sink_started_ == time_progressing_)
389 return;
390
391 if (time_progressing_)
392 StartSink();
393 else
394 StopSink();
294 } 395 }
295 396
296 void VideoRendererImpl::PaintNextReadyFrame_Locked() { 397 void VideoRendererImpl::PaintNextReadyFrame_Locked() {
398 DCHECK(!use_new_video_renderering_path_);
297 lock_.AssertAcquired(); 399 lock_.AssertAcquired();
298 400
299 scoped_refptr<VideoFrame> next_frame = ready_frames_.front(); 401 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
300 ready_frames_.pop_front(); 402 ready_frames_.pop_front();
301 frames_decoded_++; 403 frames_decoded_++;
302 404
303 last_media_time_ = wall_clock_time_cb_.Run(next_frame->timestamp()); 405 last_media_time_ = wall_clock_time_cb_.Run(next_frame->timestamp());
304 406
305 paint_cb_.Run(next_frame); 407 paint_cb_.Run(next_frame);
306 408
307 task_runner_->PostTask( 409 task_runner_->PostTask(
308 FROM_HERE, 410 FROM_HERE,
309 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr())); 411 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
310 } 412 }
311 413
312 void VideoRendererImpl::DropNextReadyFrame_Locked() { 414 void VideoRendererImpl::DropNextReadyFrame_Locked() {
415 DCHECK(!use_new_video_renderering_path_);
313 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped"); 416 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
314 417
315 lock_.AssertAcquired(); 418 lock_.AssertAcquired();
316 419
317 last_media_time_ = 420 last_media_time_ =
318 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp()); 421 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp());
319 422
320 ready_frames_.pop_front(); 423 ready_frames_.pop_front();
321 frames_decoded_++; 424 frames_decoded_++;
322 frames_dropped_++; 425 frames_dropped_++;
323 426
324 task_runner_->PostTask( 427 task_runner_->PostTask(
325 FROM_HERE, 428 FROM_HERE,
326 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr())); 429 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
327 } 430 }
328 431
329 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status, 432 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
330 const scoped_refptr<VideoFrame>& frame) { 433 const scoped_refptr<VideoFrame>& frame) {
331 DCHECK(task_runner_->BelongsToCurrentThread()); 434 DCHECK(task_runner_->BelongsToCurrentThread());
332 base::AutoLock auto_lock(lock_); 435 bool start_sink = false;
333 DCHECK_NE(state_, kUninitialized); 436 {
334 DCHECK_NE(state_, kFlushed); 437 base::AutoLock auto_lock(lock_);
438 DCHECK_NE(state_, kUninitialized);
439 DCHECK_NE(state_, kFlushed);
335 440
336 CHECK(pending_read_); 441 CHECK(pending_read_);
337 pending_read_ = false; 442 pending_read_ = false;
338 443
339 if (status == VideoFrameStream::DECODE_ERROR || 444 if (status == VideoFrameStream::DECODE_ERROR ||
340 status == VideoFrameStream::DECRYPT_ERROR) { 445 status == VideoFrameStream::DECRYPT_ERROR) {
341 DCHECK(!frame.get()); 446 DCHECK(!frame.get());
342 PipelineStatus error = PIPELINE_ERROR_DECODE; 447 PipelineStatus error = PIPELINE_ERROR_DECODE;
343 if (status == VideoFrameStream::DECRYPT_ERROR) 448 if (status == VideoFrameStream::DECRYPT_ERROR)
344 error = PIPELINE_ERROR_DECRYPT; 449 error = PIPELINE_ERROR_DECRYPT;
345 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error)); 450 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
346 return; 451 return;
452 }
453
454 // Already-queued VideoFrameStream ReadCB's can fire after various state
455 // transitions have happened; in that case just drop those frames
456 // immediately.
457 if (state_ == kFlushing)
458 return;
459
460 DCHECK_EQ(state_, kPlaying);
461
462 // Can happen when demuxers are preparing for a new Seek().
463 if (!frame.get()) {
464 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
465 return;
466 }
467
468 if (frame->end_of_stream()) {
469 DCHECK(!received_end_of_stream_);
470 received_end_of_stream_ = true;
471
472 // See if we can fire EOS immediately instead of waiting for Render() or
473 // BackgroundRender() to tick.
474 if (use_new_video_renderering_path_ && time_progressing_)
475 MaybeFireEndedCallback();
476 } else {
477 // Maintain the latest frame decoded so the correct frame is displayed
478 // after prerolling has completed.
479 if (frame->timestamp() <= start_timestamp_) {
480 if (use_new_video_renderering_path_)
481 algorithm_->Reset();
482 ready_frames_.clear();
483 }
484 AddReadyFrame_Locked(frame);
485 }
486
487 // Signal buffering state if we've met our conditions for having enough
488 // data.
489 if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked()) {
490 TransitionToHaveEnough_Locked();
491 if (use_new_video_renderering_path_ && !sink_started_) {
492 start_sink = true;
493 render_first_frame_and_stop_ = true;
494 }
495 }
496
497 // BackgroundRender may not be ticking fast enough by itself to remove
498 // expired frames, so give it a boost here by ensuring we don't exit the
499 // decoding cycle too early.
500 if (is_background_rendering_) {
501 DCHECK(use_new_video_renderering_path_);
502 BackgroundRender_Locked();
503 }
504
505 // Always request more decoded video if we have capacity. This serves two
506 // purposes:
507 // 1) Prerolling while paused
508 // 2) Keeps decoding going if video rendering thread starts falling behind
509 AttemptRead_Locked();
347 } 510 }
348 511
349 // Already-queued VideoFrameStream ReadCB's can fire after various state 512 // If time is progressing, the sink has already been started; this may be true
350 // transitions have happened; in that case just drop those frames immediately. 513 // if we have previously underflowed, yet weren't stopped because of audio.
351 if (state_ == kFlushing) 514 if (use_new_video_renderering_path_ && start_sink) {
352 return; 515 DCHECK(!sink_started_);
353 516 StartSink();
354 DCHECK_EQ(state_, kPlaying);
355
356 // Can happen when demuxers are preparing for a new Seek().
357 if (!frame.get()) {
358 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
359 return;
360 } 517 }
361
362 if (frame->end_of_stream()) {
363 DCHECK(!received_end_of_stream_);
364 received_end_of_stream_ = true;
365 } else {
366 // Maintain the latest frame decoded so the correct frame is displayed after
367 // prerolling has completed.
368 if (frame->timestamp() <= start_timestamp_)
369 ready_frames_.clear();
370 AddReadyFrame_Locked(frame);
371 }
372
373 // Signal buffering state if we've met our conditions for having enough data.
374 if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked())
375 TransitionToHaveEnough_Locked();
376
377 // Always request more decoded video if we have capacity. This serves two
378 // purposes:
379 // 1) Prerolling while paused
380 // 2) Keeps decoding going if video rendering thread starts falling behind
381 AttemptRead_Locked();
382 } 518 }
383 519
384 bool VideoRendererImpl::HaveEnoughData_Locked() { 520 bool VideoRendererImpl::HaveEnoughData_Locked() {
385 DCHECK_EQ(state_, kPlaying); 521 DCHECK_EQ(state_, kPlaying);
386 return received_end_of_stream_ || 522
387 !video_frame_stream_->CanReadWithoutStalling() || 523 if (received_end_of_stream_ || !video_frame_stream_->CanReadWithoutStalling())
388 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) || 524 return true;
389 (low_delay_ && ready_frames_.size() > 0); 525
526 if (HaveReachedBufferingCap())
527 return true;
528
529 if (!low_delay_)
530 return false;
531
532 return ready_frames_.size() > 0 ||
533 (use_new_video_renderering_path_ && algorithm_->frames_queued() > 0);
390 } 534 }
391 535
392 void VideoRendererImpl::TransitionToHaveEnough_Locked() { 536 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
393 DCHECK(task_runner_->BelongsToCurrentThread()); 537 DCHECK(task_runner_->BelongsToCurrentThread());
394 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 538 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
395 539
396 if (!ready_frames_.empty()) { 540 if (!ready_frames_.empty()) {
541 DCHECK(!use_new_video_renderering_path_);
397 // Because the clock might remain paused in for an undetermined amount 542 // Because the clock might remain paused in for an undetermined amount
398 // of time (e.g., seeking while paused), paint the first frame. 543 // of time (e.g., seeking while paused), paint the first frame.
399 PaintNextReadyFrame_Locked(); 544 PaintNextReadyFrame_Locked();
400 } 545 }
401 546
402 buffering_state_ = BUFFERING_HAVE_ENOUGH; 547 buffering_state_ = BUFFERING_HAVE_ENOUGH;
403 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); 548 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
404 } 549 }
405 550
406 void VideoRendererImpl::AddReadyFrame_Locked( 551 void VideoRendererImpl::AddReadyFrame_Locked(
407 const scoped_refptr<VideoFrame>& frame) { 552 const scoped_refptr<VideoFrame>& frame) {
408 DCHECK(task_runner_->BelongsToCurrentThread()); 553 DCHECK(task_runner_->BelongsToCurrentThread());
409 lock_.AssertAcquired(); 554 lock_.AssertAcquired();
410 DCHECK(!frame->end_of_stream()); 555 DCHECK(!frame->end_of_stream());
411 556
557 if (use_new_video_renderering_path_) {
558 frames_decoded_++;
xhwang 2015/04/30 16:39:21 Can we move this out of "if" and then drop it from
DaleCurtis 2015/04/30 18:06:00 Done.
559 algorithm_->EnqueueFrame(frame);
560 return;
561 }
562
412 ready_frames_.push_back(frame); 563 ready_frames_.push_back(frame);
413 DCHECK_LE(ready_frames_.size(), 564 DCHECK_LE(ready_frames_.size(),
414 static_cast<size_t>(limits::kMaxVideoFrames)); 565 static_cast<size_t>(limits::kMaxVideoFrames));
415 566
416 // Avoid needlessly waking up |thread_| unless playing. 567 // Avoid needlessly waking up |thread_| unless playing.
417 if (state_ == kPlaying) 568 if (state_ == kPlaying)
418 frame_available_.Signal(); 569 frame_available_.Signal();
419 } 570 }
420 571
421 void VideoRendererImpl::AttemptRead() { 572 void VideoRendererImpl::AttemptRead() {
422 base::AutoLock auto_lock(lock_); 573 base::AutoLock auto_lock(lock_);
423 AttemptRead_Locked(); 574 AttemptRead_Locked();
424 } 575 }
425 576
426 void VideoRendererImpl::AttemptRead_Locked() { 577 void VideoRendererImpl::AttemptRead_Locked() {
427 DCHECK(task_runner_->BelongsToCurrentThread()); 578 DCHECK(task_runner_->BelongsToCurrentThread());
428 lock_.AssertAcquired(); 579 lock_.AssertAcquired();
429 580
430 if (pending_read_ || received_end_of_stream_ || 581 if (pending_read_ || received_end_of_stream_)
431 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) {
432 return; 582 return;
433 } 583
584 if (HaveReachedBufferingCap())
585 return;
434 586
435 switch (state_) { 587 switch (state_) {
436 case kPlaying: 588 case kPlaying:
437 pending_read_ = true; 589 pending_read_ = true;
438 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady, 590 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
439 weak_factory_.GetWeakPtr())); 591 weak_factory_.GetWeakPtr()));
440 return; 592 return;
441 593
442 case kUninitialized: 594 case kUninitialized:
443 case kInitializing: 595 case kInitializing:
(...skipping 14 matching lines...) Expand all
458 610
459 state_ = kFlushed; 611 state_ = kFlushed;
460 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks(); 612 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks();
461 base::ResetAndReturn(&flush_cb_).Run(); 613 base::ResetAndReturn(&flush_cb_).Run();
462 } 614 }
463 615
464 void VideoRendererImpl::UpdateStatsAndWait_Locked( 616 void VideoRendererImpl::UpdateStatsAndWait_Locked(
465 base::TimeDelta wait_duration) { 617 base::TimeDelta wait_duration) {
466 lock_.AssertAcquired(); 618 lock_.AssertAcquired();
467 DCHECK_GE(frames_decoded_, 0); 619 DCHECK_GE(frames_decoded_, 0);
468 DCHECK_LE(frames_dropped_, frames_decoded_); 620 DCHECK_GE(frames_dropped_, 0);
469 621
470 if (frames_decoded_) { 622 if (frames_decoded_ || frames_dropped_) {
471 PipelineStatistics statistics; 623 PipelineStatistics statistics;
472 statistics.video_frames_decoded = frames_decoded_; 624 statistics.video_frames_decoded = frames_decoded_;
473 statistics.video_frames_dropped = frames_dropped_; 625 statistics.video_frames_dropped = frames_dropped_;
474 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics)); 626 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics));
475 627
476 frames_decoded_ = 0; 628 frames_decoded_ = 0;
477 frames_dropped_ = 0; 629 frames_dropped_ = 0;
478 } 630 }
479 631
480 frame_available_.TimedWait(wait_duration); 632 if (wait_duration > base::TimeDelta())
633 frame_available_.TimedWait(wait_duration);
634 }
635
636 void VideoRendererImpl::MaybeStopSinkAfterFirstPaint() {
637 DCHECK(task_runner_->BelongsToCurrentThread());
638 DCHECK(use_new_video_renderering_path_);
639
640 {
641 base::AutoLock auto_lock(lock_);
642 render_first_frame_and_stop_ = false;
643 }
644
645 if (!time_progressing_ && sink_started_)
646 StopSink();
647 }
648
649 void VideoRendererImpl::RestartBackgroundRenderTimer() {
650 DCHECK(use_new_video_renderering_path_);
651 if (!drop_frames_ || !should_use_background_renderering_)
652 return;
653
654 // This controls the amount of time allowed between Render() callbacks before
655 // we assume they have timed out and it's necessary to start expiring
656 // unrendered frames.
xhwang 2015/04/30 16:39:20 This comment doesn't apply to l.657, which needs a
DaleCurtis 2015/04/30 18:06:01 Done.
657 last_render_time_ = tick_clock_->NowTicks();
658 background_rendering_timer_.Start(
659 FROM_HERE, background_rendering_timeout_,
660 base::Bind(&VideoRendererImpl::BackgroundRender,
661 weak_factory_.GetWeakPtr()));
662 }
663
664 void VideoRendererImpl::BackgroundRender() {
665 base::AutoLock auto_lock(lock_);
666 BackgroundRender_Locked();
667 }
668
669 void VideoRendererImpl::BackgroundRender_Locked() {
670 DCHECK(task_runner_->BelongsToCurrentThread());
671 DCHECK_EQ(state_, kPlaying);
672 lock_.AssertAcquired();
673
674 // If a Render() call never occurs after starting playback for the first frame
675 // we need to carry out the duties of Render() and stop the sink. We don't
676 // call MaybeStopSinkAfterFirstPaint() since it may need to mutate |sink_|,
677 // which can't be done under lock.
678 if (render_first_frame_and_stop_) {
679 task_runner_->PostTask(
680 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
681 weak_factory_.GetWeakPtr()));
682
683 // MaybeStopSinkAfterFirstPaint isn't going to stop the sink if time is
684 // currently progressing, so only bail out if necessary.
685 if (!time_progressing_)
686 return;
687 }
688
689 // Do nothing if Render() calls are progressing normally.
690 if (tick_clock_->NowTicks() - last_render_time_ <
691 background_rendering_timeout_) {
692 return;
693 }
694
695 // First clear as many expired frames as we can.
696 algorithm_->RemoveExpiredFrames(tick_clock_->NowTicks());
697 is_background_rendering_ = true;
698
699 // See if we've run out of frames and need to fire the ended callback.
700 MaybeFireEndedCallback();
701 if (rendered_end_of_stream_)
702 return;
703
704 // Start queuing new frames and scheduled this process again otherwise.
705 AttemptRead_Locked();
706 UpdateStatsAndWait_Locked(base::TimeDelta());
707 }
708
709 bool VideoRendererImpl::HaveReachedBufferingCap() {
710 DCHECK(task_runner_->BelongsToCurrentThread());
711 if (use_new_video_renderering_path_) {
712 // When the display rate is less than the frame rate, the effective frames
713 // queued may be much smaller than the actual number of frames queued. Here
714 // we ensure that frames_queued() doesn't get excessive.
715 return algorithm_->EffectiveFramesQueued() >=
716 static_cast<size_t>(limits::kMaxVideoFrames) ||
717 algorithm_->frames_queued() >=
718 static_cast<size_t>(3 * limits::kMaxVideoFrames);
719 }
720
721 return ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames);
722 }
723
724 void VideoRendererImpl::StartSink() {
725 DCHECK(task_runner_->BelongsToCurrentThread());
726 sink_->Start(this);
727 sink_started_ = true;
728 RestartBackgroundRenderTimer();
729 }
730
731 void VideoRendererImpl::StopSink() {
732 DCHECK(task_runner_->BelongsToCurrentThread());
733 sink_->Stop();
734 sink_started_ = false;
735 background_rendering_timer_.Stop();
736 is_background_rendering_ = false;
737 }
738
739 size_t VideoRendererImpl::MaybeFireEndedCallback() {
740 // If there's only one frame in the video or Render() was never called, the
741 // algorithm will have one frame linger indefinitely. So in cases where the
742 // frame duration is unknown and we've recieved EOS, fire it once we get down
743 // to a single frame.
744 const size_t effective_frames = algorithm_->EffectiveFramesQueued();
745
746 if ((!effective_frames ||
747 (algorithm_->frames_queued() == 1u &&
748 algorithm_->average_frame_duration() == base::TimeDelta())) &&
749 received_end_of_stream_ && !rendered_end_of_stream_) {
750 rendered_end_of_stream_ = true;
751 task_runner_->PostTask(FROM_HERE, ended_cb_);
752 }
753
754 return effective_frames;
481 } 755 }
482 756
483 } // namespace media 757 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698