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

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: Fix layout tests. 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 static 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 init_cb_ = BindToCurrentLoop(init_cb); 156 init_cb_ = BindToCurrentLoop(init_cb);
131 157
132 statistics_cb_ = statistics_cb; 158 statistics_cb_ = statistics_cb;
133 buffering_state_cb_ = buffering_state_cb; 159 buffering_state_cb_ = buffering_state_cb;
134 paint_cb_ = base::Bind(&VideoRendererSink::PaintFrameUsingOldRenderingPath, 160 paint_cb_ = base::Bind(&VideoRendererSink::PaintFrameUsingOldRenderingPath,
135 base::Unretained(sink_)); 161 base::Unretained(sink_));
136 ended_cb_ = ended_cb; 162 ended_cb_ = ended_cb;
137 error_cb_ = error_cb; 163 error_cb_ = error_cb;
138 wall_clock_time_cb_ = wall_clock_time_cb; 164 wall_clock_time_cb_ = wall_clock_time_cb;
139 state_ = kInitializing; 165 state_ = kInitializing;
166 render_first_frame_and_stop_ = false;
167 is_background_rendering_ = false;
168 time_progressing_ = false;
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
183 size_t frames_dropped = 0;
184 scoped_refptr<VideoFrame> result =
185 algorithm_->Render(deadline_min, deadline_max, &frames_dropped);
186
187 // Due to how the |algorithm_| holds frames, this should never be null if
188 // we've had a proper startup sequence.
189 DCHECK(result);
190
191 // See if it's time to fire the ended callback.
192 const size_t effective_frames = MaybeFireEndedCallback();
193
194 // Declare HAVE_NOTHING if we have no more effective frames.
195 if (!effective_frames && !rendered_end_of_stream_ &&
196 buffering_state_ == BUFFERING_HAVE_ENOUGH) {
197 buffering_state_ = BUFFERING_HAVE_NOTHING;
198 task_runner_->PostTask(
199 FROM_HERE, base::Bind(buffering_state_cb_, BUFFERING_HAVE_NOTHING));
200 }
201
202 // As we resume from background rendering, don't count the initial batch of
203 // dropped frames since they are likely just dropped due to being too old.
204 if (!is_background_rendering_) {
205 frames_dropped_ += frames_dropped;
206 UpdateStatsAndWait_Locked(base::TimeDelta());
207 }
208 is_background_rendering_ = false;
209
210 // After painting the first frame, if playback hasn't started, we request that
211 // the sink be stopped. OnTimeStateChanged() will clear this flag if time
212 // starts before we get here and MaybeStopSinkAfterFirstPaint() will ignore
213 // this request if time starts before the call executes.
214 if (render_first_frame_and_stop_) {
215 task_runner_->PostTask(
216 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
217 weak_factory_.GetWeakPtr()));
218 }
219
220 // Always post this task, it will acquire new frames if necessary, reset the
221 // background rendering timer, and more.
222 task_runner_->PostTask(FROM_HERE, base::Bind(&VideoRendererImpl::AttemptRead,
223 weak_factory_.GetWeakPtr()));
224
225 return result;
153 } 226 }
154 227
155 void VideoRendererImpl::OnFrameDropped() { 228 void VideoRendererImpl::OnFrameDropped() {
156 // TODO(dalecurtis): Hook this up to the new VideoRendererAlgorithm. 229 base::AutoLock auto_lock(lock_);
157 NOTIMPLEMENTED(); 230 DCHECK(use_new_video_renderering_path_);
231 algorithm_->OnLastFrameDropped();
232 }
233
234 void VideoRendererImpl::SetBackgroundRenderingForTesting(
235 bool enabled,
236 base::TimeDelta timeout) {
237 should_use_background_renderering_ = enabled;
238 background_rendering_timeout_ = timeout;
158 } 239 }
159 240
160 void VideoRendererImpl::CreateVideoThread() { 241 void VideoRendererImpl::CreateVideoThread() {
161 // This may fail and cause a crash if there are too many threads created in 242 // This may fail and cause a crash if there are too many threads created in
162 // the current process. See http://crbug.com/443291 243 // the current process. See http://crbug.com/443291
163 CHECK(base::PlatformThread::Create(0, this, &thread_)); 244 CHECK(base::PlatformThread::Create(0, this, &thread_));
164 245
165 #if defined(OS_WIN) 246 #if defined(OS_WIN)
166 // Bump up our priority so our sleeping is more accurate. 247 // Bump up our priority so our sleeping is more accurate.
167 // TODO(scherkus): find out if this is necessary, but it seems to help. 248 // 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); 260 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
180 return; 261 return;
181 } 262 }
182 263
183 // We're all good! Consider ourselves flushed. (ThreadMain() should never 264 // We're all good! Consider ourselves flushed. (ThreadMain() should never
184 // see us in the kUninitialized state). 265 // see us in the kUninitialized state).
185 // Since we had an initial Preroll(), we consider ourself flushed, because we 266 // Since we had an initial Preroll(), we consider ourself flushed, because we
186 // have not populated any buffers yet. 267 // have not populated any buffers yet.
187 state_ = kFlushed; 268 state_ = kFlushed;
188 269
189 CreateVideoThread(); 270 if (use_new_video_renderering_path_) {
271 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_));
272 if (!drop_frames_)
273 algorithm_->disable_frame_dropping();
274 } else {
275 CreateVideoThread();
276 }
190 277
191 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 278 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
192 } 279 }
193 280
194 // PlatformThread::Delegate implementation. 281 // PlatformThread::Delegate implementation.
195 void VideoRendererImpl::ThreadMain() { 282 void VideoRendererImpl::ThreadMain() {
283 DCHECK(!use_new_video_renderering_path_);
196 base::PlatformThread::SetName("CrVideoRenderer"); 284 base::PlatformThread::SetName("CrVideoRenderer");
197 285
198 // The number of milliseconds to idle when we do not have anything to do. 286 // 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 287 // Nothing special about the value, other than we're being more OS-friendly
200 // than sleeping for 1 millisecond. 288 // than sleeping for 1 millisecond.
201 // 289 //
202 // TODO(scherkus): switch to pure event-driven frame timing instead of this 290 // TODO(scherkus): switch to pure event-driven frame timing instead of this
203 // kIdleTimeDelta business http://crbug.com/106874 291 // kIdleTimeDelta business http://crbug.com/106874
204 const base::TimeDelta kIdleTimeDelta = 292 const base::TimeDelta kIdleTimeDelta =
205 base::TimeDelta::FromMilliseconds(10); 293 base::TimeDelta::FromMilliseconds(10);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 PaintNextReadyFrame_Locked(); 371 PaintNextReadyFrame_Locked();
284 } 372 }
285 } 373 }
286 374
287 void VideoRendererImpl::SetTickClockForTesting( 375 void VideoRendererImpl::SetTickClockForTesting(
288 scoped_ptr<base::TickClock> tick_clock) { 376 scoped_ptr<base::TickClock> tick_clock) {
289 tick_clock_.swap(tick_clock); 377 tick_clock_.swap(tick_clock);
290 } 378 }
291 379
292 void VideoRendererImpl::OnTimeStateChanged(bool time_progressing) { 380 void VideoRendererImpl::OnTimeStateChanged(bool time_progressing) {
293 // TODO(dalecurtis): Wire up to the VideoRendererSink once it's implemented. 381 DCHECK(task_runner_->BelongsToCurrentThread());
382 time_progressing_ = time_progressing;
383
384 // WARNING: Do not attempt to use |lock_| here as this may be a reentrant call
385 // in response to callbacks firing above.
386
387 if (!use_new_video_renderering_path_ || sink_started_ == time_progressing_)
388 return;
389
390 if (time_progressing_)
391 StartSink();
392 else
393 StopSink();
294 } 394 }
295 395
296 void VideoRendererImpl::PaintNextReadyFrame_Locked() { 396 void VideoRendererImpl::PaintNextReadyFrame_Locked() {
397 DCHECK(!use_new_video_renderering_path_);
297 lock_.AssertAcquired(); 398 lock_.AssertAcquired();
298 399
299 scoped_refptr<VideoFrame> next_frame = ready_frames_.front(); 400 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
300 ready_frames_.pop_front(); 401 ready_frames_.pop_front();
301 frames_decoded_++; 402 frames_decoded_++;
302 403
303 last_media_time_ = wall_clock_time_cb_.Run(next_frame->timestamp()); 404 last_media_time_ = wall_clock_time_cb_.Run(next_frame->timestamp());
304 405
305 paint_cb_.Run(next_frame); 406 paint_cb_.Run(next_frame);
306 407
307 task_runner_->PostTask( 408 task_runner_->PostTask(
308 FROM_HERE, 409 FROM_HERE,
309 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr())); 410 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
310 } 411 }
311 412
312 void VideoRendererImpl::DropNextReadyFrame_Locked() { 413 void VideoRendererImpl::DropNextReadyFrame_Locked() {
414 DCHECK(!use_new_video_renderering_path_);
313 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped"); 415 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
314 416
315 lock_.AssertAcquired(); 417 lock_.AssertAcquired();
316 418
317 last_media_time_ = 419 last_media_time_ =
318 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp()); 420 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp());
319 421
320 ready_frames_.pop_front(); 422 ready_frames_.pop_front();
321 frames_decoded_++; 423 frames_decoded_++;
322 frames_dropped_++; 424 frames_dropped_++;
323 425
324 task_runner_->PostTask( 426 task_runner_->PostTask(
325 FROM_HERE, 427 FROM_HERE,
326 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr())); 428 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
327 } 429 }
328 430
329 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status, 431 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
330 const scoped_refptr<VideoFrame>& frame) { 432 const scoped_refptr<VideoFrame>& frame) {
331 DCHECK(task_runner_->BelongsToCurrentThread()); 433 DCHECK(task_runner_->BelongsToCurrentThread());
332 base::AutoLock auto_lock(lock_); 434 bool start_sink = false;
333 DCHECK_NE(state_, kUninitialized); 435 {
334 DCHECK_NE(state_, kFlushed); 436 base::AutoLock auto_lock(lock_);
437 DCHECK_NE(state_, kUninitialized);
438 DCHECK_NE(state_, kFlushed);
335 439
336 CHECK(pending_read_); 440 CHECK(pending_read_);
337 pending_read_ = false; 441 pending_read_ = false;
338 442
339 if (status == VideoFrameStream::DECODE_ERROR || 443 if (status == VideoFrameStream::DECODE_ERROR ||
340 status == VideoFrameStream::DECRYPT_ERROR) { 444 status == VideoFrameStream::DECRYPT_ERROR) {
341 DCHECK(!frame.get()); 445 DCHECK(!frame.get());
342 PipelineStatus error = PIPELINE_ERROR_DECODE; 446 PipelineStatus error = PIPELINE_ERROR_DECODE;
343 if (status == VideoFrameStream::DECRYPT_ERROR) 447 if (status == VideoFrameStream::DECRYPT_ERROR)
344 error = PIPELINE_ERROR_DECRYPT; 448 error = PIPELINE_ERROR_DECRYPT;
345 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error)); 449 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
346 return; 450 return;
451 }
452
453 // Already-queued VideoFrameStream ReadCB's can fire after various state
454 // transitions have happened; in that case just drop those frames
455 // immediately.
456 if (state_ == kFlushing)
457 return;
458
459 DCHECK_EQ(state_, kPlaying);
460
461 // Can happen when demuxers are preparing for a new Seek().
462 if (!frame.get()) {
463 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
464 return;
465 }
466
467 if (frame->end_of_stream()) {
468 DCHECK(!received_end_of_stream_);
469 received_end_of_stream_ = true;
470
471 // See if we can fire EOS immediately instead of waiting for Render() or
472 // BackgroundRender() to tick.
473 if (use_new_video_renderering_path_ && time_progressing_)
474 MaybeFireEndedCallback();
475 } else {
476 // Maintain the latest frame decoded so the correct frame is displayed
477 // after prerolling has completed.
478 if (frame->timestamp() <= start_timestamp_) {
479 if (use_new_video_renderering_path_)
480 algorithm_->Reset();
481 ready_frames_.clear();
482 }
483 AddReadyFrame_Locked(frame);
484 }
485
486 // Signal buffering state if we've met our conditions for having enough
487 // data.
488 if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked()) {
489 TransitionToHaveEnough_Locked();
490 if (use_new_video_renderering_path_ && !sink_started_) {
491 start_sink = true;
492 render_first_frame_and_stop_ = true;
493 }
494 }
495
496 // BackgroundRender may not be ticking fast enough by itself to remove
497 // expired frames, so give it a boost here by ensuring we don't exit the
498 // decoding cycle too early.
499 if (is_background_rendering_) {
500 DCHECK(use_new_video_renderering_path_);
501 BackgroundRender_Locked();
502 }
503
504 // Always request more decoded video if we have capacity. This serves two
505 // purposes:
506 // 1) Prerolling while paused
507 // 2) Keeps decoding going if video rendering thread starts falling behind
508 AttemptRead_Locked();
347 } 509 }
348 510
349 // Already-queued VideoFrameStream ReadCB's can fire after various state 511 // 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. 512 // if we have previously underflowed, yet weren't stopped because of audio.
351 if (state_ == kFlushing) 513 if (use_new_video_renderering_path_ && start_sink) {
352 return; 514 DCHECK(!sink_started_);
353 515 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 } 516 }
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 } 517 }
383 518
384 bool VideoRendererImpl::HaveEnoughData_Locked() { 519 bool VideoRendererImpl::HaveEnoughData_Locked() {
385 DCHECK_EQ(state_, kPlaying); 520 DCHECK_EQ(state_, kPlaying);
386 return received_end_of_stream_ || 521
387 !video_frame_stream_->CanReadWithoutStalling() || 522 if (received_end_of_stream_ || !video_frame_stream_->CanReadWithoutStalling())
388 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) || 523 return true;
389 (low_delay_ && ready_frames_.size() > 0); 524
525 if (HaveReachedBufferingCap())
526 return true;
527
528 if (!low_delay_)
529 return false;
530
531 return ready_frames_.size() > 0 ||
532 (use_new_video_renderering_path_ && algorithm_->frames_queued() > 0);
390 } 533 }
391 534
392 void VideoRendererImpl::TransitionToHaveEnough_Locked() { 535 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
393 DCHECK(task_runner_->BelongsToCurrentThread()); 536 DCHECK(task_runner_->BelongsToCurrentThread());
394 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 537 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
395 538
396 if (!ready_frames_.empty()) { 539 if (!ready_frames_.empty()) {
540 DCHECK(!use_new_video_renderering_path_);
397 // Because the clock might remain paused in for an undetermined amount 541 // Because the clock might remain paused in for an undetermined amount
398 // of time (e.g., seeking while paused), paint the first frame. 542 // of time (e.g., seeking while paused), paint the first frame.
399 PaintNextReadyFrame_Locked(); 543 PaintNextReadyFrame_Locked();
400 } 544 }
401 545
402 buffering_state_ = BUFFERING_HAVE_ENOUGH; 546 buffering_state_ = BUFFERING_HAVE_ENOUGH;
403 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); 547 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
404 } 548 }
405 549
406 void VideoRendererImpl::AddReadyFrame_Locked( 550 void VideoRendererImpl::AddReadyFrame_Locked(
407 const scoped_refptr<VideoFrame>& frame) { 551 const scoped_refptr<VideoFrame>& frame) {
408 DCHECK(task_runner_->BelongsToCurrentThread()); 552 DCHECK(task_runner_->BelongsToCurrentThread());
409 lock_.AssertAcquired(); 553 lock_.AssertAcquired();
410 DCHECK(!frame->end_of_stream()); 554 DCHECK(!frame->end_of_stream());
411 555
556 if (use_new_video_renderering_path_) {
557 frames_decoded_++;
558 algorithm_->EnqueueFrame(frame);
559 return;
560 }
561
412 ready_frames_.push_back(frame); 562 ready_frames_.push_back(frame);
413 DCHECK_LE(ready_frames_.size(), 563 DCHECK_LE(ready_frames_.size(),
414 static_cast<size_t>(limits::kMaxVideoFrames)); 564 static_cast<size_t>(limits::kMaxVideoFrames));
415 565
416 // Avoid needlessly waking up |thread_| unless playing. 566 // Avoid needlessly waking up |thread_| unless playing.
417 if (state_ == kPlaying) 567 if (state_ == kPlaying)
418 frame_available_.Signal(); 568 frame_available_.Signal();
419 } 569 }
420 570
421 void VideoRendererImpl::AttemptRead() { 571 void VideoRendererImpl::AttemptRead() {
422 base::AutoLock auto_lock(lock_); 572 base::AutoLock auto_lock(lock_);
423 AttemptRead_Locked(); 573 AttemptRead_Locked();
424 } 574 }
425 575
426 void VideoRendererImpl::AttemptRead_Locked() { 576 void VideoRendererImpl::AttemptRead_Locked() {
427 DCHECK(task_runner_->BelongsToCurrentThread()); 577 DCHECK(task_runner_->BelongsToCurrentThread());
428 lock_.AssertAcquired(); 578 lock_.AssertAcquired();
429 579
430 if (pending_read_ || received_end_of_stream_ || 580 if (pending_read_ || received_end_of_stream_)
431 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) {
432 return; 581 return;
433 } 582
583 if (use_new_video_renderering_path_ && time_progressing_)
584 RestartBackgroundRenderTimer();
585
586 if (HaveReachedBufferingCap())
587 return;
434 588
435 switch (state_) { 589 switch (state_) {
436 case kPlaying: 590 case kPlaying:
437 pending_read_ = true; 591 pending_read_ = true;
438 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady, 592 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
439 weak_factory_.GetWeakPtr())); 593 weak_factory_.GetWeakPtr()));
440 return; 594 return;
441 595
442 case kUninitialized: 596 case kUninitialized:
443 case kInitializing: 597 case kInitializing:
444 case kFlushing: 598 case kFlushing:
445 case kFlushed: 599 case kFlushed:
446 return; 600 return;
447 } 601 }
448 } 602 }
449 603
450 void VideoRendererImpl::OnVideoFrameStreamResetDone() { 604 void VideoRendererImpl::OnVideoFrameStreamResetDone() {
451 base::AutoLock auto_lock(lock_); 605 base::AutoLock auto_lock(lock_);
452 DCHECK_EQ(kFlushing, state_); 606 DCHECK_EQ(kFlushing, state_);
453 DCHECK(!pending_read_); 607 DCHECK(!pending_read_);
454 DCHECK(ready_frames_.empty()); 608 DCHECK(ready_frames_.empty());
455 DCHECK(!received_end_of_stream_); 609 DCHECK(!received_end_of_stream_);
456 DCHECK(!rendered_end_of_stream_); 610 DCHECK(!rendered_end_of_stream_);
457 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 611 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
458 612
459 state_ = kFlushed; 613 state_ = kFlushed;
460 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks(); 614 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks();
615
461 base::ResetAndReturn(&flush_cb_).Run(); 616 base::ResetAndReturn(&flush_cb_).Run();
462 } 617 }
463 618
464 void VideoRendererImpl::UpdateStatsAndWait_Locked( 619 void VideoRendererImpl::UpdateStatsAndWait_Locked(
465 base::TimeDelta wait_duration) { 620 base::TimeDelta wait_duration) {
466 lock_.AssertAcquired(); 621 lock_.AssertAcquired();
467 DCHECK_GE(frames_decoded_, 0); 622 DCHECK_GE(frames_decoded_, 0);
468 DCHECK_LE(frames_dropped_, frames_decoded_); 623 DCHECK_GE(frames_dropped_, 0);
469 624
470 if (frames_decoded_) { 625 if (frames_decoded_ || frames_dropped_) {
471 PipelineStatistics statistics; 626 PipelineStatistics statistics;
472 statistics.video_frames_decoded = frames_decoded_; 627 statistics.video_frames_decoded = frames_decoded_;
473 statistics.video_frames_dropped = frames_dropped_; 628 statistics.video_frames_dropped = frames_dropped_;
474 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics)); 629 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics));
475 630
476 frames_decoded_ = 0; 631 frames_decoded_ = 0;
477 frames_dropped_ = 0; 632 frames_dropped_ = 0;
478 } 633 }
479 634
480 frame_available_.TimedWait(wait_duration); 635 if (wait_duration > base::TimeDelta())
636 frame_available_.TimedWait(wait_duration);
637 }
638
639 void VideoRendererImpl::MaybeStopSinkAfterFirstPaint() {
640 DCHECK(task_runner_->BelongsToCurrentThread());
641 DCHECK(use_new_video_renderering_path_);
642
643 {
644 base::AutoLock auto_lock(lock_);
645 render_first_frame_and_stop_ = false;
646 }
647
648 if (!time_progressing_ && sink_started_)
649 StopSink();
650 }
651
652 void VideoRendererImpl::RestartBackgroundRenderTimer() {
653 DCHECK(use_new_video_renderering_path_);
654 if (!drop_frames_ || !should_use_background_renderering_)
655 return;
656
657 // This controls the amount of time allowed between Render() callbacks before
658 // we assume they have timed out and it's necessary to start expiring
659 // unrendered frames.
660 background_rendering_timer_.Start(
661 FROM_HERE, background_rendering_timeout_,
662 base::Bind(&VideoRendererImpl::BackgroundRender,
663 weak_factory_.GetWeakPtr()));
664 }
665
666 void VideoRendererImpl::BackgroundRender() {
667 base::AutoLock auto_lock(lock_);
668 BackgroundRender_Locked();
669 }
670
671 void VideoRendererImpl::BackgroundRender_Locked() {
672 DCHECK(task_runner_->BelongsToCurrentThread());
673 DCHECK_EQ(state_, kPlaying);
674 lock_.AssertAcquired();
675
676 // If a Render() call never occurs after starting playback for the first frame
677 // we need to carry out the duties of Render() and stop the sink. We don't
678 // call MaybeStopSinkAfterFirstPaint() since it may need to mutate |sink_|,
679 // which can't be done under lock.
680 if (render_first_frame_and_stop_) {
681 task_runner_->PostTask(
682 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
683 weak_factory_.GetWeakPtr()));
684
685 // MaybeStopSinkAfterFirstPaint isn't going to stop the sink if time is
686 // currently progressing, so only bail out if necessary.
687 if (!time_progressing_) {
688 RestartBackgroundRenderTimer();
689 return;
690 }
691 }
692
693 // First clear as many expired frames as we can.
694 algorithm_->RemoveExpiredFrames(tick_clock_->NowTicks());
695 is_background_rendering_ = true;
696
697 // See if we've run out of frames and need to fire the ended callback.
698 MaybeFireEndedCallback();
699 if (rendered_end_of_stream_)
700 return;
701
702 // Start queuing new frames and scheduled this process again otherwise.
703 AttemptRead_Locked();
704 UpdateStatsAndWait_Locked(base::TimeDelta());
705 RestartBackgroundRenderTimer();
706 }
707
708 bool VideoRendererImpl::HaveReachedBufferingCap() {
709 DCHECK(task_runner_->BelongsToCurrentThread());
710 if (use_new_video_renderering_path_) {
711 // When the display rate is less than the frame rate, the effective frames
712 // queued may be much smaller than the actual number of frames queued. Here
713 // we ensure that frames_queued() doesn't get excessive.
714 return algorithm_->EffectiveFramesQueued() >=
715 static_cast<size_t>(limits::kMaxVideoFrames) ||
716 algorithm_->frames_queued() >=
717 static_cast<size_t>(3 * limits::kMaxVideoFrames);
718 }
719
720 return ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames);
721 }
722
723 void VideoRendererImpl::StartSink() {
724 DCHECK(task_runner_->BelongsToCurrentThread());
725 sink_->Start(this);
726 sink_started_ = true;
727 RestartBackgroundRenderTimer();
728 }
729
730 void VideoRendererImpl::StopSink() {
731 DCHECK(task_runner_->BelongsToCurrentThread());
732 sink_->Stop();
733 sink_started_ = false;
734 background_rendering_timer_.Stop();
735 is_background_rendering_ = false;
736 }
737
738 size_t VideoRendererImpl::MaybeFireEndedCallback() {
739 // If there's only one frame in the video or Render() was never called, the
740 // algorithm will have one frame linger indefinitely. So in cases where the
741 // frame duration is unknown nad we've recieved EOS, fire it once we get down
742 // to a single frame.
743 const size_t effective_frames = algorithm_->EffectiveFramesQueued();
744
745 if ((!effective_frames ||
746 (algorithm_->frames_queued() == 1u &&
747 algorithm_->average_frame_duration() == base::TimeDelta())) &&
748 received_end_of_stream_ && !rendered_end_of_stream_) {
749 rendered_end_of_stream_ = true;
750 task_runner_->PostTask(FROM_HERE, ended_cb_);
751 }
752
753 return effective_frames;
481 } 754 }
482 755
483 } // namespace media 756 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698