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

Side by Side Diff: media/filters/video_renderer_base.cc

Issue 8417019: Simplify VideoDecodeEngine interface by making everything synchronous. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: recycling: vanquished Created 9 years, 1 month 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "base/bind.h" 5 #include "base/bind.h"
6 #include "base/callback.h" 6 #include "base/callback.h"
7 #include "base/threading/platform_thread.h" 7 #include "base/threading/platform_thread.h"
8 #include "media/base/buffers.h" 8 #include "media/base/buffers.h"
9 #include "media/base/filter_host.h" 9 #include "media/base/filter_host.h"
10 #include "media/base/limits.h" 10 #include "media/base/limits.h"
(...skipping 12 matching lines...) Expand all
23 23
24 // The number of milliseconds to idle when we do not have anything to do. 24 // The number of milliseconds to idle when we do not have anything to do.
25 // Nothing special about the value, other than we're being more OS-friendly 25 // Nothing special about the value, other than we're being more OS-friendly
26 // than sleeping for 1 millisecond. 26 // than sleeping for 1 millisecond.
27 static const int kIdleMilliseconds = 10; 27 static const int kIdleMilliseconds = 10;
28 28
29 VideoRendererBase::VideoRendererBase() 29 VideoRendererBase::VideoRendererBase()
30 : frame_available_(&lock_), 30 : frame_available_(&lock_),
31 state_(kUninitialized), 31 state_(kUninitialized),
32 thread_(base::kNullThreadHandle), 32 thread_(base::kNullThreadHandle),
33 pending_reads_(0), 33 pending_read_(false),
34 pending_paint_(false), 34 pending_paint_(false),
35 pending_paint_with_last_available_(false), 35 pending_paint_with_last_available_(false),
36 playback_rate_(0) { 36 playback_rate_(0),
37 frame_ready_cb_(base::Bind(&VideoRendererBase::FrameReady,
38 base::Unretained(this))) {
37 } 39 }
38 40
39 VideoRendererBase::~VideoRendererBase() { 41 VideoRendererBase::~VideoRendererBase() {
40 base::AutoLock auto_lock(lock_); 42 base::AutoLock auto_lock(lock_);
41 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; 43 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
42 } 44 }
43 45
44 void VideoRendererBase::Play(const base::Closure& callback) { 46 void VideoRendererBase::Play(const base::Closure& callback) {
45 base::AutoLock auto_lock(lock_); 47 base::AutoLock auto_lock(lock_);
46 DCHECK_EQ(kPrerolled, state_); 48 DCHECK_EQ(kPrerolled, state_);
47 state_ = kPlaying; 49 state_ = kPlaying;
48 callback.Run(); 50 callback.Run();
49 } 51 }
50 52
51 void VideoRendererBase::Pause(const base::Closure& callback) { 53 void VideoRendererBase::Pause(const base::Closure& callback) {
52 base::AutoLock auto_lock(lock_); 54 base::AutoLock auto_lock(lock_);
53 DCHECK(state_ != kUninitialized || state_ == kError); 55 DCHECK(state_ != kUninitialized || state_ == kError);
54 state_ = kPaused; 56 state_ = kPaused;
55 callback.Run(); 57 callback.Run();
56 } 58 }
57 59
58 void VideoRendererBase::Flush(const base::Closure& callback) { 60 void VideoRendererBase::Flush(const base::Closure& callback) {
59 base::AutoLock auto_lock(lock_); 61 base::AutoLock auto_lock(lock_);
60 DCHECK_EQ(state_, kPaused); 62 DCHECK_EQ(state_, kPaused);
61 flush_callback_ = callback; 63 flush_callback_ = callback;
62 state_ = kFlushing; 64 state_ = kFlushing;
63 65
64 if (!pending_paint_) 66 AttemptFlush_Locked();
65 FlushBuffers_Locked();
66 } 67 }
67 68
68 void VideoRendererBase::Stop(const base::Closure& callback) { 69 void VideoRendererBase::Stop(const base::Closure& callback) {
69 base::PlatformThreadHandle old_thread_handle = base::kNullThreadHandle; 70 base::PlatformThreadHandle old_thread_handle = base::kNullThreadHandle;
70 { 71 {
71 base::AutoLock auto_lock(lock_); 72 base::AutoLock auto_lock(lock_);
72 state_ = kStopped; 73 state_ = kStopped;
73 74
74 if (!pending_paint_ && !pending_paint_with_last_available_) 75 if (!pending_paint_ && !pending_paint_with_last_available_)
75 DoStopOrErrorFlush_Locked(); 76 DoStopOrError_Locked();
76 77
77 // Clean up our thread if present. 78 // Clean up our thread if present.
78 if (thread_) { 79 if (thread_) {
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Given the code below shouldn't this be (thread_ !=
scherkus (not reviewing) 2011/11/03 04:55:59 Done.
79 // Signal the thread since it's possible to get stopped with the video 80 // Signal the thread since it's possible to get stopped with the video
80 // thread waiting for a read to complete. 81 // thread waiting for a read to complete.
81 frame_available_.Signal(); 82 frame_available_.Signal();
82 old_thread_handle = thread_; 83 old_thread_handle = thread_;
83 thread_ = base::kNullThreadHandle; 84 thread_ = base::kNullThreadHandle;
84 } 85 }
85 } 86 }
86 if (old_thread_handle) 87 if (old_thread_handle)
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 ditto
scherkus (not reviewing) 2011/11/03 04:55:59 Done.
87 base::PlatformThread::Join(old_thread_handle); 88 base::PlatformThread::Join(old_thread_handle);
88 89
89 // Signal the subclass we're stopping. 90 // Signal the subclass we're stopping.
90 OnStop(callback); 91 OnStop(callback);
91 } 92 }
92 93
93 void VideoRendererBase::SetPlaybackRate(float playback_rate) { 94 void VideoRendererBase::SetPlaybackRate(float playback_rate) {
94 base::AutoLock auto_lock(lock_); 95 base::AutoLock auto_lock(lock_);
95 playback_rate_ = playback_rate; 96 playback_rate_ = playback_rate;
96 } 97 }
(...skipping 16 matching lines...) Expand all
113 // Already get enough buffers from decoder. 114 // Already get enough buffers from decoder.
114 run_callback = true; 115 run_callback = true;
115 } else { 116 } else {
116 // Otherwise we are either kFlushed or kSeeking, but without enough 117 // Otherwise we are either kFlushed or kSeeking, but without enough
117 // buffers we should save the callback function and call it later. 118 // buffers we should save the callback function and call it later.
118 state_ = kSeeking; 119 state_ = kSeeking;
119 seek_cb_ = cb; 120 seek_cb_ = cb;
120 } 121 }
121 122
122 seek_timestamp_ = time; 123 seek_timestamp_ = time;
123 ScheduleRead_Locked(); 124 AttemptRead_Locked();
124 } 125 }
125 126
126 if (run_callback) 127 if (run_callback)
127 cb.Run(PIPELINE_OK); 128 cb.Run(PIPELINE_OK);
128 } 129 }
129 130
130 void VideoRendererBase::Initialize(VideoDecoder* decoder, 131 void VideoRendererBase::Initialize(VideoDecoder* decoder,
131 const base::Closure& callback, 132 const base::Closure& callback,
132 const StatisticsCallback& stats_callback) { 133 const StatisticsCallback& stats_callback) {
133 base::AutoLock auto_lock(lock_); 134 base::AutoLock auto_lock(lock_);
134 DCHECK(decoder); 135 DCHECK(decoder);
135 DCHECK(!callback.is_null()); 136 DCHECK(!callback.is_null());
136 DCHECK(!stats_callback.is_null()); 137 DCHECK(!stats_callback.is_null());
137 DCHECK_EQ(kUninitialized, state_); 138 DCHECK_EQ(kUninitialized, state_);
138 decoder_ = decoder; 139 decoder_ = decoder;
139 140
140 statistics_callback_ = stats_callback; 141 statistics_callback_ = stats_callback;
141 142
142 decoder_->set_consume_video_frame_callback(
143 base::Bind(&VideoRendererBase::ConsumeVideoFrame,
144 base::Unretained(this)));
145
146 // Notify the pipeline of the video dimensions. 143 // Notify the pipeline of the video dimensions.
147 host()->SetNaturalVideoSize(decoder_->natural_size()); 144 host()->SetNaturalVideoSize(decoder_->natural_size());
148 145
149 // Initialize the subclass. 146 // Initialize the subclass.
150 // TODO(scherkus): do we trust subclasses not to do something silly while 147 // TODO(scherkus): do we trust subclasses not to do something silly while
151 // we're holding the lock? 148 // we're holding the lock?
152 if (!OnInitialize(decoder)) { 149 if (!OnInitialize(decoder)) {
153 EnterErrorState_Locked(PIPELINE_ERROR_INITIALIZATION_FAILED); 150 EnterErrorState_Locked(PIPELINE_ERROR_INITIALIZATION_FAILED);
154 callback.Run(); 151 callback.Run();
155 return; 152 return;
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 // exceptions that cause us to drop a frame and/or consider painting a 259 // exceptions that cause us to drop a frame and/or consider painting a
263 // "next" frame. 260 // "next" frame.
264 if (next_frame->GetTimestamp() > host()->GetTime() + kIdleTimeDelta && 261 if (next_frame->GetTimestamp() > host()->GetTime() + kIdleTimeDelta &&
265 current_frame_ && 262 current_frame_ &&
266 current_frame_->GetTimestamp() <= host()->GetDuration()) { 263 current_frame_->GetTimestamp() <= host()->GetDuration()) {
267 continue; 264 continue;
268 } 265 }
269 266
270 // If we got here then: 267 // If we got here then:
271 // 1. next frame's timestamp is already current; or 268 // 1. next frame's timestamp is already current; or
272 // 2. we do not have any current frame yet anyway; or 269 // 2. we do not have a current frame yet; or
273 // 3. a special case when the stream is badly formatted and 270 // 3. a special case when the stream is badly formatted and
274 // we got a frame with timestamp greater than overall duration. 271 // we got a frame with timestamp greater than overall duration.
275 // In this case we should proceed anyway and try to obtain the 272 // In this case we should proceed anyway and try to obtain the
276 // end-of-stream packet. 273 // end-of-stream packet.
277 274
278 if (pending_paint_) { 275 if (pending_paint_) {
279 // The pending paint might be really slow. Check if we have any frames 276 // The pending paint might be really slow. Check if we have any frames
280 // available that we can drop if they've already expired. 277 // available that we can drop if they've already expired.
281 while (!frames_queue_ready_.empty()) { 278 while (!frames_queue_ready_.empty()) {
282 // Can't drop anything if we're at the end. 279 // Can't drop anything if we're at the end.
283 if (frames_queue_ready_.front()->IsEndOfStream()) 280 if (frames_queue_ready_.front()->IsEndOfStream())
284 break; 281 break;
285 282
286 base::TimeDelta remaining_time = 283 base::TimeDelta remaining_time =
287 frames_queue_ready_.front()->GetTimestamp() - host()->GetTime(); 284 frames_queue_ready_.front()->GetTimestamp() - host()->GetTime();
288 285
289 // Still a chance we can render the frame! 286 // Still a chance we can render the frame!
290 if (remaining_time.InMicroseconds() > 0) 287 if (remaining_time.InMicroseconds() > 0)
291 break; 288 break;
292 289
293 // Frame dropped: transfer ready frame into done queue and read again. 290 // Frame dropped: read again.
294 frames_queue_done_.push_back(frames_queue_ready_.front()); 291 ++frames_dropped;
295 frames_queue_ready_.pop_front(); 292 frames_queue_ready_.pop_front();
296 ScheduleRead_Locked(); 293 AttemptRead_Locked();
297 ++frames_dropped;
298 } 294 }
299 295
300 // Continue waiting for the current paint to finish. 296 // Continue waiting for the current paint to finish.
301 continue; 297 continue;
302 } 298 }
303 299
304 // Congratulations! You've made it past the video frame timing gauntlet. 300 // Congratulations! You've made it past the video frame timing gauntlet.
305 // 301 //
306 // We can now safely update the current frame, request another frame, and 302 // We can now safely update the current frame, request another frame, and
307 // signal to the client that a new frame is available. 303 // signal to the client that a new frame is available.
308 frames_queue_done_.push_back(current_frame_);
309 current_frame_ = frames_queue_ready_.front(); 304 current_frame_ = frames_queue_ready_.front();
310 frames_queue_ready_.pop_front(); 305 frames_queue_ready_.pop_front();
311 ScheduleRead_Locked(); 306 AttemptRead_Locked();
312 307
313 base::AutoUnlock auto_unlock(lock_); 308 base::AutoUnlock auto_unlock(lock_);
314 OnFrameAvailable(); 309 OnFrameAvailable();
315 } 310 }
316 } 311 }
317 312
318 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { 313 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) {
319 base::AutoLock auto_lock(lock_); 314 base::AutoLock auto_lock(lock_);
320 DCHECK(!pending_paint_ && !pending_paint_with_last_available_); 315 DCHECK(!pending_paint_ && !pending_paint_with_last_available_);
321 316
322 if ((!current_frame_ || current_frame_->IsEndOfStream()) && 317 if ((!current_frame_ || current_frame_->IsEndOfStream()) &&
323 (!last_available_frame_ || 318 (!last_available_frame_ || last_available_frame_->IsEndOfStream())) {
324 last_available_frame_->IsEndOfStream())) {
325 *frame_out = NULL; 319 *frame_out = NULL;
326 return; 320 return;
327 } 321 }
328 322
329 // We should have initialized and have the current frame. 323 // We should have initialized and have the current frame.
330 DCHECK_NE(state_, kUninitialized); 324 DCHECK_NE(state_, kUninitialized);
331 DCHECK_NE(state_, kStopped); 325 DCHECK_NE(state_, kStopped);
332 DCHECK_NE(state_, kError); 326 DCHECK_NE(state_, kError);
333 327
334 if (current_frame_) { 328 if (current_frame_) {
(...skipping 22 matching lines...) Expand all
357 pending_paint_with_last_available_ = false; 351 pending_paint_with_last_available_ = false;
358 } else { 352 } else {
359 DCHECK(!frame); 353 DCHECK(!frame);
360 } 354 }
361 355
362 // We had cleared the |pending_paint_| flag, there are chances that current 356 // We had cleared the |pending_paint_| flag, there are chances that current
363 // frame is timed-out. We will wake up our main thread to advance the current 357 // frame is timed-out. We will wake up our main thread to advance the current
364 // frame when this is true. 358 // frame when this is true.
365 frame_available_.Signal(); 359 frame_available_.Signal();
366 if (state_ == kFlushing) { 360 if (state_ == kFlushing) {
367 FlushBuffers_Locked(); 361 AttemptFlush_Locked();
368 } else if (state_ == kError || state_ == kStopped) { 362 } else if (state_ == kError || state_ == kStopped) {
369 DoStopOrErrorFlush_Locked(); 363 DoStopOrError_Locked();
370 } 364 }
371 } 365 }
372 366
373 void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { 367 void VideoRendererBase::FrameReady(scoped_refptr<VideoFrame> frame) {
374 if (frame) { 368 DCHECK(frame);
375 PipelineStatistics statistics;
376 statistics.video_frames_decoded = 1;
377 statistics_callback_.Run(statistics);
378 }
379 369
380 base::AutoLock auto_lock(lock_); 370 base::AutoLock auto_lock(lock_);
371 DCHECK_NE(state_, kUninitialized);
372 DCHECK_NE(state_, kStopped);
373 DCHECK_NE(state_, kError);
374 CHECK(pending_read_);
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 DCHECK?
scherkus (not reviewing) 2011/11/03 04:55:59 Again this one of those things where a callback wa
381 375
382 if (!frame) { 376 pending_read_ = false;
383 EnterErrorState_Locked(PIPELINE_ERROR_DECODE); 377
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Why not keep this?
378 // Decoder could reach seek state before our Seek() get called.
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 s/get/got/
379 // We will enter kSeeking
380 if (state_ == kFlushed) {
381 CHECK(false) << "I don't think this is possible";
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 CHECK(false) is always better spelled LOG(FATAL) B
scherkus (not reviewing) 2011/11/03 04:55:59 Left these CHECK()s in for local testing -- they w
382 //state_ = kSeeking;
384 return; 383 return;
385 } 384 }
386 385
387 // Decoder could reach seek state before our Seek() get called. 386 if (state_ == kPaused) {
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Can't this happen based on the "Prerolling while p
scherkus (not reviewing) 2011/11/03 04:55:59 I believe it can: T1: VRB holds lock inside FrameR
388 // We will enter kSeeking 387 CHECK(false) << "I don't think this is possible";
389 if (state_ == kFlushed) 388 //frame_queue_ready_.push_back(video_frame);
390 state_ = kSeeking; 389 return;
390 }
391 391
392 // Synchronous flush between filters should prevent this from happening. 392 if (state_ == kFlushing) {
393 DCHECK_NE(state_, kStopped); 393 AttemptFlush_Locked();
394 if (frame && !frame->IsEndOfStream())
395 --pending_reads_;
396
397 DCHECK_NE(state_, kUninitialized);
398 DCHECK_NE(state_, kStopped);
399 DCHECK_NE(state_, kError);
400
401 if (state_ == kPaused || state_ == kFlushing) {
402 // Decoder are flushing rubbish video frame, we will not display them.
403 if (frame && !frame->IsEndOfStream())
404 frames_queue_done_.push_back(frame);
405 DCHECK_LE(frames_queue_done_.size(),
406 static_cast<size_t>(Limits::kMaxVideoFrames));
407
408 // Excluding kPause here, because in pause state, we will never
409 // transfer out-bounding buffer. We do not flush buffer when Compositor
410 // hold reference to our video frame either.
411 if (state_ == kFlushing && pending_paint_ == false)
412 FlushBuffers_Locked();
413
414 return; 394 return;
415 } 395 }
416 396
417 // Discard frames until we reach our desired seek timestamp. 397 // Discard frames until we reach our desired seek timestamp.
418 if (state_ == kSeeking && !frame->IsEndOfStream() && 398 if (state_ == kSeeking && !frame->IsEndOfStream() &&
419 (frame->GetTimestamp() + frame->GetDuration()) <= seek_timestamp_) { 399 (frame->GetTimestamp() + frame->GetDuration()) <= seek_timestamp_) {
420 frames_queue_done_.push_back(frame); 400 AttemptRead_Locked();
421 ScheduleRead_Locked(); 401 return;
422 } else {
423 frames_queue_ready_.push_back(frame);
424 DCHECK_LE(frames_queue_ready_.size(),
425 static_cast<size_t>(Limits::kMaxVideoFrames));
426 frame_available_.Signal();
427 } 402 }
428 403
429 // Check for our preroll complete condition. 404 // This one's a keeper! Place it in the ready queue.
430 bool new_frame_available = false; 405 frames_queue_ready_.push_back(frame);
431 if (state_ == kSeeking) { 406 DCHECK_LE(frames_queue_ready_.size(),
432 if (frames_queue_ready_.size() == Limits::kMaxVideoFrames || 407 static_cast<size_t>(Limits::kMaxVideoFrames));
433 frame->IsEndOfStream()) { 408 frame_available_.Signal();
434 // We're paused, so make sure we update |current_frame_| to represent
435 // our new location.
436 state_ = kPrerolled;
437 409
438 // Because we might remain paused (i.e., we were not playing before we 410 PipelineStatistics statistics;
439 // received a seek), we can't rely on ThreadMain() to notify the subclass 411 statistics.video_frames_decoded = 1;
440 // the frame has been updated. 412 statistics_callback_.Run(statistics);
441 scoped_refptr<VideoFrame> first_frame;
442 first_frame = frames_queue_ready_.front();
443 if (!first_frame->IsEndOfStream()) {
444 frames_queue_ready_.pop_front();
445 current_frame_ = first_frame;
446 }
447 new_frame_available = true;
448 413
449 // If we reach prerolled state before Seek() is called by pipeline, 414 // Always request more decoded video if we have capacity. This serves two
450 // |seek_callback_| is not set, we will return immediately during 415 // purposes:
451 // when Seek() is eventually called. 416 // 1) Prerolling while paused
452 if (!seek_cb_.is_null()) { 417 // 2) Keeps decoding going if video rendering thread starts falling behind
453 ResetAndRunCB(&seek_cb_, PIPELINE_OK); 418 if (frames_queue_ready_.size() < Limits::kMaxVideoFrames &&
454 } 419 !frame->IsEndOfStream()) {
455 } 420 AttemptRead_Locked();
456 } else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) { 421 return;
457 OnFlushDone_Locked();
458 } 422 }
459 423
460 if (new_frame_available) { 424 // If we're at capacity or end of stream while seeking we need to transition
461 base::AutoUnlock auto_unlock(lock_); 425 // to prerolled.
426 if (state_ == kSeeking) {
427 state_ = kPrerolled;
428
429 // Because we might remain in the prerolled state for an undetermined amount
430 // of time (i.e., we were not playing before we received a seek), we'll
431 // manually update the current frame and notify the subclass below.
432 if (!frames_queue_ready_.front()->IsEndOfStream()) {
433 current_frame_ = frames_queue_ready_.front();
434 frames_queue_ready_.pop_front();
435 }
436
437 // If we reach prerolled state before Seek() is called by pipeline,
438 // |seek_callback_| is not set, we will return immediately during
439 // when Seek() is eventually called.
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 English.
scherkus (not reviewing) 2011/11/03 04:55:59 this and the comments up in Seek() are crazy bizar
440 if (!seek_cb_.is_null()) {
441 ResetAndRunCB(&seek_cb_, PIPELINE_OK);
442 }
443
444 base::AutoUnlock ul(lock_);
462 OnFrameAvailable(); 445 OnFrameAvailable();
463 } 446 }
464 } 447 }
465 448
466 void VideoRendererBase::ReadInput(scoped_refptr<VideoFrame> frame) { 449 void VideoRendererBase::AttemptRead_Locked() {
467 // We should never return empty frames or EOS frame. 450 lock_.AssertAcquired();
468 DCHECK(frame && !frame->IsEndOfStream()); 451 DCHECK_NE(kEnded, state_);
469 452
470 decoder_->ProduceVideoFrame(frame); 453 if (pending_read_ || frames_queue_ready_.size() == Limits::kMaxVideoFrames) {
471 ++pending_reads_; 454 return;
455 }
456
457 pending_read_ = true;
458 decoder_->Read(frame_ready_cb_);
472 } 459 }
473 460
474 void VideoRendererBase::ScheduleRead_Locked() { 461 void VideoRendererBase::AttemptFlush_Locked() {
475 lock_.AssertAcquired(); 462 lock_.AssertAcquired();
476 DCHECK_NE(kEnded, state_); 463 DCHECK_EQ(kFlushing, state_);
477 // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to 464
478 // provide buffer pools. In the future, we may want to implement real 465 // Get rid of any ready frames.
479 // buffer pool to recycle buffers. 466 while (!frames_queue_ready_.empty()) {
480 while (!frames_queue_done_.empty()) { 467 frames_queue_ready_.pop_front();
481 scoped_refptr<VideoFrame> video_frame = frames_queue_done_.front(); 468 }
482 frames_queue_done_.pop_front(); 469
483 ReadInput(video_frame); 470 if (!pending_paint_ && !pending_read_) {
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 I think this may be where you can get into trouble
scherkus (not reviewing) 2011/11/03 04:55:59 Correct -- fixed + updated unit tests
471 state_ = kFlushed;
472 current_frame_ = NULL;
473 ResetAndRunCB(&flush_callback_);
484 } 474 }
485 } 475 }
486 476
487 void VideoRendererBase::FlushBuffers_Locked() {
488 lock_.AssertAcquired();
489 DCHECK(!pending_paint_);
490
491 // We should never put EOF frame into "done queue".
492 while (!frames_queue_ready_.empty()) {
493 scoped_refptr<VideoFrame> video_frame = frames_queue_ready_.front();
494 if (!video_frame->IsEndOfStream()) {
495 frames_queue_done_.push_back(video_frame);
496 }
497 frames_queue_ready_.pop_front();
498 }
499 if (current_frame_ && !current_frame_->IsEndOfStream()) {
500 frames_queue_done_.push_back(current_frame_);
501 }
502 current_frame_ = NULL;
503
504 // Flush all buffers out to decoder.
505 ScheduleRead_Locked();
506
507 if (pending_reads_ == 0 && state_ == kFlushing)
508 OnFlushDone_Locked();
509 }
510
511 void VideoRendererBase::OnFlushDone_Locked() {
512 lock_.AssertAcquired();
513 // Check all buffers are returned to owners.
514 DCHECK_EQ(frames_queue_done_.size(), 0u);
515 DCHECK(!current_frame_);
516 DCHECK(frames_queue_ready_.empty());
517
518 if (!flush_callback_.is_null()) // This ensures callback is invoked once.
519 ResetAndRunCB(&flush_callback_);
520
521 state_ = kFlushed;
522 }
523
524 base::TimeDelta VideoRendererBase::CalculateSleepDuration( 477 base::TimeDelta VideoRendererBase::CalculateSleepDuration(
525 VideoFrame* next_frame, float playback_rate) { 478 VideoFrame* next_frame, float playback_rate) {
526 // Determine the current and next presentation timestamps. 479 // Determine the current and next presentation timestamps.
527 base::TimeDelta now = host()->GetTime(); 480 base::TimeDelta now = host()->GetTime();
528 base::TimeDelta this_pts = current_frame_->GetTimestamp(); 481 base::TimeDelta this_pts = current_frame_->GetTimestamp();
529 base::TimeDelta next_pts; 482 base::TimeDelta next_pts;
530 if (next_frame) { 483 if (next_frame) {
531 next_pts = next_frame->GetTimestamp(); 484 next_pts = next_frame->GetTimestamp();
532 } else { 485 } else {
533 next_pts = this_pts + current_frame_->GetDuration(); 486 next_pts = this_pts + current_frame_->GetDuration();
534 } 487 }
535 488
536 // Determine our sleep duration based on whether time advanced. 489 // Determine our sleep duration based on whether time advanced.
537 base::TimeDelta sleep; 490 base::TimeDelta sleep;
538 if (now == previous_time_) { 491 if (now == previous_time_) {
539 // Time has not changed, assume we sleep for the frame's duration. 492 // Time has not changed, assume we sleep for the frame's duration.
540 sleep = next_pts - this_pts; 493 sleep = next_pts - this_pts;
541 } else { 494 } else {
542 // Time has changed, figure out real sleep duration. 495 // Time has changed, figure out real sleep duration.
543 sleep = next_pts - now; 496 sleep = next_pts - now;
544 previous_time_ = now; 497 previous_time_ = now;
545 } 498 }
546 499
547 // Scale our sleep based on the playback rate. 500 // Scale our sleep based on the playback rate.
548 // TODO(scherkus): floating point badness and degrade gracefully. 501 // TODO(scherkus): floating point badness and degrade gracefully.
549 return base::TimeDelta::FromMicroseconds( 502 return base::TimeDelta::FromMicroseconds(
550 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); 503 static_cast<int64>(sleep.InMicroseconds() / playback_rate));
551 } 504 }
552 505
553 void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) { 506 void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) {
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 assuming you don't reinstate the call in FrameRead
scherkus (not reviewing) 2011/11/03 04:55:59 Done.
554 lock_.AssertAcquired(); 507 lock_.AssertAcquired();
555 508
556 base::Closure callback; 509 base::Closure callback;
557 State old_state = state_; 510 State old_state = state_;
558 state_ = kError; 511 state_ = kError;
559 512
560 // Flush frames if we aren't in the middle of a paint. If we 513 // Flush frames if we aren't in the middle of a paint. If we
561 // are painting then flushing will happen when the paint completes. 514 // are painting then flushing will happen when the paint completes.
562 if (!pending_paint_ && !pending_paint_with_last_available_) 515 if (!pending_paint_ && !pending_paint_with_last_available_)
563 DoStopOrErrorFlush_Locked(); 516 DoStopOrError_Locked();
564 517
565 switch (old_state) { 518 switch (old_state) {
566 case kUninitialized: 519 case kUninitialized:
567 case kPrerolled: 520 case kPrerolled:
568 case kPaused: 521 case kPaused:
569 case kFlushed: 522 case kFlushed:
570 case kEnded: 523 case kEnded:
571 case kPlaying: 524 case kPlaying:
572 break; 525 break;
573 526
(...skipping 15 matching lines...) Expand all
589 case kError: 542 case kError:
590 return; 543 return;
591 } 544 }
592 545
593 host()->SetError(status); 546 host()->SetError(status);
594 547
595 if (!callback.is_null()) 548 if (!callback.is_null())
596 callback.Run(); 549 callback.Run();
597 } 550 }
598 551
599 void VideoRendererBase::DoStopOrErrorFlush_Locked() { 552 void VideoRendererBase::DoStopOrError_Locked() {
600 DCHECK(!pending_paint_); 553 DCHECK(!pending_paint_);
601 DCHECK(!pending_paint_with_last_available_); 554 DCHECK(!pending_paint_with_last_available_);
602 lock_.AssertAcquired(); 555 lock_.AssertAcquired();
603 FlushBuffers_Locked();
604 last_available_frame_ = NULL; 556 last_available_frame_ = NULL;
605 DCHECK_EQ(pending_reads_, 0); 557 DCHECK(!pending_read_);
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Looking at the code this doesn't seem like a safe
scherkus (not reviewing) 2011/11/03 04:55:59 I really don't know what this method does but the
606 } 558 }
607 559
608 } // namespace media 560 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698