OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |