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

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

Issue 3030013: preparation for recycling buffer, patch 2 (Closed)
Patch Set: fix layout test Created 10 years, 4 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/filters/video_renderer_base.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/callback.h" 5 #include "base/callback.h"
6 #include "media/base/buffers.h" 6 #include "media/base/buffers.h"
7 #include "media/base/callback.h"
7 #include "media/base/filter_host.h" 8 #include "media/base/filter_host.h"
8 #include "media/base/video_frame.h" 9 #include "media/base/video_frame.h"
9 #include "media/filters/video_renderer_base.h" 10 #include "media/filters/video_renderer_base.h"
10 11
11 namespace media { 12 namespace media {
12 13
13 // Limit our read ahead to at least 3 frames. One frame is typically in flux at 14 // Limit our read ahead to at least 3 frames. One frame is typically in flux at
14 // all times, as in frame n is discarded at the top of ThreadMain() while frame 15 // all times, as in frame n is discarded at the top of ThreadMain() while frame
15 // (n + kMaxFrames) is being asynchronously fetched. The remaining two frames 16 // (n + kMaxFrames) is being asynchronously fetched. The remaining two frames
16 // allow us to advance the current frame as well as read the timestamp of the 17 // allow us to advance the current frame as well as read the timestamp of the
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 return false; 84 return false;
84 if (!media_format.GetAsInteger(MediaFormat::kHeight, &height)) 85 if (!media_format.GetAsInteger(MediaFormat::kHeight, &height))
85 return false; 86 return false;
86 if (width_out) *width_out = width; 87 if (width_out) *width_out = width;
87 if (height_out) *height_out = height; 88 if (height_out) *height_out = height;
88 return true; 89 return true;
89 } 90 }
90 91
91 void VideoRendererBase::Play(FilterCallback* callback) { 92 void VideoRendererBase::Play(FilterCallback* callback) {
92 AutoLock auto_lock(lock_); 93 AutoLock auto_lock(lock_);
93 DCHECK_EQ(kPaused, state_); 94 DCHECK(kPaused == state_ || kFlushing == state_);
94 scoped_ptr<FilterCallback> c(callback); 95 scoped_ptr<FilterCallback> c(callback);
95 state_ = kPlaying; 96 state_ = kPlaying;
96 callback->Run(); 97 callback->Run();
97 } 98 }
98 99
99 void VideoRendererBase::Pause(FilterCallback* callback) { 100 void VideoRendererBase::Pause(FilterCallback* callback) {
100 AutoLock auto_lock(lock_); 101 AutoLock auto_lock(lock_);
101 DCHECK(state_ == kPlaying || state_ == kEnded); 102 DCHECK(state_ == kPlaying || state_ == kEnded);
102 pause_callback_.reset(callback); 103 AutoCallbackRunner done_runner(callback);
103 state_ = kPaused; 104 state_ = kPaused;
105 }
104 106
105 // TODO(jiesun): currently we use Pause() to fulfill Flush(). 107 void VideoRendererBase::Flush(FilterCallback* callback) {
108 DCHECK(state_ == kPaused);
109
110 AutoLock auto_lock(lock_);
111 flush_callback_.reset(callback);
112 state_ = kFlushing;
113
106 // Filter is considered paused when we've finished all pending reads, which 114 // Filter is considered paused when we've finished all pending reads, which
107 // implies all buffers are returned to owner in Decoder/Renderer. Renderer 115 // implies all buffers are returned to owner in Decoder/Renderer. Renderer
108 // is considered paused with one more contingency that |pending_paint_| is 116 // is considered paused with one more contingency that |pending_paint_| is
109 // false, such that no client of us is holding any reference to VideoFrame. 117 // false, such that no client of us is holding any reference to VideoFrame.
110 if (pending_reads_ == 0 && pending_paint_ == false) { 118 if (pending_reads_ == 0 && pending_paint_ == false) {
111 pause_callback_->Run(); 119 flush_callback_->Run();
112 pause_callback_.reset(); 120 flush_callback_.reset();
113 FlushBuffers(); 121 FlushBuffers();
114 } 122 }
115 } 123 }
116 124
117 void VideoRendererBase::Stop(FilterCallback* callback) { 125 void VideoRendererBase::Stop(FilterCallback* callback) {
118 { 126 {
119 AutoLock auto_lock(lock_); 127 AutoLock auto_lock(lock_);
120 state_ = kStopped; 128 state_ = kStopped;
121 129
122 // TODO(jiesun): move this to flush. 130 // TODO(jiesun): move this to flush.
(...skipping 17 matching lines...) Expand all
140 OnStop(callback); 148 OnStop(callback);
141 } 149 }
142 150
143 void VideoRendererBase::SetPlaybackRate(float playback_rate) { 151 void VideoRendererBase::SetPlaybackRate(float playback_rate) {
144 AutoLock auto_lock(lock_); 152 AutoLock auto_lock(lock_);
145 playback_rate_ = playback_rate; 153 playback_rate_ = playback_rate;
146 } 154 }
147 155
148 void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { 156 void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) {
149 AutoLock auto_lock(lock_); 157 AutoLock auto_lock(lock_);
150 DCHECK_EQ(kPaused, state_); 158 DCHECK(kPaused == state_ || kFlushing == state_);
151 DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed"; 159 DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
152 state_ = kSeeking; 160 state_ = kSeeking;
153 seek_callback_.reset(callback); 161 seek_callback_.reset(callback);
154 seek_timestamp_ = time; 162 seek_timestamp_ = time;
155 163
156 // Throw away everything and schedule our reads. 164 // Throw away everything and schedule our reads.
157 // TODO(jiesun): this should be guaranteed by pause/flush before seek happen. 165 // TODO(jiesun): this should be guaranteed by pause/flush before seek happen.
158 frames_queue_ready_.clear(); 166 frames_queue_ready_.clear();
159 frames_queue_done_.clear(); 167 frames_queue_done_.clear();
160 for (size_t i = 0; i < kMaxFrames; ++i) { 168 for (size_t i = 0; i < kMaxFrames; ++i) {
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 243
236 for (;;) { 244 for (;;) {
237 AutoLock auto_lock(lock_); 245 AutoLock auto_lock(lock_);
238 246
239 const base::TimeDelta kIdleTimeDelta = 247 const base::TimeDelta kIdleTimeDelta =
240 base::TimeDelta::FromMilliseconds(kIdleMilliseconds); 248 base::TimeDelta::FromMilliseconds(kIdleMilliseconds);
241 249
242 if (state_ == kStopped) 250 if (state_ == kStopped)
243 return; 251 return;
244 252
245 if (state_ == kPaused || state_ == kSeeking || state_ == kEnded || 253 if (state_ != kPlaying || playback_rate_ == 0) {
246 playback_rate_ == 0) {
247 remaining_time = kIdleTimeDelta; 254 remaining_time = kIdleTimeDelta;
248 } else if (frames_queue_ready_.empty() || 255 } else if (frames_queue_ready_.empty() ||
249 frames_queue_ready_.front()->IsEndOfStream()) { 256 frames_queue_ready_.front()->IsEndOfStream()) {
250 if (current_frame_.get()) 257 if (current_frame_.get())
251 remaining_time = CalculateSleepDuration(NULL, playback_rate_); 258 remaining_time = CalculateSleepDuration(NULL, playback_rate_);
252 else 259 else
253 remaining_time = kIdleTimeDelta; 260 remaining_time = kIdleTimeDelta;
254 } else { 261 } else {
255 // Calculate how long until we should advance the frame, which is 262 // Calculate how long until we should advance the frame, which is
256 // typically negative but for playback rates < 1.0f may be long enough 263 // typically negative but for playback rates < 1.0f may be long enough
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 DCHECK(!pending_paint_); 350 DCHECK(!pending_paint_);
344 351
345 if (state_ == kStopped || !current_frame_.get() || 352 if (state_ == kStopped || !current_frame_.get() ||
346 current_frame_->IsEndOfStream()) { 353 current_frame_->IsEndOfStream()) {
347 *frame_out = NULL; 354 *frame_out = NULL;
348 return; 355 return;
349 } 356 }
350 357
351 // We should have initialized and have the current frame. 358 // We should have initialized and have the current frame.
352 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || 359 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying ||
353 state_ == kEnded); 360 state_ == kFlushing || state_ == kEnded);
354 *frame_out = current_frame_; 361 *frame_out = current_frame_;
355 pending_paint_ = true; 362 pending_paint_ = true;
356 } 363 }
357 364
358 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) { 365 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) {
359 AutoLock auto_lock(lock_); 366 AutoLock auto_lock(lock_);
360 367
361 // Note that we do not claim |pending_paint_| when we return NULL frame, in 368 // Note that we do not claim |pending_paint_| when we return NULL frame, in
362 // that case, |current_frame_| could be changed before PutCurrentFrame. 369 // that case, |current_frame_| could be changed before PutCurrentFrame.
363 DCHECK(pending_paint_ || frame.get() == NULL); 370 DCHECK(pending_paint_ || frame.get() == NULL);
364 DCHECK(current_frame_.get() == frame.get() || frame.get() == NULL); 371 DCHECK(current_frame_.get() == frame.get() || frame.get() == NULL);
365 372
366 pending_paint_ = false; 373 pending_paint_ = false;
367 // We had cleared the |pending_paint_| flag, there are chances that current 374 // We had cleared the |pending_paint_| flag, there are chances that current
368 // frame is timed-out. We will wake up our main thread to advance the current 375 // frame is timed-out. We will wake up our main thread to advance the current
369 // frame when this is true. 376 // frame when this is true.
370 frame_available_.Signal(); 377 frame_available_.Signal();
371 if (state_ == kPaused && pending_reads_ == 0 && pause_callback_.get()) { 378 if (state_ == kFlushing && pending_reads_ == 0 && flush_callback_.get()) {
372 // No more pending reads! We're now officially "paused". 379 // No more pending reads! We're now officially "paused".
373 FlushBuffers(); 380 FlushBuffers();
374 pause_callback_->Run(); 381 flush_callback_->Run();
375 pause_callback_.reset(); 382 flush_callback_.reset();
376 } 383 }
377 } 384 }
378 385
379 void VideoRendererBase::OnFillBufferDone(scoped_refptr<VideoFrame> frame) { 386 void VideoRendererBase::OnFillBufferDone(scoped_refptr<VideoFrame> frame) {
380 AutoLock auto_lock(lock_); 387 AutoLock auto_lock(lock_);
381 388
382 // TODO(ajwong): Work around cause we don't synchronize on stop. Correct 389 // TODO(ajwong): Work around cause we don't synchronize on stop. Correct
383 // fix is to resolve http://crbug.com/16059. 390 // fix is to resolve http://crbug.com/16059.
384 if (state_ == kStopped) { 391 if (state_ == kStopped) {
385 // TODO(jiesun): Remove this when flush before stop landed! 392 // TODO(jiesun): Remove this when flush before stop landed!
386 return; 393 return;
387 } 394 }
388 395
389 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || 396 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying ||
390 state_ == kEnded); 397 state_ == kFlushing || state_ == kEnded);
391 DCHECK_GT(pending_reads_, 0u); 398 DCHECK_GT(pending_reads_, 0u);
392 --pending_reads_; 399 --pending_reads_;
393 400
394 // Discard frames until we reach our desired seek timestamp. 401 // Discard frames until we reach our desired seek timestamp.
395 if (state_ == kSeeking && !frame->IsEndOfStream() && 402 if (state_ == kSeeking && !frame->IsEndOfStream() &&
396 (frame->GetTimestamp() + frame->GetDuration()) < seek_timestamp_) { 403 (frame->GetTimestamp() + frame->GetDuration()) < seek_timestamp_) {
397 frames_queue_done_.push_back(frame); 404 frames_queue_done_.push_back(frame);
398 ScheduleRead_Locked(); 405 ScheduleRead_Locked();
399 } else { 406 } else {
400 frames_queue_ready_.push_back(frame); 407 frames_queue_ready_.push_back(frame);
401 DCHECK_LE(frames_queue_ready_.size(), kMaxFrames); 408 DCHECK_LE(frames_queue_ready_.size(), kMaxFrames);
402 frame_available_.Signal(); 409 frame_available_.Signal();
403 } 410 }
404 411
405 // Check for our preroll complete condition. 412 // Check for our preroll complete condition.
406 if (state_ == kSeeking) { 413 if (state_ == kSeeking) {
407 DCHECK(seek_callback_.get()); 414 DCHECK(seek_callback_.get());
408 if (frames_queue_ready_.size() == kMaxFrames) { 415 if (frames_queue_ready_.size() == kMaxFrames || frame->IsEndOfStream()) {
409 // We're paused, so make sure we update |current_frame_| to represent 416 // We're paused, so make sure we update |current_frame_| to represent
410 // our new location. 417 // our new location.
411 state_ = kPaused; 418 state_ = kPaused;
412 419
413 // Because we might remain paused (i.e., we were not playing before we 420 // Because we might remain paused (i.e., we were not playing before we
414 // received a seek), we can't rely on ThreadMain() to notify the subclass 421 // received a seek), we can't rely on ThreadMain() to notify the subclass
415 // the frame has been updated. 422 // the frame has been updated.
416 current_frame_ = frames_queue_ready_.front(); 423 scoped_refptr<VideoFrame> first_frame;
417 frames_queue_ready_.pop_front(); 424 first_frame = frames_queue_ready_.front();
425 if (!first_frame->IsEndOfStream()) {
426 frames_queue_ready_.pop_front();
427 current_frame_ = first_frame;
428 }
418 OnFrameAvailable(); 429 OnFrameAvailable();
419 430
420 seek_callback_->Run(); 431 seek_callback_->Run();
421 seek_callback_.reset(); 432 seek_callback_.reset();
422 } 433 }
423 } else if (state_ == kPaused && pending_reads_ == 0 && !pending_paint_) { 434 } else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) {
424 // No more pending reads! We're now officially "paused". 435 // No more pending reads! We're now officially "paused".
425 if (pause_callback_.get()) { 436 if (flush_callback_.get()) {
426 pause_callback_->Run(); 437 flush_callback_->Run();
427 pause_callback_.reset(); 438 flush_callback_.reset();
428 } 439 }
429 } 440 }
430 } 441 }
431 442
432 void VideoRendererBase::ScheduleRead_Locked() { 443 void VideoRendererBase::ScheduleRead_Locked() {
433 lock_.AssertAcquired(); 444 lock_.AssertAcquired();
434 DCHECK_NE(kEnded, state_); 445 DCHECK_NE(kEnded, state_);
435 // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to 446 // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to
436 // provide buffer pools. In the future, we may want to implement real 447 // provide buffer pools. In the future, we may want to implement real
437 // buffer pool to recycle buffers. 448 // buffer pool to recycle buffers.
438 while (!frames_queue_done_.empty()) { 449 while (!frames_queue_done_.empty()) {
439 scoped_refptr<VideoFrame> video_frame = frames_queue_done_.front(); 450 scoped_refptr<VideoFrame> video_frame = frames_queue_done_.front();
440 frames_queue_done_.pop_front(); 451 frames_queue_done_.pop_front();
441 decoder_->FillThisBuffer(video_frame); 452 decoder_->FillThisBuffer(video_frame);
442 DCHECK_LT(pending_reads_, kMaxFrames); 453 DCHECK_LT(pending_reads_, kMaxFrames);
443 ++pending_reads_; 454 ++pending_reads_;
444 } 455 }
445 } 456 }
446 457
447 void VideoRendererBase::FlushBuffers() { 458 void VideoRendererBase::FlushBuffers() {
448 DCHECK(!pending_paint_); 459 DCHECK(!pending_paint_);
449 460
450 // We should never put EOF frame into "done queue". 461 // We should never put EOF frame into "done queue".
451 while (!frames_queue_ready_.empty()) { 462 while (!frames_queue_ready_.empty()) {
452 scoped_refptr<VideoFrame> video_frame = frames_queue_ready_.front(); 463 scoped_refptr<VideoFrame> video_frame = frames_queue_ready_.front();
453 if (video_frame->IsEndOfStream()) { 464 if (!video_frame->IsEndOfStream()) {
454 frames_queue_done_.push_back(video_frame); 465 frames_queue_done_.push_back(video_frame);
455 } 466 }
456 frames_queue_ready_.pop_front(); 467 frames_queue_ready_.pop_front();
457 } 468 }
458 if (current_frame_.get() && !current_frame_->IsEndOfStream()) { 469 if (current_frame_.get() && !current_frame_->IsEndOfStream()) {
459 frames_queue_done_.push_back(current_frame_); 470 frames_queue_done_.push_back(current_frame_);
460 } 471 }
461 current_frame_ = NULL; 472 current_frame_ = NULL;
462 } 473 }
463 474
(...skipping 20 matching lines...) Expand all
484 previous_time_ = now; 495 previous_time_ = now;
485 } 496 }
486 497
487 // Scale our sleep based on the playback rate. 498 // Scale our sleep based on the playback rate.
488 // TODO(scherkus): floating point badness and degrade gracefully. 499 // TODO(scherkus): floating point badness and degrade gracefully.
489 return base::TimeDelta::FromMicroseconds( 500 return base::TimeDelta::FromMicroseconds(
490 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); 501 static_cast<int64>(sleep.InMicroseconds() / playback_rate));
491 } 502 }
492 503
493 } // namespace media 504 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/video_renderer_base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698