Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/filters/video_renderer_base.h" | 5 #include "media/filters/video_renderer_base.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/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/threading/platform_thread.h" | 11 #include "base/threading/platform_thread.h" |
| 12 #include "media/base/buffers.h" | 12 #include "media/base/buffers.h" |
| 13 #include "media/base/limits.h" | 13 #include "media/base/limits.h" |
| 14 #include "media/base/pipeline.h" | 14 #include "media/base/pipeline.h" |
| 15 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
| 16 #include "media/filters/decrypting_demuxer_stream.h" | 16 #include "media/filters/decrypting_demuxer_stream.h" |
| 17 #include "media/filters/video_decoder_selector.h" | 17 #include "media/filters/video_decoder_selector.h" |
| 18 | 18 |
| 19 namespace media { | 19 namespace media { |
| 20 | 20 |
| 21 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() { | 21 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() { |
| 22 return base::TimeDelta::FromMilliseconds(250); | 22 return base::TimeDelta::FromMilliseconds(250); |
| 23 } | 23 } |
| 24 | 24 |
| 25 VideoRendererBase::VideoRendererBase( | 25 VideoRendererBase::VideoRendererBase( |
| 26 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 26 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
| 27 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 27 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
| 28 const base::Closure& paint_cb, | 28 const PaintCB& paint_cb, |
| 29 const SetOpaqueCB& set_opaque_cb, | 29 const SetOpaqueCB& set_opaque_cb, |
| 30 bool drop_frames) | 30 bool drop_frames) |
| 31 : message_loop_(message_loop), | 31 : message_loop_(message_loop), |
| 32 set_decryptor_ready_cb_(set_decryptor_ready_cb), | 32 set_decryptor_ready_cb_(set_decryptor_ready_cb), |
| 33 frame_available_(&lock_), | 33 frame_available_(&lock_), |
| 34 state_(kUninitialized), | 34 state_(kUninitialized), |
| 35 thread_(base::kNullThreadHandle), | 35 thread_(base::kNullThreadHandle), |
| 36 pending_read_(false), | 36 pending_read_(false), |
| 37 pending_paint_(false), | |
| 38 pending_paint_with_last_available_(false), | |
| 39 drop_frames_(drop_frames), | 37 drop_frames_(drop_frames), |
| 40 playback_rate_(0), | 38 playback_rate_(0), |
| 41 paint_cb_(paint_cb), | 39 paint_cb_(paint_cb), |
| 42 set_opaque_cb_(set_opaque_cb) { | 40 set_opaque_cb_(set_opaque_cb), |
| 41 last_timestamp_(kNoTimestamp()) { | |
| 43 DCHECK(!paint_cb_.is_null()); | 42 DCHECK(!paint_cb_.is_null()); |
| 44 } | 43 } |
| 45 | 44 |
| 46 void VideoRendererBase::Play(const base::Closure& callback) { | 45 void VideoRendererBase::Play(const base::Closure& callback) { |
| 47 DCHECK(message_loop_->BelongsToCurrentThread()); | 46 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 48 base::AutoLock auto_lock(lock_); | 47 base::AutoLock auto_lock(lock_); |
| 49 DCHECK_EQ(kPrerolled, state_); | 48 DCHECK_EQ(kPrerolled, state_); |
| 50 state_ = kPlaying; | 49 state_ = kPlaying; |
| 51 callback.Run(); | 50 callback.Run(); |
| 52 } | 51 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 76 } | 75 } |
| 77 | 76 |
| 78 void VideoRendererBase::ResetDecoder() { | 77 void VideoRendererBase::ResetDecoder() { |
| 79 DCHECK(message_loop_->BelongsToCurrentThread()); | 78 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 80 base::AutoLock auto_lock(lock_); | 79 base::AutoLock auto_lock(lock_); |
| 81 decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderResetDone, this)); | 80 decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderResetDone, this)); |
| 82 } | 81 } |
| 83 | 82 |
| 84 void VideoRendererBase::Stop(const base::Closure& callback) { | 83 void VideoRendererBase::Stop(const base::Closure& callback) { |
| 85 DCHECK(message_loop_->BelongsToCurrentThread()); | 84 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 86 if (state_ == kUninitialized || state_ == kStopped) { | 85 if (state_ == kUninitialized || state_ == kStopped) { |
|
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
I'm pretty sure these checks should be done under
scherkus (not reviewing)
2013/02/01 22:45:25
Done.
| |
| 87 callback.Run(); | 86 callback.Run(); |
|
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
message_loop_->PostTask(FROM_HERE, callback) ?
scherkus (not reviewing)
2013/02/01 22:45:25
I'm going to hold off on cleaning up VRB threading
| |
| 88 return; | 87 return; |
| 89 } | 88 } |
| 90 | 89 |
| 91 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; | 90 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; |
| 92 { | 91 { |
| 93 base::AutoLock auto_lock(lock_); | 92 base::AutoLock auto_lock(lock_); |
| 94 state_ = kStopped; | 93 state_ = kStopped; |
| 95 | 94 |
| 96 statistics_cb_.Reset(); | 95 statistics_cb_.Reset(); |
| 97 max_time_cb_.Reset(); | 96 max_time_cb_.Reset(); |
| 98 if (!pending_paint_ && !pending_paint_with_last_available_) | 97 DoStopOrError_Locked(); |
| 99 DoStopOrError_Locked(); | |
| 100 | 98 |
| 101 // Clean up our thread if present. | 99 // Clean up our thread if present. |
| 102 if (thread_ != base::kNullThreadHandle) { | 100 if (thread_ != base::kNullThreadHandle) { |
| 103 // Signal the thread since it's possible to get stopped with the video | 101 // Signal the thread since it's possible to get stopped with the video |
| 104 // thread waiting for a read to complete. | 102 // thread waiting for a read to complete. |
| 105 frame_available_.Signal(); | 103 frame_available_.Signal(); |
| 106 thread_to_join = thread_; | 104 thread_to_join = thread_; |
| 107 thread_ = base::kNullThreadHandle; | 105 thread_ = base::kNullThreadHandle; |
|
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
nit: std::swap(thread_to_join, thread_)
scherkus (not reviewing)
2013/02/01 22:45:25
Done.
| |
| 108 } | 106 } |
| 109 } | 107 } |
| 110 if (thread_to_join != base::kNullThreadHandle) | 108 if (thread_to_join != base::kNullThreadHandle) |
| 111 base::PlatformThread::Join(thread_to_join); | 109 base::PlatformThread::Join(thread_to_join); |
| 112 | 110 |
| 113 if (decrypting_demuxer_stream_) { | 111 if (decrypting_demuxer_stream_) { |
| 114 decrypting_demuxer_stream_->Reset(base::Bind( | 112 decrypting_demuxer_stream_->Reset(base::Bind( |
| 115 &VideoRendererBase::StopDecoder, this, callback)); | 113 &VideoRendererBase::StopDecoder, this, callback)); |
| 116 return; | 114 return; |
| 117 } | 115 } |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 frame_available_.TimedWait(kIdleTimeDelta); | 272 frame_available_.TimedWait(kIdleTimeDelta); |
| 275 continue; | 273 continue; |
| 276 } | 274 } |
| 277 | 275 |
| 278 // Remain idle until we have the next frame ready for rendering. | 276 // Remain idle until we have the next frame ready for rendering. |
| 279 if (ready_frames_.empty()) { | 277 if (ready_frames_.empty()) { |
| 280 frame_available_.TimedWait(kIdleTimeDelta); | 278 frame_available_.TimedWait(kIdleTimeDelta); |
| 281 continue; | 279 continue; |
| 282 } | 280 } |
| 283 | 281 |
| 284 // Remain idle until we've initialized |current_frame_| via prerolling. | 282 // This can happen if our preroll only contains end of stream frames. |
| 285 if (!current_frame_) { | 283 if (ready_frames_.front()->IsEndOfStream()) { |
| 286 // This can happen if our preroll only contains end of stream frames. | 284 state_ = kEnded; |
| 287 if (ready_frames_.front()->IsEndOfStream()) { | 285 ended_cb_.Run(); |
| 288 state_ = kEnded; | 286 ready_frames_.clear(); |
| 289 ended_cb_.Run(); | |
| 290 ready_frames_.clear(); | |
| 291 | 287 |
| 292 // No need to sleep here as we idle when |state_ != kPlaying|. | 288 // No need to sleep here as we idle when |state_ != kPlaying|. |
| 293 continue; | |
| 294 } | |
| 295 | |
| 296 frame_available_.TimedWait(kIdleTimeDelta); | |
| 297 continue; | 289 continue; |
| 298 } | 290 } |
| 299 | 291 |
| 300 // Calculate how long until we should advance the frame, which is | 292 // Calculate how long until we should advance the frame, which is |
| 301 // typically negative but for playback rates < 1.0f may be long enough | 293 // typically negative but for playback rates < 1.0f may be long enough |
| 302 // that it makes more sense to idle and check again. | 294 // that it makes more sense to idle and check again. |
| 303 base::TimeDelta remaining_time = | 295 base::TimeDelta remaining_time = |
| 304 CalculateSleepDuration(ready_frames_.front(), playback_rate_); | 296 CalculateSleepDuration(ready_frames_.front(), playback_rate_); |
| 305 | 297 |
| 306 // Sleep up to a maximum of our idle time until we're within the time to | 298 // Sleep up to a maximum of our idle time until we're within the time to |
| 307 // render the next frame. | 299 // render the next frame. |
| 308 if (remaining_time.InMicroseconds() > 0) { | 300 if (remaining_time.InMicroseconds() > 0) { |
| 309 remaining_time = std::min(remaining_time, kIdleTimeDelta); | 301 remaining_time = std::min(remaining_time, kIdleTimeDelta); |
| 310 frame_available_.TimedWait(remaining_time); | 302 frame_available_.TimedWait(remaining_time); |
| 311 continue; | 303 continue; |
| 312 } | 304 } |
| 313 | 305 |
| 314 | |
| 315 // We're almost there! | |
| 316 // | |
| 317 // At this point we've rendered |current_frame_| for the proper amount | |
| 318 // of time and also have the next frame that ready for rendering. | |
| 319 | |
| 320 | |
| 321 // If the next frame is end of stream then we are truly at the end of the | |
| 322 // video stream. | |
| 323 // | |
| 324 // TODO(scherkus): deduplicate this end of stream check after we get rid of | |
| 325 // |current_frame_|. | |
| 326 if (ready_frames_.front()->IsEndOfStream()) { | |
| 327 state_ = kEnded; | |
| 328 ended_cb_.Run(); | |
| 329 ready_frames_.clear(); | |
| 330 | |
| 331 // No need to sleep here as we idle when |state_ != kPlaying|. | |
| 332 continue; | |
| 333 } | |
| 334 | |
| 335 // We cannot update |current_frame_| until we've completed the pending | |
| 336 // paint. Furthermore, the pending paint might be really slow: check to | |
| 337 // see if we have any ready frames that we can drop if they've already | |
| 338 // expired. | |
| 339 if (pending_paint_) { | |
| 340 while (!ready_frames_.empty()) { | |
| 341 // Can't drop anything if we're at the end. | |
| 342 if (ready_frames_.front()->IsEndOfStream()) | |
| 343 break; | |
| 344 | |
| 345 base::TimeDelta remaining_time = | |
| 346 ready_frames_.front()->GetTimestamp() - get_time_cb_.Run(); | |
| 347 | |
| 348 // Still a chance we can render the frame! | |
| 349 if (remaining_time.InMicroseconds() > 0) | |
| 350 break; | |
| 351 | |
| 352 if (!drop_frames_) | |
| 353 break; | |
| 354 | |
| 355 // Frame dropped: read again. | |
| 356 ++frames_dropped; | |
| 357 ready_frames_.pop_front(); | |
| 358 message_loop_->PostTask(FROM_HERE, base::Bind( | |
| 359 &VideoRendererBase::AttemptRead, this)); | |
| 360 } | |
| 361 // Continue waiting for the current paint to finish. | |
| 362 frame_available_.TimedWait(kIdleTimeDelta); | |
| 363 continue; | |
| 364 } | |
| 365 | |
| 366 | |
| 367 // Congratulations! You've made it past the video frame timing gauntlet. | 306 // Congratulations! You've made it past the video frame timing gauntlet. |
| 368 // | 307 // |
| 369 // We can now safely update the current frame, request another frame, and | 308 // At this point enough time has passed that the next frame that ready for |
| 370 // signal to the client that a new frame is available. | 309 // rendering. |
| 371 DCHECK(!pending_paint_); | 310 PaintWithNextReadyFrame(); |
| 372 DCHECK(!ready_frames_.empty()); | |
| 373 SetCurrentFrameToNextReadyFrame(); | |
| 374 message_loop_->PostTask(FROM_HERE, base::Bind( | 311 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 375 &VideoRendererBase::AttemptRead, this)); | 312 &VideoRendererBase::AttemptRead, this)); |
| 376 | |
| 377 base::AutoUnlock auto_unlock(lock_); | |
| 378 paint_cb_.Run(); | |
| 379 } | 313 } |
| 380 } | 314 } |
| 381 | 315 |
| 382 void VideoRendererBase::SetCurrentFrameToNextReadyFrame() { | 316 void VideoRendererBase::PaintWithNextReadyFrame() { |
|
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
nit: Add _Locked() & corresponding assert since th
scherkus (not reviewing)
2013/02/01 22:45:25
Done.
| |
| 383 current_frame_ = ready_frames_.front(); | 317 scoped_refptr<VideoFrame> next_frame = ready_frames_.front(); |
| 384 ready_frames_.pop_front(); | 318 ready_frames_.pop_front(); |
| 385 | 319 |
| 386 // Notify the pipeline of natural_size() changes. | 320 // Notify the pipeline of natural_size() changes. |
| 387 const gfx::Size& natural_size = current_frame_->natural_size(); | 321 const gfx::Size& natural_size = next_frame->natural_size(); |
| 388 if (natural_size != last_natural_size_) { | 322 if (natural_size != last_natural_size_) { |
| 389 size_changed_cb_.Run(natural_size); | 323 size_changed_cb_.Run(natural_size); |
| 390 last_natural_size_ = natural_size; | 324 last_natural_size_ = natural_size; |
| 391 } | 325 } |
| 392 } | |
| 393 | 326 |
| 394 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { | 327 paint_cb_.Run(next_frame); |
|
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
This calls the callback under lock now. Are you su
scherkus (not reviewing)
2013/02/01 22:45:25
Yes. Previously it was terrifying because the most
| |
| 395 base::AutoLock auto_lock(lock_); | |
| 396 DCHECK(!pending_paint_ && !pending_paint_with_last_available_); | |
| 397 | |
| 398 if ((!current_frame_ || current_frame_->IsEndOfStream()) && | |
| 399 (!last_available_frame_ || last_available_frame_->IsEndOfStream())) { | |
| 400 *frame_out = NULL; | |
| 401 return; | |
| 402 } | |
| 403 | |
| 404 // We should have initialized and have the current frame. | |
| 405 DCHECK_NE(state_, kUninitialized); | |
| 406 DCHECK_NE(state_, kStopped); | |
| 407 DCHECK_NE(state_, kError); | |
| 408 | |
| 409 if (current_frame_) { | |
| 410 *frame_out = current_frame_; | |
| 411 last_available_frame_ = current_frame_; | |
| 412 pending_paint_ = true; | |
| 413 } else { | |
| 414 DCHECK(last_available_frame_); | |
| 415 *frame_out = last_available_frame_; | |
| 416 pending_paint_with_last_available_ = true; | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) { | |
| 421 base::AutoLock auto_lock(lock_); | |
| 422 | |
| 423 // Note that we do not claim |pending_paint_| when we return NULL frame, in | |
| 424 // that case, |current_frame_| could be changed before PutCurrentFrame. | |
| 425 if (pending_paint_) { | |
| 426 DCHECK_EQ(current_frame_, frame); | |
| 427 DCHECK(!pending_paint_with_last_available_); | |
| 428 pending_paint_ = false; | |
| 429 } else if (pending_paint_with_last_available_) { | |
| 430 DCHECK_EQ(last_available_frame_, frame); | |
| 431 DCHECK(!pending_paint_); | |
| 432 pending_paint_with_last_available_ = false; | |
| 433 } else { | |
| 434 DCHECK(!frame); | |
| 435 } | |
| 436 | |
| 437 // We had cleared the |pending_paint_| flag, there are chances that current | |
| 438 // frame is timed-out. We will wake up our main thread to advance the current | |
| 439 // frame when this is true. | |
| 440 frame_available_.Signal(); | |
| 441 if (state_ == kFlushingDecoder) | |
| 442 return; | |
| 443 | |
| 444 if (state_ == kFlushing) { | |
| 445 AttemptFlush_Locked(); | |
| 446 return; | |
| 447 } | |
| 448 | |
| 449 if (state_ == kError || state_ == kStopped) { | |
| 450 DoStopOrError_Locked(); | |
| 451 } | |
| 452 } | 328 } |
| 453 | 329 |
| 454 VideoRendererBase::~VideoRendererBase() { | 330 VideoRendererBase::~VideoRendererBase() { |
| 455 base::AutoLock auto_lock(lock_); | 331 base::AutoLock auto_lock(lock_); |
| 456 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; | 332 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; |
| 457 } | 333 } |
| 458 | 334 |
| 459 void VideoRendererBase::FrameReady(VideoDecoder::Status status, | 335 void VideoRendererBase::FrameReady(VideoDecoder::Status status, |
| 460 const scoped_refptr<VideoFrame>& frame) { | 336 const scoped_refptr<VideoFrame>& frame) { |
| 461 base::AutoLock auto_lock(lock_); | 337 base::AutoLock auto_lock(lock_); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 525 // purposes: | 401 // purposes: |
| 526 // 1) Prerolling while paused | 402 // 1) Prerolling while paused |
| 527 // 2) Keeps decoding going if video rendering thread starts falling behind | 403 // 2) Keeps decoding going if video rendering thread starts falling behind |
| 528 if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) { | 404 if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) { |
| 529 AttemptRead_Locked(); | 405 AttemptRead_Locked(); |
| 530 return; | 406 return; |
| 531 } | 407 } |
| 532 | 408 |
| 533 // If we're at capacity or end of stream while prerolling we need to | 409 // If we're at capacity or end of stream while prerolling we need to |
| 534 // transition to prerolled. | 410 // transition to prerolled. |
| 535 if (state_ == kPrerolling) { | 411 if (state_ == kPrerolling) { |
|
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
nit: reverse check and unindent?
scherkus (not reviewing)
2013/02/01 22:45:25
Done.
| |
| 536 DCHECK(!current_frame_); | |
| 537 state_ = kPrerolled; | 412 state_ = kPrerolled; |
| 538 | 413 |
| 539 // Because we might remain in the prerolled state for an undetermined amount | 414 // Because we might remain in the prerolled state for an undetermined amount |
| 540 // of time (i.e., we were not playing before we started prerolling), we'll | 415 // of time (i.e., we were not playing before we started prerolling), we'll |
| 541 // manually update the current frame and notify the subclass below. | 416 // manually update the current frame and notify the subclass below. |
| 542 if (!ready_frames_.front()->IsEndOfStream()) | 417 if (!ready_frames_.front()->IsEndOfStream()) |
| 543 SetCurrentFrameToNextReadyFrame(); | 418 PaintWithNextReadyFrame(); |
| 544 | 419 |
| 545 // ...and we're done prerolling! | 420 // ...and we're done prerolling! |
| 546 DCHECK(!preroll_cb_.is_null()); | |
| 547 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK); | 421 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK); |
| 548 | 422 |
| 423 #if 0 | |
| 424 // XXX do we still need this!? | |
|
scherkus (not reviewing)
2013/01/31 17:54:05
PWNRF() fires the paint_cb_ ... I suppose this mig
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
Not sure. What did we use to paint in the case whe
scherkus (not reviewing)
2013/02/01 22:45:25
current_frame_ would have been null, so SkCanvasVi
| |
| 549 base::AutoUnlock ul(lock_); | 425 base::AutoUnlock ul(lock_); |
| 550 paint_cb_.Run(); | 426 paint_cb_.Run(); |
| 427 #endif | |
| 551 } | 428 } |
| 552 } | 429 } |
| 553 | 430 |
| 554 void VideoRendererBase::AddReadyFrame(const scoped_refptr<VideoFrame>& frame) { | 431 void VideoRendererBase::AddReadyFrame(const scoped_refptr<VideoFrame>& frame) { |
| 555 // Adjust the incoming frame if its rendering stop time is past the duration | 432 // Adjust the incoming frame if its rendering stop time is past the duration |
| 556 // of the video itself. This is typically the last frame of the video and | 433 // of the video itself. This is typically the last frame of the video and |
| 557 // occurs if the container specifies a duration that isn't a multiple of the | 434 // occurs if the container specifies a duration that isn't a multiple of the |
| 558 // frame rate. Another way for this to happen is for the container to state a | 435 // frame rate. Another way for this to happen is for the container to state a |
| 559 // smaller duration than the largest packet timestamp. | 436 // smaller duration than the largest packet timestamp. |
| 560 base::TimeDelta duration = get_duration_cb_.Run(); | 437 base::TimeDelta duration = get_duration_cb_.Run(); |
| 561 if (frame->IsEndOfStream()) { | 438 if (frame->IsEndOfStream()) { |
| 562 base::TimeDelta end_timestamp = kNoTimestamp(); | 439 base::TimeDelta end_timestamp = kNoTimestamp(); |
| 563 if (!ready_frames_.empty()) { | 440 if (!ready_frames_.empty()) { |
| 564 end_timestamp = std::min( | 441 end_timestamp = std::min( |
| 565 duration, | 442 duration, |
| 566 ready_frames_.back()->GetTimestamp() + kMaxLastFrameDuration()); | 443 ready_frames_.back()->GetTimestamp() + kMaxLastFrameDuration()); |
| 567 } else if (current_frame_) { | 444 } else if (last_timestamp_ != kNoTimestamp()) { |
| 568 end_timestamp = | 445 end_timestamp = |
| 569 std::min(duration, | 446 std::min(duration, last_timestamp_ + kMaxLastFrameDuration()); |
| 570 current_frame_->GetTimestamp() + kMaxLastFrameDuration()); | |
| 571 } | 447 } |
| 572 frame->SetTimestamp(end_timestamp); | 448 frame->SetTimestamp(end_timestamp); |
| 573 } else if (frame->GetTimestamp() > duration) { | 449 } else if (frame->GetTimestamp() > duration) { |
| 574 frame->SetTimestamp(duration); | 450 frame->SetTimestamp(duration); |
| 575 } | 451 } |
| 576 | 452 |
| 577 ready_frames_.push_back(frame); | 453 ready_frames_.push_back(frame); |
| 578 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); | 454 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); |
| 579 | 455 |
| 580 base::TimeDelta max_clock_time = | 456 base::TimeDelta max_clock_time = |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 629 AttemptFlush_Locked(); | 505 AttemptFlush_Locked(); |
| 630 } | 506 } |
| 631 | 507 |
| 632 void VideoRendererBase::AttemptFlush_Locked() { | 508 void VideoRendererBase::AttemptFlush_Locked() { |
| 633 lock_.AssertAcquired(); | 509 lock_.AssertAcquired(); |
| 634 DCHECK_EQ(kFlushing, state_); | 510 DCHECK_EQ(kFlushing, state_); |
| 635 | 511 |
| 636 prerolling_delayed_frame_ = NULL; | 512 prerolling_delayed_frame_ = NULL; |
| 637 ready_frames_.clear(); | 513 ready_frames_.clear(); |
| 638 | 514 |
| 639 if (!pending_paint_ && !pending_read_) { | 515 if (!pending_read_) { |
| 640 state_ = kFlushed; | 516 state_ = kFlushed; |
| 641 current_frame_ = NULL; | 517 last_timestamp_ = kNoTimestamp(); |
| 642 base::ResetAndReturn(&flush_cb_).Run(); | 518 base::ResetAndReturn(&flush_cb_).Run(); |
| 643 } | 519 } |
| 644 } | 520 } |
| 645 | 521 |
| 646 base::TimeDelta VideoRendererBase::CalculateSleepDuration( | 522 base::TimeDelta VideoRendererBase::CalculateSleepDuration( |
| 647 const scoped_refptr<VideoFrame>& next_frame, | 523 const scoped_refptr<VideoFrame>& next_frame, |
| 648 float playback_rate) { | 524 float playback_rate) { |
| 649 // Determine the current and next presentation timestamps. | 525 // Determine the current and next presentation timestamps. |
| 650 base::TimeDelta now = get_time_cb_.Run(); | 526 base::TimeDelta now = get_time_cb_.Run(); |
| 651 base::TimeDelta next_pts = next_frame->GetTimestamp(); | 527 base::TimeDelta next_pts = next_frame->GetTimestamp(); |
| 652 | 528 |
| 653 // Scale our sleep based on the playback rate. | 529 // Scale our sleep based on the playback rate. |
| 654 base::TimeDelta sleep = next_pts - now; | 530 base::TimeDelta sleep = next_pts - now; |
| 655 return base::TimeDelta::FromMicroseconds( | 531 return base::TimeDelta::FromMicroseconds( |
| 656 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); | 532 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); |
| 657 } | 533 } |
| 658 | 534 |
| 659 void VideoRendererBase::DoStopOrError_Locked() { | 535 void VideoRendererBase::DoStopOrError_Locked() { |
| 660 DCHECK(!pending_paint_); | |
| 661 DCHECK(!pending_paint_with_last_available_); | |
| 662 lock_.AssertAcquired(); | 536 lock_.AssertAcquired(); |
| 663 current_frame_ = NULL; | 537 last_timestamp_ = kNoTimestamp(); |
| 664 last_available_frame_ = NULL; | |
| 665 ready_frames_.clear(); | 538 ready_frames_.clear(); |
| 666 } | 539 } |
| 667 | 540 |
| 668 int VideoRendererBase::NumFrames_Locked() const { | 541 int VideoRendererBase::NumFrames_Locked() const { |
| 669 lock_.AssertAcquired(); | 542 lock_.AssertAcquired(); |
| 670 int outstanding_frames = | 543 return ready_frames_.size(); |
| 671 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) + | |
| 672 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0); | |
|
acolwell GONE FROM CHROMIUM
2013/02/01 00:24:34
o.O I'm not going to miss this.
| |
| 673 return ready_frames_.size() + outstanding_frames; | |
| 674 } | 544 } |
| 675 | 545 |
| 676 } // namespace media | 546 } // namespace media |
| OLD | NEW |