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()); |
85 base::AutoLock auto_lock(lock_); | |
86 if (state_ == kUninitialized || state_ == kStopped) { | 86 if (state_ == kUninitialized || state_ == kStopped) { |
87 callback.Run(); | 87 callback.Run(); |
88 return; | 88 return; |
89 } | 89 } |
90 | 90 |
91 state_ = kStopped; | |
92 | |
93 statistics_cb_.Reset(); | |
94 max_time_cb_.Reset(); | |
95 DoStopOrError_Locked(); | |
96 | |
97 // Clean up our thread if present. | |
91 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; | 98 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; |
92 { | 99 if (thread_ != base::kNullThreadHandle) { |
93 base::AutoLock auto_lock(lock_); | 100 // Signal the thread since it's possible to get stopped with the video |
94 state_ = kStopped; | 101 // thread waiting for a read to complete. |
102 frame_available_.Signal(); | |
103 std::swap(thread_, thread_to_join); | |
104 } | |
95 | 105 |
96 statistics_cb_.Reset(); | 106 if (thread_to_join != base::kNullThreadHandle) { |
97 max_time_cb_.Reset(); | 107 base::AutoUnlock auto_unlock(lock_); |
98 if (!pending_paint_ && !pending_paint_with_last_available_) | 108 base::PlatformThread::Join(thread_to_join); |
99 DoStopOrError_Locked(); | |
100 | |
101 // Clean up our thread if present. | |
102 if (thread_ != base::kNullThreadHandle) { | |
103 // Signal the thread since it's possible to get stopped with the video | |
104 // thread waiting for a read to complete. | |
105 frame_available_.Signal(); | |
106 thread_to_join = thread_; | |
107 thread_ = base::kNullThreadHandle; | |
108 } | |
109 } | 109 } |
110 if (thread_to_join != base::kNullThreadHandle) | |
111 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 } |
118 | 116 |
119 decoder_->Stop(callback); | 117 decoder_->Stop(callback); |
120 } | 118 } |
121 | 119 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
245 | 243 |
246 // The number of milliseconds to idle when we do not have anything to do. | 244 // The number of milliseconds to idle when we do not have anything to do. |
247 // Nothing special about the value, other than we're being more OS-friendly | 245 // Nothing special about the value, other than we're being more OS-friendly |
248 // than sleeping for 1 millisecond. | 246 // than sleeping for 1 millisecond. |
249 // | 247 // |
250 // TOOD(scherkus): switch to pure event-driven frame timing instead of this | 248 // TOOD(scherkus): switch to pure event-driven frame timing instead of this |
251 // kIdleTimeDelta business http://crbug.com/106874 | 249 // kIdleTimeDelta business http://crbug.com/106874 |
252 const base::TimeDelta kIdleTimeDelta = | 250 const base::TimeDelta kIdleTimeDelta = |
253 base::TimeDelta::FromMilliseconds(10); | 251 base::TimeDelta::FromMilliseconds(10); |
254 | 252 |
255 uint32 frames_dropped = 0; | |
256 | |
257 for (;;) { | 253 for (;;) { |
258 base::AutoLock auto_lock(lock_); | 254 base::AutoLock auto_lock(lock_); |
259 | 255 |
260 // Thread exit condition. | 256 // Thread exit condition. |
261 if (state_ == kStopped) | 257 if (state_ == kStopped) |
262 return; | 258 return; |
263 | 259 |
264 if (frames_dropped > 0) { | |
265 PipelineStatistics statistics; | |
266 statistics.video_frames_dropped = frames_dropped; | |
267 statistics_cb_.Run(statistics); | |
268 | |
269 frames_dropped = 0; | |
270 } | |
271 | |
272 // Remain idle as long as we're not playing. | 260 // Remain idle as long as we're not playing. |
273 if (state_ != kPlaying || playback_rate_ == 0) { | 261 if (state_ != kPlaying || playback_rate_ == 0) { |
274 frame_available_.TimedWait(kIdleTimeDelta); | 262 frame_available_.TimedWait(kIdleTimeDelta); |
275 continue; | 263 continue; |
276 } | 264 } |
277 | 265 |
278 // Remain idle until we have the next frame ready for rendering. | 266 // Remain idle until we have the next frame ready for rendering. |
279 if (ready_frames_.empty()) { | 267 if (ready_frames_.empty()) { |
280 frame_available_.TimedWait(kIdleTimeDelta); | 268 frame_available_.TimedWait(kIdleTimeDelta); |
281 continue; | 269 continue; |
282 } | 270 } |
283 | 271 |
284 // Remain idle until we've initialized |current_frame_| via prerolling. | 272 // We've reached the end! |
285 if (!current_frame_) { | 273 if (ready_frames_.front()->IsEndOfStream()) { |
286 // This can happen if our preroll only contains end of stream frames. | 274 state_ = kEnded; |
287 if (ready_frames_.front()->IsEndOfStream()) { | 275 ended_cb_.Run(); |
288 state_ = kEnded; | |
289 ended_cb_.Run(); | |
290 ready_frames_.clear(); | |
acolwell GONE FROM CHROMIUM
2013/02/04 17:35:15
Shouldn't we keep this line?
scherkus (not reviewing)
2013/02/05 00:29:39
Done.
| |
291 | 276 |
292 // No need to sleep here as we idle when |state_ != kPlaying|. | 277 // No need to sleep here as we idle when |state_ != kPlaying|. |
293 continue; | |
294 } | |
295 | |
296 frame_available_.TimedWait(kIdleTimeDelta); | |
297 continue; | 278 continue; |
298 } | 279 } |
299 | 280 |
300 // Calculate how long until we should advance the frame, which is | |
301 // typically negative but for playback rates < 1.0f may be long enough | |
302 // that it makes more sense to idle and check again. | |
303 base::TimeDelta remaining_time = | 281 base::TimeDelta remaining_time = |
304 CalculateSleepDuration(ready_frames_.front(), playback_rate_); | 282 CalculateSleepDuration(ready_frames_.front(), playback_rate_); |
305 | 283 |
306 // Sleep up to a maximum of our idle time until we're within the time to | 284 // Sleep up to a maximum of our idle time until we're within the time to |
307 // render the next frame. | 285 // render the next frame. |
308 if (remaining_time.InMicroseconds() > 0) { | 286 if (remaining_time.InMicroseconds() > 0) { |
309 remaining_time = std::min(remaining_time, kIdleTimeDelta); | 287 remaining_time = std::min(remaining_time, kIdleTimeDelta); |
310 frame_available_.TimedWait(remaining_time); | 288 frame_available_.TimedWait(remaining_time); |
311 continue; | 289 continue; |
312 } | 290 } |
313 | 291 |
292 // Deadline is defined as the midpoint between this frame and the next | |
scherkus (not reviewing)
2013/02/01 22:45:25
The old code's deadline was defined as:
remaining_
scherkus (not reviewing)
2013/02/05 00:29:39
Expanded this comment w/ more ideas.
| |
293 // frame, using the delta between this frame and the previous frame as the | |
294 // assumption for frame duration. | |
295 // | |
296 // TODO(scherkus): This can be vastly improved. Use a histogram to measure | |
297 // the accuracy of our frame timing code. http://crbug.com/149829 | |
298 if (drop_frames_ && last_timestamp_ != kNoTimestamp()) { | |
299 base::TimeDelta now = get_time_cb_.Run(); | |
300 base::TimeDelta deadline = ready_frames_.front()->GetTimestamp() + | |
301 (ready_frames_.front()->GetTimestamp() - last_timestamp_) / 2; | |
314 | 302 |
315 // We're almost there! | 303 if (now > deadline) { |
316 // | 304 DropNextReadyFrame_Locked(); |
317 // At this point we've rendered |current_frame_| for the proper amount | 305 continue; |
318 // of time and also have the next frame that ready for rendering. | 306 } |
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 } | 307 } |
334 | 308 |
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. | 309 // Congratulations! You've made it past the video frame timing gauntlet. |
368 // | 310 // |
369 // We can now safely update the current frame, request another frame, and | 311 // 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. | 312 // rendering. |
371 DCHECK(!pending_paint_); | 313 PaintNextReadyFrame_Locked(); |
372 DCHECK(!ready_frames_.empty()); | |
373 SetCurrentFrameToNextReadyFrame(); | |
374 message_loop_->PostTask(FROM_HERE, base::Bind( | |
375 &VideoRendererBase::AttemptRead, this)); | |
376 | |
377 base::AutoUnlock auto_unlock(lock_); | |
378 paint_cb_.Run(); | |
379 } | 314 } |
380 } | 315 } |
381 | 316 |
382 void VideoRendererBase::SetCurrentFrameToNextReadyFrame() { | 317 void VideoRendererBase::PaintNextReadyFrame_Locked() { |
383 current_frame_ = ready_frames_.front(); | 318 lock_.AssertAcquired(); |
319 | |
320 scoped_refptr<VideoFrame> next_frame = ready_frames_.front(); | |
384 ready_frames_.pop_front(); | 321 ready_frames_.pop_front(); |
385 | 322 |
386 // Notify the pipeline of natural_size() changes. | 323 last_timestamp_ = next_frame->GetTimestamp(); |
387 const gfx::Size& natural_size = current_frame_->natural_size(); | 324 |
325 const gfx::Size& natural_size = next_frame->natural_size(); | |
388 if (natural_size != last_natural_size_) { | 326 if (natural_size != last_natural_size_) { |
327 last_natural_size_ = natural_size; | |
389 size_changed_cb_.Run(natural_size); | 328 size_changed_cb_.Run(natural_size); |
390 last_natural_size_ = natural_size; | |
391 } | 329 } |
330 | |
331 paint_cb_.Run(next_frame); | |
332 | |
333 message_loop_->PostTask(FROM_HERE, base::Bind( | |
334 &VideoRendererBase::AttemptRead, this)); | |
392 } | 335 } |
393 | 336 |
394 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { | 337 void VideoRendererBase::DropNextReadyFrame_Locked() { |
395 base::AutoLock auto_lock(lock_); | 338 lock_.AssertAcquired(); |
396 DCHECK(!pending_paint_ && !pending_paint_with_last_available_); | |
397 | 339 |
398 if ((!current_frame_ || current_frame_->IsEndOfStream()) && | 340 last_timestamp_ = ready_frames_.front()->GetTimestamp(); |
399 (!last_available_frame_ || last_available_frame_->IsEndOfStream())) { | 341 ready_frames_.pop_front(); |
400 *frame_out = NULL; | |
401 return; | |
402 } | |
403 | 342 |
404 // We should have initialized and have the current frame. | 343 PipelineStatistics statistics; |
405 DCHECK_NE(state_, kUninitialized); | 344 statistics.video_frames_dropped = 1; |
406 DCHECK_NE(state_, kStopped); | 345 statistics_cb_.Run(statistics); |
407 DCHECK_NE(state_, kError); | |
408 | 346 |
409 if (current_frame_) { | 347 message_loop_->PostTask(FROM_HERE, base::Bind( |
410 *frame_out = current_frame_; | 348 &VideoRendererBase::AttemptRead, this)); |
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 } | 349 } |
453 | 350 |
454 VideoRendererBase::~VideoRendererBase() { | 351 VideoRendererBase::~VideoRendererBase() { |
455 base::AutoLock auto_lock(lock_); | 352 base::AutoLock auto_lock(lock_); |
456 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; | 353 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; |
457 } | 354 } |
458 | 355 |
459 void VideoRendererBase::FrameReady(VideoDecoder::Status status, | 356 void VideoRendererBase::FrameReady(VideoDecoder::Status status, |
460 const scoped_refptr<VideoFrame>& frame) { | 357 const scoped_refptr<VideoFrame>& frame) { |
461 base::AutoLock auto_lock(lock_); | 358 base::AutoLock auto_lock(lock_); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
525 // purposes: | 422 // purposes: |
526 // 1) Prerolling while paused | 423 // 1) Prerolling while paused |
527 // 2) Keeps decoding going if video rendering thread starts falling behind | 424 // 2) Keeps decoding going if video rendering thread starts falling behind |
528 if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) { | 425 if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) { |
529 AttemptRead_Locked(); | 426 AttemptRead_Locked(); |
530 return; | 427 return; |
531 } | 428 } |
532 | 429 |
533 // If we're at capacity or end of stream while prerolling we need to | 430 // If we're at capacity or end of stream while prerolling we need to |
534 // transition to prerolled. | 431 // transition to prerolled. |
535 if (state_ == kPrerolling) { | 432 if (state_ != kPrerolling) |
536 DCHECK(!current_frame_); | 433 return; |
537 state_ = kPrerolled; | |
538 | 434 |
539 // Because we might remain in the prerolled state for an undetermined amount | 435 state_ = kPrerolled; |
540 // 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. | |
542 if (!ready_frames_.front()->IsEndOfStream()) | |
543 SetCurrentFrameToNextReadyFrame(); | |
544 | 436 |
545 // ...and we're done prerolling! | 437 // Because we might remain in the prerolled state for an undetermined amount |
546 DCHECK(!preroll_cb_.is_null()); | 438 // of time (e.g., we seeked while paused), we'll paint the first prerolled |
547 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK); | 439 // frame. |
440 if (!ready_frames_.front()->IsEndOfStream()) | |
441 PaintNextReadyFrame_Locked(); | |
548 | 442 |
549 base::AutoUnlock ul(lock_); | 443 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK); |
550 paint_cb_.Run(); | |
551 } | |
552 } | 444 } |
553 | 445 |
554 void VideoRendererBase::AddReadyFrame(const scoped_refptr<VideoFrame>& frame) { | 446 void VideoRendererBase::AddReadyFrame(const scoped_refptr<VideoFrame>& frame) { |
555 // Adjust the incoming frame if its rendering stop time is past the duration | 447 // 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 | 448 // 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 | 449 // 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 | 450 // frame rate. Another way for this to happen is for the container to state a |
559 // smaller duration than the largest packet timestamp. | 451 // smaller duration than the largest packet timestamp. |
560 base::TimeDelta duration = get_duration_cb_.Run(); | 452 base::TimeDelta duration = get_duration_cb_.Run(); |
561 if (frame->IsEndOfStream()) { | 453 if (frame->IsEndOfStream()) { |
562 base::TimeDelta end_timestamp = kNoTimestamp(); | 454 base::TimeDelta end_timestamp = kNoTimestamp(); |
563 if (!ready_frames_.empty()) { | 455 if (!ready_frames_.empty()) { |
564 end_timestamp = std::min( | 456 end_timestamp = std::min( |
565 duration, | 457 duration, |
566 ready_frames_.back()->GetTimestamp() + kMaxLastFrameDuration()); | 458 ready_frames_.back()->GetTimestamp() + kMaxLastFrameDuration()); |
567 } else if (current_frame_) { | 459 } else if (last_timestamp_ != kNoTimestamp()) { |
568 end_timestamp = | 460 end_timestamp = |
569 std::min(duration, | 461 std::min(duration, last_timestamp_ + kMaxLastFrameDuration()); |
570 current_frame_->GetTimestamp() + kMaxLastFrameDuration()); | |
571 } | 462 } |
572 frame->SetTimestamp(end_timestamp); | 463 frame->SetTimestamp(end_timestamp); |
573 } else if (frame->GetTimestamp() > duration) { | 464 } else if (frame->GetTimestamp() > duration) { |
574 frame->SetTimestamp(duration); | 465 frame->SetTimestamp(duration); |
575 } | 466 } |
576 | 467 |
577 ready_frames_.push_back(frame); | 468 ready_frames_.push_back(frame); |
578 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); | 469 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); |
579 | 470 |
580 base::TimeDelta max_clock_time = | 471 base::TimeDelta max_clock_time = |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
629 AttemptFlush_Locked(); | 520 AttemptFlush_Locked(); |
630 } | 521 } |
631 | 522 |
632 void VideoRendererBase::AttemptFlush_Locked() { | 523 void VideoRendererBase::AttemptFlush_Locked() { |
633 lock_.AssertAcquired(); | 524 lock_.AssertAcquired(); |
634 DCHECK_EQ(kFlushing, state_); | 525 DCHECK_EQ(kFlushing, state_); |
635 | 526 |
636 prerolling_delayed_frame_ = NULL; | 527 prerolling_delayed_frame_ = NULL; |
637 ready_frames_.clear(); | 528 ready_frames_.clear(); |
638 | 529 |
639 if (!pending_paint_ && !pending_read_) { | 530 if (pending_read_) |
640 state_ = kFlushed; | 531 return; |
641 current_frame_ = NULL; | 532 |
642 base::ResetAndReturn(&flush_cb_).Run(); | 533 state_ = kFlushed; |
643 } | 534 last_timestamp_ = kNoTimestamp(); |
535 base::ResetAndReturn(&flush_cb_).Run(); | |
644 } | 536 } |
645 | 537 |
646 base::TimeDelta VideoRendererBase::CalculateSleepDuration( | 538 base::TimeDelta VideoRendererBase::CalculateSleepDuration( |
647 const scoped_refptr<VideoFrame>& next_frame, | 539 const scoped_refptr<VideoFrame>& next_frame, |
648 float playback_rate) { | 540 float playback_rate) { |
649 // Determine the current and next presentation timestamps. | 541 // Determine the current and next presentation timestamps. |
650 base::TimeDelta now = get_time_cb_.Run(); | 542 base::TimeDelta now = get_time_cb_.Run(); |
651 base::TimeDelta next_pts = next_frame->GetTimestamp(); | 543 base::TimeDelta next_pts = next_frame->GetTimestamp(); |
652 | 544 |
653 // Scale our sleep based on the playback rate. | 545 // Scale our sleep based on the playback rate. |
654 base::TimeDelta sleep = next_pts - now; | 546 base::TimeDelta sleep = next_pts - now; |
655 return base::TimeDelta::FromMicroseconds( | 547 return base::TimeDelta::FromMicroseconds( |
656 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); | 548 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); |
657 } | 549 } |
658 | 550 |
659 void VideoRendererBase::DoStopOrError_Locked() { | 551 void VideoRendererBase::DoStopOrError_Locked() { |
660 DCHECK(!pending_paint_); | |
661 DCHECK(!pending_paint_with_last_available_); | |
662 lock_.AssertAcquired(); | 552 lock_.AssertAcquired(); |
663 current_frame_ = NULL; | 553 last_timestamp_ = kNoTimestamp(); |
664 last_available_frame_ = NULL; | |
665 ready_frames_.clear(); | 554 ready_frames_.clear(); |
666 } | 555 } |
667 | 556 |
668 int VideoRendererBase::NumFrames_Locked() const { | 557 int VideoRendererBase::NumFrames_Locked() const { |
669 lock_.AssertAcquired(); | 558 lock_.AssertAcquired(); |
670 int outstanding_frames = | 559 return ready_frames_.size(); |
671 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) + | |
672 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0); | |
673 return ready_frames_.size() + outstanding_frames; | |
674 } | 560 } |
675 | 561 |
676 } // namespace media | 562 } // namespace media |
OLD | NEW |