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

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: Update LoginCustomFlags histogram. 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
« no previous file with comments | « media/renderers/video_renderer_impl.h ('k') | media/renderers/video_renderer_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_++;
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_++;
322 frames_dropped_++; 423 frames_dropped_++;
323 424
324 task_runner_->PostTask( 425 task_runner_->PostTask(
325 FROM_HERE, 426 FROM_HERE,
326 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr())); 427 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
327 } 428 }
328 429
329 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status, 430 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
330 const scoped_refptr<VideoFrame>& frame) { 431 const scoped_refptr<VideoFrame>& frame) {
331 DCHECK(task_runner_->BelongsToCurrentThread()); 432 DCHECK(task_runner_->BelongsToCurrentThread());
332 base::AutoLock auto_lock(lock_); 433 bool start_sink = false;
333 DCHECK_NE(state_, kUninitialized); 434 {
334 DCHECK_NE(state_, kFlushed); 435 base::AutoLock auto_lock(lock_);
436 DCHECK_NE(state_, kUninitialized);
437 DCHECK_NE(state_, kFlushed);
335 438
336 CHECK(pending_read_); 439 CHECK(pending_read_);
337 pending_read_ = false; 440 pending_read_ = false;
338 441
339 if (status == VideoFrameStream::DECODE_ERROR || 442 if (status == VideoFrameStream::DECODE_ERROR ||
340 status == VideoFrameStream::DECRYPT_ERROR) { 443 status == VideoFrameStream::DECRYPT_ERROR) {
341 DCHECK(!frame.get()); 444 DCHECK(!frame.get());
342 PipelineStatus error = PIPELINE_ERROR_DECODE; 445 PipelineStatus error = PIPELINE_ERROR_DECODE;
343 if (status == VideoFrameStream::DECRYPT_ERROR) 446 if (status == VideoFrameStream::DECRYPT_ERROR)
344 error = PIPELINE_ERROR_DECRYPT; 447 error = PIPELINE_ERROR_DECRYPT;
345 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error)); 448 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
346 return; 449 return;
450 }
451
452 // Already-queued VideoFrameStream ReadCB's can fire after various state
453 // transitions have happened; in that case just drop those frames
454 // immediately.
455 if (state_ == kFlushing)
456 return;
457
458 DCHECK_EQ(state_, kPlaying);
459
460 // Can happen when demuxers are preparing for a new Seek().
461 if (!frame.get()) {
462 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
463 return;
464 }
465
466 if (frame->end_of_stream()) {
467 DCHECK(!received_end_of_stream_);
468 received_end_of_stream_ = true;
469
470 // See if we can fire EOS immediately instead of waiting for Render() or
471 // BackgroundRender() to tick. We also want to fire EOS if we have no
472 // frames and received EOS.
473 if (use_new_video_renderering_path_ &&
474 (time_progressing_ || !algorithm_->frames_queued())) {
475 MaybeFireEndedCallback();
476 }
477 } else {
478 // Maintain the latest frame decoded so the correct frame is displayed
479 // after prerolling has completed.
480 if (frame->timestamp() <= start_timestamp_) {
481 if (use_new_video_renderering_path_)
482 algorithm_->Reset();
483 ready_frames_.clear();
484 }
485 AddReadyFrame_Locked(frame);
486 }
487
488 // Signal buffering state if we've met our conditions for having enough
489 // data.
490 if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked()) {
491 TransitionToHaveEnough_Locked();
492 if (use_new_video_renderering_path_ && !sink_started_ &&
493 !rendered_end_of_stream_) {
494 start_sink = true;
495 render_first_frame_and_stop_ = true;
496 }
497 }
498
499 // BackgroundRender may not be ticking fast enough by itself to remove
500 // expired frames, so give it a boost here by ensuring we don't exit the
501 // decoding cycle too early.
502 if (is_background_rendering_) {
503 DCHECK(use_new_video_renderering_path_);
504 BackgroundRender_Locked();
505 }
506
507 // Always request more decoded video if we have capacity. This serves two
508 // purposes:
509 // 1) Prerolling while paused
510 // 2) Keeps decoding going if video rendering thread starts falling behind
511 AttemptRead_Locked();
347 } 512 }
348 513
349 // Already-queued VideoFrameStream ReadCB's can fire after various state 514 // 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. 515 // if we have previously underflowed, yet weren't stopped because of audio.
351 if (state_ == kFlushing) 516 if (use_new_video_renderering_path_ && start_sink) {
352 return; 517 DCHECK(!sink_started_);
353 518 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 } 519 }
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 } 520 }
383 521
384 bool VideoRendererImpl::HaveEnoughData_Locked() { 522 bool VideoRendererImpl::HaveEnoughData_Locked() {
385 DCHECK_EQ(state_, kPlaying); 523 DCHECK_EQ(state_, kPlaying);
386 return received_end_of_stream_ || 524
387 !video_frame_stream_->CanReadWithoutStalling() || 525 if (received_end_of_stream_ || !video_frame_stream_->CanReadWithoutStalling())
388 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) || 526 return true;
389 (low_delay_ && ready_frames_.size() > 0); 527
528 if (HaveReachedBufferingCap())
529 return true;
530
531 if (!low_delay_)
532 return false;
533
534 return ready_frames_.size() > 0 ||
535 (use_new_video_renderering_path_ && algorithm_->frames_queued() > 0);
390 } 536 }
391 537
392 void VideoRendererImpl::TransitionToHaveEnough_Locked() { 538 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
393 DCHECK(task_runner_->BelongsToCurrentThread()); 539 DCHECK(task_runner_->BelongsToCurrentThread());
394 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 540 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
395 541
396 if (!ready_frames_.empty()) { 542 if (!ready_frames_.empty()) {
543 DCHECK(!use_new_video_renderering_path_);
397 // Because the clock might remain paused in for an undetermined amount 544 // Because the clock might remain paused in for an undetermined amount
398 // of time (e.g., seeking while paused), paint the first frame. 545 // of time (e.g., seeking while paused), paint the first frame.
399 PaintNextReadyFrame_Locked(); 546 PaintNextReadyFrame_Locked();
400 } 547 }
401 548
402 buffering_state_ = BUFFERING_HAVE_ENOUGH; 549 buffering_state_ = BUFFERING_HAVE_ENOUGH;
403 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); 550 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
404 } 551 }
405 552
406 void VideoRendererImpl::AddReadyFrame_Locked( 553 void VideoRendererImpl::AddReadyFrame_Locked(
407 const scoped_refptr<VideoFrame>& frame) { 554 const scoped_refptr<VideoFrame>& frame) {
408 DCHECK(task_runner_->BelongsToCurrentThread()); 555 DCHECK(task_runner_->BelongsToCurrentThread());
409 lock_.AssertAcquired(); 556 lock_.AssertAcquired();
410 DCHECK(!frame->end_of_stream()); 557 DCHECK(!frame->end_of_stream());
411 558
559 frames_decoded_++;
560
561 if (use_new_video_renderering_path_) {
562 algorithm_->EnqueueFrame(frame);
563 return;
564 }
565
412 ready_frames_.push_back(frame); 566 ready_frames_.push_back(frame);
413 DCHECK_LE(ready_frames_.size(), 567 DCHECK_LE(ready_frames_.size(),
414 static_cast<size_t>(limits::kMaxVideoFrames)); 568 static_cast<size_t>(limits::kMaxVideoFrames));
415 569
416 // Avoid needlessly waking up |thread_| unless playing. 570 // Avoid needlessly waking up |thread_| unless playing.
417 if (state_ == kPlaying) 571 if (state_ == kPlaying)
418 frame_available_.Signal(); 572 frame_available_.Signal();
419 } 573 }
420 574
421 void VideoRendererImpl::AttemptRead() { 575 void VideoRendererImpl::AttemptRead() {
422 base::AutoLock auto_lock(lock_); 576 base::AutoLock auto_lock(lock_);
423 AttemptRead_Locked(); 577 AttemptRead_Locked();
424 } 578 }
425 579
426 void VideoRendererImpl::AttemptRead_Locked() { 580 void VideoRendererImpl::AttemptRead_Locked() {
427 DCHECK(task_runner_->BelongsToCurrentThread()); 581 DCHECK(task_runner_->BelongsToCurrentThread());
428 lock_.AssertAcquired(); 582 lock_.AssertAcquired();
429 583
430 if (pending_read_ || received_end_of_stream_ || 584 if (pending_read_ || received_end_of_stream_)
431 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) {
432 return; 585 return;
433 } 586
587 if (HaveReachedBufferingCap())
588 return;
434 589
435 switch (state_) { 590 switch (state_) {
436 case kPlaying: 591 case kPlaying:
437 pending_read_ = true; 592 pending_read_ = true;
438 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady, 593 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
439 weak_factory_.GetWeakPtr())); 594 weak_factory_.GetWeakPtr()));
440 return; 595 return;
441 596
442 case kUninitialized: 597 case kUninitialized:
443 case kInitializing: 598 case kInitializing:
(...skipping 14 matching lines...) Expand all
458 613
459 state_ = kFlushed; 614 state_ = kFlushed;
460 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks(); 615 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks();
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::StartBackgroundRenderTimer() {
653 DCHECK(use_new_video_renderering_path_);
654 if (!drop_frames_ || !should_use_background_renderering_)
655 return;
656
657 // |last_render_time_| and |background_rendering_timer_| work in conjunction
658 // to ensure we don't exceed |kBackgroundRenderingTimeoutMs| between calls to
659 // Render(). BackgroundRender() will tick repeatedly and verify that Render()
660 // has fired within the allotted time, by checking |last_render_time_|.
661 last_render_time_ = tick_clock_->NowTicks();
662 background_rendering_timer_.Start(
663 FROM_HERE, background_rendering_timeout_,
664 base::Bind(&VideoRendererImpl::BackgroundRender,
665 weak_factory_.GetWeakPtr()));
666 }
667
668 void VideoRendererImpl::BackgroundRender() {
669 base::AutoLock auto_lock(lock_);
670 BackgroundRender_Locked();
671 }
672
673 void VideoRendererImpl::BackgroundRender_Locked() {
674 DCHECK(task_runner_->BelongsToCurrentThread());
675 DCHECK_EQ(state_, kPlaying);
676 lock_.AssertAcquired();
677
678 // If a Render() call never occurs after starting playback for the first frame
679 // we need to carry out the duties of Render() and stop the sink. We don't
680 // call MaybeStopSinkAfterFirstPaint() since it may need to mutate |sink_|,
681 // which can't be done under lock.
682 if (render_first_frame_and_stop_) {
683 task_runner_->PostTask(
684 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
685 weak_factory_.GetWeakPtr()));
686
687 // MaybeStopSinkAfterFirstPaint isn't going to stop the sink if time is
688 // currently progressing, so only bail out if necessary.
689 if (!time_progressing_)
690 return;
691 }
692
693 // Do nothing if Render() calls are progressing normally.
694 if (tick_clock_->NowTicks() - last_render_time_ <
695 background_rendering_timeout_) {
696 return;
697 }
698
699 // First clear as many expired frames as we can.
700 algorithm_->RemoveExpiredFrames(tick_clock_->NowTicks());
701 is_background_rendering_ = true;
702
703 // See if we've run out of frames and need to fire the ended callback.
704 MaybeFireEndedCallback();
705 if (rendered_end_of_stream_)
706 return;
707
708 // Start queuing new frames and scheduled this process again otherwise.
709 AttemptRead_Locked();
710 UpdateStatsAndWait_Locked(base::TimeDelta());
711 }
712
713 bool VideoRendererImpl::HaveReachedBufferingCap() {
714 DCHECK(task_runner_->BelongsToCurrentThread());
715 if (use_new_video_renderering_path_) {
716 // When the display rate is less than the frame rate, the effective frames
717 // queued may be much smaller than the actual number of frames queued. Here
718 // we ensure that frames_queued() doesn't get excessive.
719 return algorithm_->EffectiveFramesQueued() >=
720 static_cast<size_t>(limits::kMaxVideoFrames) ||
721 algorithm_->frames_queued() >=
722 static_cast<size_t>(3 * limits::kMaxVideoFrames);
723 }
724
725 return ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames);
726 }
727
728 void VideoRendererImpl::StartSink() {
729 DCHECK(task_runner_->BelongsToCurrentThread());
730 sink_->Start(this);
731 sink_started_ = true;
732 StartBackgroundRenderTimer();
733 }
734
735 void VideoRendererImpl::StopSink() {
736 DCHECK(task_runner_->BelongsToCurrentThread());
737 sink_->Stop();
738 sink_started_ = false;
739 background_rendering_timer_.Stop();
740 is_background_rendering_ = false;
741 }
742
743 size_t VideoRendererImpl::MaybeFireEndedCallback() {
744 // If there's only one frame in the video or Render() was never called, the
745 // algorithm will have one frame linger indefinitely. So in cases where the
746 // frame duration is unknown and we've received EOS, fire it once we get down
747 // to a single frame.
748 const size_t effective_frames = algorithm_->EffectiveFramesQueued();
749
750 if ((!effective_frames ||
751 (algorithm_->frames_queued() == 1u &&
752 algorithm_->average_frame_duration() == base::TimeDelta())) &&
753 received_end_of_stream_ && !rendered_end_of_stream_) {
754 rendered_end_of_stream_ = true;
755 task_runner_->PostTask(FROM_HERE, ended_cb_);
756 }
757
758 return effective_frames;
481 } 759 }
482 760
483 } // namespace media 761 } // namespace media
OLDNEW
« no previous file with comments | « media/renderers/video_renderer_impl.h ('k') | media/renderers/video_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698