roll skia to 4057
[chromium-blink-merge.git] / media / filters / video_renderer_base.cc
blobb0672f540bc80b1178537e65a5108812cd5450d7
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
3 // found in the LICENSE file.
5 #include "base/bind.h"
6 #include "base/callback.h"
7 #include "base/callback_helpers.h"
8 #include "base/threading/platform_thread.h"
9 #include "media/base/buffers.h"
10 #include "media/base/filter_host.h"
11 #include "media/base/limits.h"
12 #include "media/base/pipeline.h"
13 #include "media/base/video_frame.h"
14 #include "media/filters/video_renderer_base.h"
16 namespace media {
18 VideoRendererBase::VideoRendererBase(const base::Closure& paint_cb,
19 const SetOpaqueCB& set_opaque_cb,
20 bool drop_frames)
21 : frame_available_(&lock_),
22 state_(kUninitialized),
23 thread_(base::kNullThreadHandle),
24 pending_read_(false),
25 pending_paint_(false),
26 pending_paint_with_last_available_(false),
27 drop_frames_(drop_frames),
28 playback_rate_(0),
29 paint_cb_(paint_cb),
30 set_opaque_cb_(set_opaque_cb) {
31 DCHECK(!paint_cb_.is_null());
34 void VideoRendererBase::Play(const base::Closure& callback) {
35 base::AutoLock auto_lock(lock_);
36 DCHECK_EQ(kPrerolled, state_);
37 state_ = kPlaying;
38 callback.Run();
41 void VideoRendererBase::Pause(const base::Closure& callback) {
42 base::AutoLock auto_lock(lock_);
43 DCHECK(state_ != kUninitialized || state_ == kError);
44 state_ = kPaused;
45 callback.Run();
48 void VideoRendererBase::Flush(const base::Closure& callback) {
49 base::AutoLock auto_lock(lock_);
50 DCHECK_EQ(state_, kPaused);
51 flush_cb_ = callback;
52 state_ = kFlushingDecoder;
54 // We must unlock here because the callback might run within the Flush()
55 // call.
56 // TODO: Remove this line when fixing http://crbug.com/125020
57 base::AutoUnlock auto_unlock(lock_);
58 decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderFlushDone, this));
61 void VideoRendererBase::Stop(const base::Closure& callback) {
62 if (state_ == kStopped) {
63 callback.Run();
64 return;
67 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle;
69 base::AutoLock auto_lock(lock_);
70 state_ = kStopped;
72 statistics_cb_.Reset();
73 time_cb_.Reset();
74 if (!pending_paint_ && !pending_paint_with_last_available_)
75 DoStopOrError_Locked();
77 // Clean up our thread if present.
78 if (thread_ != base::kNullThreadHandle) {
79 // Signal the thread since it's possible to get stopped with the video
80 // thread waiting for a read to complete.
81 frame_available_.Signal();
82 thread_to_join = thread_;
83 thread_ = base::kNullThreadHandle;
86 if (thread_to_join != base::kNullThreadHandle)
87 base::PlatformThread::Join(thread_to_join);
89 decoder_->Stop(callback);
92 void VideoRendererBase::SetPlaybackRate(float playback_rate) {
93 base::AutoLock auto_lock(lock_);
94 playback_rate_ = playback_rate;
97 void VideoRendererBase::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
98 base::AutoLock auto_lock(lock_);
99 DCHECK_EQ(state_, kFlushed) << "Must flush prior to seeking.";
100 DCHECK(!cb.is_null());
101 DCHECK(seek_cb_.is_null());
103 state_ = kSeeking;
104 seek_cb_ = cb;
105 seek_timestamp_ = time;
106 AttemptRead_Locked();
109 void VideoRendererBase::Initialize(const scoped_refptr<VideoDecoder>& decoder,
110 const PipelineStatusCB& status_cb,
111 const StatisticsCB& statistics_cb,
112 const TimeCB& time_cb) {
113 base::AutoLock auto_lock(lock_);
114 DCHECK(decoder);
115 DCHECK(!status_cb.is_null());
116 DCHECK(!statistics_cb.is_null());
117 DCHECK(!time_cb.is_null());
118 DCHECK_EQ(kUninitialized, state_);
119 decoder_ = decoder;
121 statistics_cb_ = statistics_cb;
122 time_cb_ = time_cb;
124 // Notify the pipeline of the video dimensions.
125 host()->SetNaturalVideoSize(decoder_->natural_size());
127 // We're all good! Consider ourselves flushed. (ThreadMain() should never
128 // see us in the kUninitialized state).
129 // Since we had an initial Seek, we consider ourself flushed, because we
130 // have not populated any buffers yet.
131 state_ = kFlushed;
133 set_opaque_cb_.Run(!decoder->HasAlpha());
134 set_opaque_cb_.Reset();
136 // Create our video thread.
137 if (!base::PlatformThread::Create(0, this, &thread_)) {
138 NOTREACHED() << "Video thread creation failed";
139 state_ = kError;
140 status_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
141 return;
144 #if defined(OS_WIN)
145 // Bump up our priority so our sleeping is more accurate.
146 // TODO(scherkus): find out if this is necessary, but it seems to help.
147 ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
148 #endif // defined(OS_WIN)
149 status_cb.Run(PIPELINE_OK);
152 bool VideoRendererBase::HasEnded() {
153 base::AutoLock auto_lock(lock_);
154 return state_ == kEnded;
157 // PlatformThread::Delegate implementation.
158 void VideoRendererBase::ThreadMain() {
159 base::PlatformThread::SetName("CrVideoRenderer");
161 // The number of milliseconds to idle when we do not have anything to do.
162 // Nothing special about the value, other than we're being more OS-friendly
163 // than sleeping for 1 millisecond.
165 // TOOD(scherkus): switch to pure event-driven frame timing instead of this
166 // kIdleTimeDelta business http://crbug.com/106874
167 const base::TimeDelta kIdleTimeDelta =
168 base::TimeDelta::FromMilliseconds(10);
170 uint32 frames_dropped = 0;
172 for (;;) {
173 if (frames_dropped > 0) {
174 PipelineStatistics statistics;
175 statistics.video_frames_dropped = frames_dropped;
176 statistics_cb_.Run(statistics);
178 frames_dropped = 0;
181 base::AutoLock auto_lock(lock_);
183 // Thread exit condition.
184 if (state_ == kStopped)
185 return;
187 // Remain idle as long as we're not playing.
188 if (state_ != kPlaying || playback_rate_ == 0) {
189 frame_available_.TimedWait(kIdleTimeDelta);
190 continue;
193 // Remain idle until we have the next frame ready for rendering.
194 if (ready_frames_.empty()) {
195 frame_available_.TimedWait(kIdleTimeDelta);
196 continue;
199 // Remain idle until we've initialized |current_frame_| via prerolling.
200 if (!current_frame_) {
201 // This can happen if our preroll only contains end of stream frames.
202 if (ready_frames_.front()->IsEndOfStream()) {
203 state_ = kEnded;
204 host()->NotifyEnded();
205 ready_frames_.clear();
207 // No need to sleep here as we idle when |state_ != kPlaying|.
208 continue;
211 frame_available_.TimedWait(kIdleTimeDelta);
212 continue;
215 // Calculate how long until we should advance the frame, which is
216 // typically negative but for playback rates < 1.0f may be long enough
217 // that it makes more sense to idle and check again.
218 base::TimeDelta remaining_time =
219 CalculateSleepDuration(ready_frames_.front(), playback_rate_);
221 // Sleep up to a maximum of our idle time until we're within the time to
222 // render the next frame.
223 if (remaining_time.InMicroseconds() > 0) {
224 remaining_time = std::min(remaining_time, kIdleTimeDelta);
225 frame_available_.TimedWait(remaining_time);
226 continue;
230 // We're almost there!
232 // At this point we've rendered |current_frame_| for the proper amount
233 // of time and also have the next frame that ready for rendering.
236 // If the next frame is end of stream then we are truly at the end of the
237 // video stream.
239 // TODO(scherkus): deduplicate this end of stream check after we get rid of
240 // |current_frame_|.
241 if (ready_frames_.front()->IsEndOfStream()) {
242 state_ = kEnded;
243 host()->NotifyEnded();
244 ready_frames_.clear();
246 // No need to sleep here as we idle when |state_ != kPlaying|.
247 continue;
250 // We cannot update |current_frame_| until we've completed the pending
251 // paint. Furthermore, the pending paint might be really slow: check to
252 // see if we have any ready frames that we can drop if they've already
253 // expired.
254 if (pending_paint_) {
255 while (!ready_frames_.empty()) {
256 // Can't drop anything if we're at the end.
257 if (ready_frames_.front()->IsEndOfStream())
258 break;
260 base::TimeDelta remaining_time =
261 ready_frames_.front()->GetTimestamp() - host()->GetTime();
263 // Still a chance we can render the frame!
264 if (remaining_time.InMicroseconds() > 0)
265 break;
267 if (!drop_frames_)
268 break;
270 // Frame dropped: read again.
271 ++frames_dropped;
272 ready_frames_.pop_front();
273 AttemptRead_Locked();
275 // Continue waiting for the current paint to finish.
276 frame_available_.TimedWait(kIdleTimeDelta);
277 continue;
281 // Congratulations! You've made it past the video frame timing gauntlet.
283 // We can now safely update the current frame, request another frame, and
284 // signal to the client that a new frame is available.
285 DCHECK(!pending_paint_);
286 DCHECK(!ready_frames_.empty());
287 current_frame_ = ready_frames_.front();
288 ready_frames_.pop_front();
289 AttemptRead_Locked();
291 base::AutoUnlock auto_unlock(lock_);
292 paint_cb_.Run();
296 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) {
297 base::AutoLock auto_lock(lock_);
298 DCHECK(!pending_paint_ && !pending_paint_with_last_available_);
300 if ((!current_frame_ || current_frame_->IsEndOfStream()) &&
301 (!last_available_frame_ || last_available_frame_->IsEndOfStream())) {
302 *frame_out = NULL;
303 return;
306 // We should have initialized and have the current frame.
307 DCHECK_NE(state_, kUninitialized);
308 DCHECK_NE(state_, kStopped);
309 DCHECK_NE(state_, kError);
311 if (current_frame_) {
312 *frame_out = current_frame_;
313 last_available_frame_ = current_frame_;
314 pending_paint_ = true;
315 } else {
316 DCHECK(last_available_frame_);
317 *frame_out = last_available_frame_;
318 pending_paint_with_last_available_ = true;
322 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) {
323 base::AutoLock auto_lock(lock_);
325 // Note that we do not claim |pending_paint_| when we return NULL frame, in
326 // that case, |current_frame_| could be changed before PutCurrentFrame.
327 if (pending_paint_) {
328 DCHECK_EQ(current_frame_, frame);
329 DCHECK(!pending_paint_with_last_available_);
330 pending_paint_ = false;
331 } else if (pending_paint_with_last_available_) {
332 DCHECK_EQ(last_available_frame_, frame);
333 DCHECK(!pending_paint_);
334 pending_paint_with_last_available_ = false;
335 } else {
336 DCHECK(!frame);
339 // We had cleared the |pending_paint_| flag, there are chances that current
340 // frame is timed-out. We will wake up our main thread to advance the current
341 // frame when this is true.
342 frame_available_.Signal();
343 if (state_ == kFlushingDecoder)
344 return;
346 if (state_ == kFlushing) {
347 AttemptFlush_Locked();
348 return;
351 if (state_ == kError || state_ == kStopped) {
352 DoStopOrError_Locked();
356 VideoRendererBase::~VideoRendererBase() {
357 base::AutoLock auto_lock(lock_);
358 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
361 void VideoRendererBase::FrameReady(VideoDecoder::DecoderStatus status,
362 scoped_refptr<VideoFrame> frame) {
363 base::AutoLock auto_lock(lock_);
364 DCHECK_NE(state_, kUninitialized);
366 CHECK(pending_read_);
367 pending_read_ = false;
369 if (status != VideoDecoder::kOk) {
370 DCHECK(!frame);
371 PipelineStatus error = PIPELINE_ERROR_DECODE;
372 if (status == VideoDecoder::kDecryptError)
373 error = PIPELINE_ERROR_DECRYPT;
375 if (!seek_cb_.is_null()) {
376 base::ResetAndReturn(&seek_cb_).Run(error);
377 return;
380 host()->SetError(error);
381 return;
384 // Already-queued Decoder ReadCB's can fire after various state transitions
385 // have happened; in that case just drop those frames immediately.
386 if (state_ == kStopped || state_ == kError || state_ == kFlushed ||
387 state_ == kFlushingDecoder)
388 return;
390 if (state_ == kFlushing) {
391 AttemptFlush_Locked();
392 return;
395 if (!frame) {
396 if (state_ != kSeeking)
397 return;
399 // Abort seek early for a NULL frame because we won't get more frames.
400 // A new seek will be requested after this one completes so there is no
401 // point trying to collect more frames.
402 state_ = kPrerolled;
403 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
404 return;
407 // Discard frames until we reach our desired seek timestamp.
408 if (state_ == kSeeking && !frame->IsEndOfStream() &&
409 (frame->GetTimestamp() + frame->GetDuration()) <= seek_timestamp_) {
410 AttemptRead_Locked();
411 return;
414 // Adjust the incoming frame if its rendering stop time is past the duration
415 // of the video itself. This is typically the last frame of the video and
416 // occurs if the container specifies a duration that isn't a multiple of the
417 // frame rate. Another way for this to happen is for the container to state a
418 // smaller duration than the largest packet timestamp.
419 if (!frame->IsEndOfStream()) {
420 if (frame->GetTimestamp() > host()->GetDuration())
421 frame->SetTimestamp(host()->GetDuration());
422 if ((frame->GetTimestamp() + frame->GetDuration()) > host()->GetDuration())
423 frame->SetDuration(host()->GetDuration() - frame->GetTimestamp());
426 // This one's a keeper! Place it in the ready queue.
427 ready_frames_.push_back(frame);
428 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames);
429 if (!frame->IsEndOfStream())
430 time_cb_.Run(frame->GetTimestamp() + frame->GetDuration());
431 frame_available_.Signal();
433 PipelineStatistics statistics;
434 statistics.video_frames_decoded = 1;
435 statistics_cb_.Run(statistics);
437 // Always request more decoded video if we have capacity. This serves two
438 // purposes:
439 // 1) Prerolling while paused
440 // 2) Keeps decoding going if video rendering thread starts falling behind
441 if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) {
442 AttemptRead_Locked();
443 return;
446 // If we're at capacity or end of stream while seeking we need to transition
447 // to prerolled.
448 if (state_ == kSeeking) {
449 DCHECK(!current_frame_);
450 state_ = kPrerolled;
452 // Because we might remain in the prerolled state for an undetermined amount
453 // of time (i.e., we were not playing before we received a seek), we'll
454 // manually update the current frame and notify the subclass below.
455 if (!ready_frames_.front()->IsEndOfStream()) {
456 current_frame_ = ready_frames_.front();
457 ready_frames_.pop_front();
460 // ...and we're done seeking!
461 DCHECK(!seek_cb_.is_null());
462 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
464 base::AutoUnlock ul(lock_);
465 paint_cb_.Run();
469 void VideoRendererBase::AttemptRead_Locked() {
470 lock_.AssertAcquired();
471 DCHECK_NE(kEnded, state_);
473 if (pending_read_ ||
474 NumFrames_Locked() == limits::kMaxVideoFrames ||
475 (!ready_frames_.empty() && ready_frames_.back()->IsEndOfStream()) ||
476 state_ == kFlushingDecoder ||
477 state_ == kFlushing) {
478 return;
481 pending_read_ = true;
482 decoder_->Read(base::Bind(&VideoRendererBase::FrameReady, this));
485 void VideoRendererBase::OnDecoderFlushDone() {
486 base::AutoLock auto_lock(lock_);
487 DCHECK_EQ(kFlushingDecoder, state_);
488 DCHECK(!pending_read_);
490 state_ = kFlushing;
491 AttemptFlush_Locked();
494 void VideoRendererBase::AttemptFlush_Locked() {
495 lock_.AssertAcquired();
496 DCHECK_EQ(kFlushing, state_);
498 // Get rid of any ready frames.
499 ready_frames_.clear();
501 if (!pending_paint_ && !pending_read_) {
502 state_ = kFlushed;
503 current_frame_ = NULL;
504 base::ResetAndReturn(&flush_cb_).Run();
508 base::TimeDelta VideoRendererBase::CalculateSleepDuration(
509 const scoped_refptr<VideoFrame>& next_frame,
510 float playback_rate) {
511 // Determine the current and next presentation timestamps.
512 base::TimeDelta now = host()->GetTime();
513 base::TimeDelta this_pts = current_frame_->GetTimestamp();
514 base::TimeDelta next_pts;
515 if (!next_frame->IsEndOfStream()) {
516 next_pts = next_frame->GetTimestamp();
517 } else {
518 next_pts = this_pts + current_frame_->GetDuration();
521 // Scale our sleep based on the playback rate.
522 base::TimeDelta sleep = next_pts - now;
523 return base::TimeDelta::FromMicroseconds(
524 static_cast<int64>(sleep.InMicroseconds() / playback_rate));
527 void VideoRendererBase::DoStopOrError_Locked() {
528 DCHECK(!pending_paint_);
529 DCHECK(!pending_paint_with_last_available_);
530 lock_.AssertAcquired();
531 current_frame_ = NULL;
532 last_available_frame_ = NULL;
533 ready_frames_.clear();
536 int VideoRendererBase::NumFrames_Locked() const {
537 lock_.AssertAcquired();
538 int outstanding_frames =
539 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) +
540 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0);
541 return ready_frames_.size() + outstanding_frames;
544 } // namespace media