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" |
| 6 |
5 #include "base/bind.h" | 7 #include "base/bind.h" |
6 #include "base/callback.h" | 8 #include "base/callback.h" |
7 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
8 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
9 #include "media/base/buffers.h" | 11 #include "media/base/buffers.h" |
10 #include "media/base/filter_host.h" | |
11 #include "media/base/limits.h" | 12 #include "media/base/limits.h" |
12 #include "media/base/pipeline.h" | 13 #include "media/base/pipeline.h" |
13 #include "media/base/video_frame.h" | 14 #include "media/base/video_frame.h" |
14 #include "media/filters/video_renderer_base.h" | |
15 | 15 |
16 namespace media { | 16 namespace media { |
17 | 17 |
18 VideoRendererBase::VideoRendererBase(const base::Closure& paint_cb, | 18 VideoRendererBase::VideoRendererBase(const base::Closure& paint_cb, |
19 const SetOpaqueCB& set_opaque_cb, | 19 const SetOpaqueCB& set_opaque_cb, |
20 bool drop_frames) | 20 bool drop_frames) |
21 : host_(NULL), | 21 : frame_available_(&lock_), |
22 frame_available_(&lock_), | |
23 state_(kUninitialized), | 22 state_(kUninitialized), |
24 thread_(base::kNullThreadHandle), | 23 thread_(base::kNullThreadHandle), |
25 pending_read_(false), | 24 pending_read_(false), |
26 pending_paint_(false), | 25 pending_paint_(false), |
27 pending_paint_with_last_available_(false), | 26 pending_paint_with_last_available_(false), |
28 drop_frames_(drop_frames), | 27 drop_frames_(drop_frames), |
29 playback_rate_(0), | 28 playback_rate_(0), |
30 paint_cb_(paint_cb), | 29 paint_cb_(paint_cb), |
31 set_opaque_cb_(set_opaque_cb) { | 30 set_opaque_cb_(set_opaque_cb) { |
32 DCHECK(!paint_cb_.is_null()); | 31 DCHECK(!paint_cb_.is_null()); |
33 } | 32 } |
34 | 33 |
35 void VideoRendererBase::SetHost(FilterHost* host) { | |
36 DCHECK(host); | |
37 DCHECK(!host_); | |
38 host_ = host; | |
39 } | |
40 | |
41 void VideoRendererBase::Play(const base::Closure& callback) { | 34 void VideoRendererBase::Play(const base::Closure& callback) { |
42 base::AutoLock auto_lock(lock_); | 35 base::AutoLock auto_lock(lock_); |
43 DCHECK_EQ(kPrerolled, state_); | 36 DCHECK_EQ(kPrerolled, state_); |
44 state_ = kPlaying; | 37 state_ = kPlaying; |
45 callback.Run(); | 38 callback.Run(); |
46 } | 39 } |
47 | 40 |
48 void VideoRendererBase::Pause(const base::Closure& callback) { | 41 void VideoRendererBase::Pause(const base::Closure& callback) { |
49 base::AutoLock auto_lock(lock_); | 42 base::AutoLock auto_lock(lock_); |
50 DCHECK(state_ != kUninitialized || state_ == kError); | 43 DCHECK(state_ != kUninitialized || state_ == kError); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 | 102 |
110 state_ = kSeeking; | 103 state_ = kSeeking; |
111 seek_cb_ = cb; | 104 seek_cb_ = cb; |
112 seek_timestamp_ = time; | 105 seek_timestamp_ = time; |
113 AttemptRead_Locked(); | 106 AttemptRead_Locked(); |
114 } | 107 } |
115 | 108 |
116 void VideoRendererBase::Initialize(const scoped_refptr<VideoDecoder>& decoder, | 109 void VideoRendererBase::Initialize(const scoped_refptr<VideoDecoder>& decoder, |
117 const PipelineStatusCB& status_cb, | 110 const PipelineStatusCB& status_cb, |
118 const StatisticsCB& statistics_cb, | 111 const StatisticsCB& statistics_cb, |
119 const TimeCB& time_cb) { | 112 const TimeCB& time_cb, |
| 113 const NaturalSizeChangedCB& size_changed_cb, |
| 114 const base::Closure& ended_cb, |
| 115 const PipelineStatusCB& error_cb, |
| 116 const TimeDeltaCB& get_time_cb, |
| 117 const TimeDeltaCB& get_duration_cb) { |
120 base::AutoLock auto_lock(lock_); | 118 base::AutoLock auto_lock(lock_); |
121 DCHECK(decoder); | 119 DCHECK(decoder); |
122 DCHECK(!status_cb.is_null()); | 120 DCHECK(!status_cb.is_null()); |
123 DCHECK(!statistics_cb.is_null()); | 121 DCHECK(!statistics_cb.is_null()); |
124 DCHECK(!time_cb.is_null()); | 122 DCHECK(!time_cb.is_null()); |
| 123 DCHECK(!size_changed_cb.is_null()); |
| 124 DCHECK(!ended_cb.is_null()); |
| 125 DCHECK(!get_time_cb.is_null()); |
| 126 DCHECK(!get_duration_cb.is_null()); |
125 DCHECK_EQ(kUninitialized, state_); | 127 DCHECK_EQ(kUninitialized, state_); |
126 decoder_ = decoder; | 128 decoder_ = decoder; |
127 | 129 |
128 statistics_cb_ = statistics_cb; | 130 statistics_cb_ = statistics_cb; |
129 time_cb_ = time_cb; | 131 time_cb_ = time_cb; |
| 132 size_changed_cb_ = size_changed_cb; |
| 133 ended_cb_ = ended_cb; |
| 134 error_cb_ = error_cb; |
| 135 get_time_cb_ = get_time_cb; |
| 136 get_duration_cb_ = get_duration_cb; |
130 | 137 |
131 // Notify the pipeline of the video dimensions. | 138 // Notify the pipeline of the video dimensions. |
132 host_->SetNaturalVideoSize(decoder_->natural_size()); | 139 size_changed_cb_.Run(decoder_->natural_size()); |
133 | 140 |
134 // We're all good! Consider ourselves flushed. (ThreadMain() should never | 141 // We're all good! Consider ourselves flushed. (ThreadMain() should never |
135 // see us in the kUninitialized state). | 142 // see us in the kUninitialized state). |
136 // Since we had an initial Seek, we consider ourself flushed, because we | 143 // Since we had an initial Seek, we consider ourself flushed, because we |
137 // have not populated any buffers yet. | 144 // have not populated any buffers yet. |
138 state_ = kFlushed; | 145 state_ = kFlushed; |
139 | 146 |
140 set_opaque_cb_.Run(!decoder->HasAlpha()); | 147 set_opaque_cb_.Run(!decoder->HasAlpha()); |
141 set_opaque_cb_.Reset(); | 148 set_opaque_cb_.Reset(); |
142 | 149 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 if (ready_frames_.empty()) { | 208 if (ready_frames_.empty()) { |
202 frame_available_.TimedWait(kIdleTimeDelta); | 209 frame_available_.TimedWait(kIdleTimeDelta); |
203 continue; | 210 continue; |
204 } | 211 } |
205 | 212 |
206 // Remain idle until we've initialized |current_frame_| via prerolling. | 213 // Remain idle until we've initialized |current_frame_| via prerolling. |
207 if (!current_frame_) { | 214 if (!current_frame_) { |
208 // This can happen if our preroll only contains end of stream frames. | 215 // This can happen if our preroll only contains end of stream frames. |
209 if (ready_frames_.front()->IsEndOfStream()) { | 216 if (ready_frames_.front()->IsEndOfStream()) { |
210 state_ = kEnded; | 217 state_ = kEnded; |
211 host_->NotifyEnded(); | 218 ended_cb_.Run(); |
212 ready_frames_.clear(); | 219 ready_frames_.clear(); |
213 | 220 |
214 // No need to sleep here as we idle when |state_ != kPlaying|. | 221 // No need to sleep here as we idle when |state_ != kPlaying|. |
215 continue; | 222 continue; |
216 } | 223 } |
217 | 224 |
218 frame_available_.TimedWait(kIdleTimeDelta); | 225 frame_available_.TimedWait(kIdleTimeDelta); |
219 continue; | 226 continue; |
220 } | 227 } |
221 | 228 |
(...skipping 18 matching lines...) Expand all Loading... |
240 // of time and also have the next frame that ready for rendering. | 247 // of time and also have the next frame that ready for rendering. |
241 | 248 |
242 | 249 |
243 // If the next frame is end of stream then we are truly at the end of the | 250 // If the next frame is end of stream then we are truly at the end of the |
244 // video stream. | 251 // video stream. |
245 // | 252 // |
246 // TODO(scherkus): deduplicate this end of stream check after we get rid of | 253 // TODO(scherkus): deduplicate this end of stream check after we get rid of |
247 // |current_frame_|. | 254 // |current_frame_|. |
248 if (ready_frames_.front()->IsEndOfStream()) { | 255 if (ready_frames_.front()->IsEndOfStream()) { |
249 state_ = kEnded; | 256 state_ = kEnded; |
250 host_->NotifyEnded(); | 257 ended_cb_.Run(); |
251 ready_frames_.clear(); | 258 ready_frames_.clear(); |
252 | 259 |
253 // No need to sleep here as we idle when |state_ != kPlaying|. | 260 // No need to sleep here as we idle when |state_ != kPlaying|. |
254 continue; | 261 continue; |
255 } | 262 } |
256 | 263 |
257 // We cannot update |current_frame_| until we've completed the pending | 264 // We cannot update |current_frame_| until we've completed the pending |
258 // paint. Furthermore, the pending paint might be really slow: check to | 265 // paint. Furthermore, the pending paint might be really slow: check to |
259 // see if we have any ready frames that we can drop if they've already | 266 // see if we have any ready frames that we can drop if they've already |
260 // expired. | 267 // expired. |
261 if (pending_paint_) { | 268 if (pending_paint_) { |
262 while (!ready_frames_.empty()) { | 269 while (!ready_frames_.empty()) { |
263 // Can't drop anything if we're at the end. | 270 // Can't drop anything if we're at the end. |
264 if (ready_frames_.front()->IsEndOfStream()) | 271 if (ready_frames_.front()->IsEndOfStream()) |
265 break; | 272 break; |
266 | 273 |
267 base::TimeDelta remaining_time = | 274 base::TimeDelta remaining_time = |
268 ready_frames_.front()->GetTimestamp() - host_->GetTime(); | 275 ready_frames_.front()->GetTimestamp() - get_time_cb_.Run(); |
269 | 276 |
270 // Still a chance we can render the frame! | 277 // Still a chance we can render the frame! |
271 if (remaining_time.InMicroseconds() > 0) | 278 if (remaining_time.InMicroseconds() > 0) |
272 break; | 279 break; |
273 | 280 |
274 if (!drop_frames_) | 281 if (!drop_frames_) |
275 break; | 282 break; |
276 | 283 |
277 // Frame dropped: read again. | 284 // Frame dropped: read again. |
278 ++frames_dropped; | 285 ++frames_dropped; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 DCHECK(!frame); | 384 DCHECK(!frame); |
378 PipelineStatus error = PIPELINE_ERROR_DECODE; | 385 PipelineStatus error = PIPELINE_ERROR_DECODE; |
379 if (status == VideoDecoder::kDecryptError) | 386 if (status == VideoDecoder::kDecryptError) |
380 error = PIPELINE_ERROR_DECRYPT; | 387 error = PIPELINE_ERROR_DECRYPT; |
381 | 388 |
382 if (!seek_cb_.is_null()) { | 389 if (!seek_cb_.is_null()) { |
383 base::ResetAndReturn(&seek_cb_).Run(error); | 390 base::ResetAndReturn(&seek_cb_).Run(error); |
384 return; | 391 return; |
385 } | 392 } |
386 | 393 |
387 host_->SetError(error); | 394 error_cb_.Run(error); |
388 return; | 395 return; |
389 } | 396 } |
390 | 397 |
391 // Already-queued Decoder ReadCB's can fire after various state transitions | 398 // Already-queued Decoder ReadCB's can fire after various state transitions |
392 // have happened; in that case just drop those frames immediately. | 399 // have happened; in that case just drop those frames immediately. |
393 if (state_ == kStopped || state_ == kError || state_ == kFlushed || | 400 if (state_ == kStopped || state_ == kError || state_ == kFlushed || |
394 state_ == kFlushingDecoder) | 401 state_ == kFlushingDecoder) |
395 return; | 402 return; |
396 | 403 |
397 if (state_ == kFlushing) { | 404 if (state_ == kFlushing) { |
(...skipping 19 matching lines...) Expand all Loading... |
417 AttemptRead_Locked(); | 424 AttemptRead_Locked(); |
418 return; | 425 return; |
419 } | 426 } |
420 | 427 |
421 // Adjust the incoming frame if its rendering stop time is past the duration | 428 // Adjust the incoming frame if its rendering stop time is past the duration |
422 // of the video itself. This is typically the last frame of the video and | 429 // of the video itself. This is typically the last frame of the video and |
423 // occurs if the container specifies a duration that isn't a multiple of the | 430 // occurs if the container specifies a duration that isn't a multiple of the |
424 // frame rate. Another way for this to happen is for the container to state a | 431 // frame rate. Another way for this to happen is for the container to state a |
425 // smaller duration than the largest packet timestamp. | 432 // smaller duration than the largest packet timestamp. |
426 if (!frame->IsEndOfStream()) { | 433 if (!frame->IsEndOfStream()) { |
427 if (frame->GetTimestamp() > host_->GetDuration()) | 434 base::TimeDelta duration = get_duration_cb_.Run(); |
428 frame->SetTimestamp(host_->GetDuration()); | 435 if (frame->GetTimestamp() > duration) |
429 if ((frame->GetTimestamp() + frame->GetDuration()) > host_->GetDuration()) | 436 frame->SetTimestamp(duration); |
430 frame->SetDuration(host_->GetDuration() - frame->GetTimestamp()); | 437 if ((frame->GetTimestamp() + frame->GetDuration()) > duration) |
| 438 frame->SetDuration(duration - frame->GetTimestamp()); |
431 } | 439 } |
432 | 440 |
433 // This one's a keeper! Place it in the ready queue. | 441 // This one's a keeper! Place it in the ready queue. |
434 ready_frames_.push_back(frame); | 442 ready_frames_.push_back(frame); |
435 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); | 443 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); |
436 if (!frame->IsEndOfStream()) | 444 if (!frame->IsEndOfStream()) |
437 time_cb_.Run(frame->GetTimestamp() + frame->GetDuration()); | 445 time_cb_.Run(frame->GetTimestamp() + frame->GetDuration()); |
438 frame_available_.Signal(); | 446 frame_available_.Signal(); |
439 | 447 |
440 PipelineStatistics statistics; | 448 PipelineStatistics statistics; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 state_ = kFlushed; | 517 state_ = kFlushed; |
510 current_frame_ = NULL; | 518 current_frame_ = NULL; |
511 base::ResetAndReturn(&flush_cb_).Run(); | 519 base::ResetAndReturn(&flush_cb_).Run(); |
512 } | 520 } |
513 } | 521 } |
514 | 522 |
515 base::TimeDelta VideoRendererBase::CalculateSleepDuration( | 523 base::TimeDelta VideoRendererBase::CalculateSleepDuration( |
516 const scoped_refptr<VideoFrame>& next_frame, | 524 const scoped_refptr<VideoFrame>& next_frame, |
517 float playback_rate) { | 525 float playback_rate) { |
518 // Determine the current and next presentation timestamps. | 526 // Determine the current and next presentation timestamps. |
519 base::TimeDelta now = host_->GetTime(); | 527 base::TimeDelta now = get_time_cb_.Run(); |
520 base::TimeDelta this_pts = current_frame_->GetTimestamp(); | 528 base::TimeDelta this_pts = current_frame_->GetTimestamp(); |
521 base::TimeDelta next_pts; | 529 base::TimeDelta next_pts; |
522 if (!next_frame->IsEndOfStream()) { | 530 if (!next_frame->IsEndOfStream()) { |
523 next_pts = next_frame->GetTimestamp(); | 531 next_pts = next_frame->GetTimestamp(); |
524 } else { | 532 } else { |
525 next_pts = this_pts + current_frame_->GetDuration(); | 533 next_pts = this_pts + current_frame_->GetDuration(); |
526 } | 534 } |
527 | 535 |
528 // Scale our sleep based on the playback rate. | 536 // Scale our sleep based on the playback rate. |
529 base::TimeDelta sleep = next_pts - now; | 537 base::TimeDelta sleep = next_pts - now; |
(...skipping 12 matching lines...) Expand all Loading... |
542 | 550 |
543 int VideoRendererBase::NumFrames_Locked() const { | 551 int VideoRendererBase::NumFrames_Locked() const { |
544 lock_.AssertAcquired(); | 552 lock_.AssertAcquired(); |
545 int outstanding_frames = | 553 int outstanding_frames = |
546 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) + | 554 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) + |
547 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0); | 555 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0); |
548 return ready_frames_.size() + outstanding_frames; | 556 return ready_frames_.size() + outstanding_frames; |
549 } | 557 } |
550 | 558 |
551 } // namespace media | 559 } // namespace media |
OLD | NEW |