Revert of Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320) (patchset...
[chromium-blink-merge.git] / media / renderers / video_renderer_impl.cc
blob627ada64a13ea9a148a0bbcf4c2b394e44b8f3fb
1 // Copyright 2013 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 "media/renderers/video_renderer_impl.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/location.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/threading/platform_thread.h"
13 #include "base/time/default_tick_clock.h"
14 #include "base/trace_event/trace_event.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/buffers.h"
17 #include "media/base/limits.h"
18 #include "media/base/pipeline.h"
19 #include "media/base/video_frame.h"
21 namespace media {
23 VideoRendererImpl::VideoRendererImpl(
24 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
25 ScopedVector<VideoDecoder> decoders,
26 bool drop_frames,
27 const scoped_refptr<MediaLog>& media_log)
28 : task_runner_(task_runner),
29 video_frame_stream_(
30 new VideoFrameStream(task_runner, decoders.Pass(), media_log)),
31 low_delay_(false),
32 received_end_of_stream_(false),
33 rendered_end_of_stream_(false),
34 frame_available_(&lock_),
35 state_(kUninitialized),
36 thread_(),
37 pending_read_(false),
38 drop_frames_(drop_frames),
39 buffering_state_(BUFFERING_HAVE_NOTHING),
40 frames_decoded_(0),
41 frames_dropped_(0),
42 is_shutting_down_(false),
43 tick_clock_(new base::DefaultTickClock()),
44 weak_factory_(this) {
47 VideoRendererImpl::~VideoRendererImpl() {
48 DCHECK(task_runner_->BelongsToCurrentThread());
51 base::AutoLock auto_lock(lock_);
52 is_shutting_down_ = true;
53 frame_available_.Signal();
56 if (!thread_.is_null())
57 base::PlatformThread::Join(thread_);
59 if (!init_cb_.is_null())
60 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
62 if (!flush_cb_.is_null())
63 base::ResetAndReturn(&flush_cb_).Run();
66 void VideoRendererImpl::Flush(const base::Closure& callback) {
67 DVLOG(1) << __FUNCTION__;
68 DCHECK(task_runner_->BelongsToCurrentThread());
69 base::AutoLock auto_lock(lock_);
70 DCHECK_EQ(state_, kPlaying);
71 flush_cb_ = callback;
72 state_ = kFlushing;
74 // This is necessary if the |video_frame_stream_| has already seen an end of
75 // stream and needs to drain it before flushing it.
76 ready_frames_.clear();
77 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
78 buffering_state_ = BUFFERING_HAVE_NOTHING;
79 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
81 received_end_of_stream_ = false;
82 rendered_end_of_stream_ = false;
84 video_frame_stream_->Reset(
85 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone,
86 weak_factory_.GetWeakPtr()));
89 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
90 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")";
91 DCHECK(task_runner_->BelongsToCurrentThread());
92 base::AutoLock auto_lock(lock_);
93 DCHECK_EQ(state_, kFlushed);
94 DCHECK(!pending_read_);
95 DCHECK(ready_frames_.empty());
96 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
98 state_ = kPlaying;
99 start_timestamp_ = timestamp;
100 AttemptRead_Locked();
103 void VideoRendererImpl::Initialize(
104 DemuxerStream* stream,
105 const PipelineStatusCB& init_cb,
106 const SetDecryptorReadyCB& set_decryptor_ready_cb,
107 const StatisticsCB& statistics_cb,
108 const BufferingStateCB& buffering_state_cb,
109 const PaintCB& paint_cb,
110 const base::Closure& ended_cb,
111 const PipelineStatusCB& error_cb,
112 const WallClockTimeCB& wall_clock_time_cb,
113 const base::Closure& waiting_for_decryption_key_cb) {
114 DCHECK(task_runner_->BelongsToCurrentThread());
115 base::AutoLock auto_lock(lock_);
116 DCHECK(stream);
117 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
118 DCHECK(!init_cb.is_null());
119 DCHECK(!statistics_cb.is_null());
120 DCHECK(!buffering_state_cb.is_null());
121 DCHECK(!paint_cb.is_null());
122 DCHECK(!ended_cb.is_null());
123 DCHECK(!wall_clock_time_cb.is_null());
124 DCHECK_EQ(kUninitialized, state_);
126 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE);
128 // Always post |init_cb_| because |this| could be destroyed if initialization
129 // failed.
130 init_cb_ = BindToCurrentLoop(init_cb);
132 statistics_cb_ = statistics_cb;
133 buffering_state_cb_ = buffering_state_cb;
134 paint_cb_ = paint_cb,
135 ended_cb_ = ended_cb;
136 error_cb_ = error_cb;
137 wall_clock_time_cb_ = wall_clock_time_cb;
138 state_ = kInitializing;
140 video_frame_stream_->Initialize(
141 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
142 weak_factory_.GetWeakPtr()),
143 set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
146 void VideoRendererImpl::CreateVideoThread() {
147 // This may fail and cause a crash if there are too many threads created in
148 // the current process. See http://crbug.com/443291
149 CHECK(base::PlatformThread::Create(0, this, &thread_));
151 #if defined(OS_WIN)
152 // Bump up our priority so our sleeping is more accurate.
153 // TODO(scherkus): find out if this is necessary, but it seems to help.
154 ::SetThreadPriority(thread_.platform_handle(), THREAD_PRIORITY_ABOVE_NORMAL);
155 #endif // defined(OS_WIN)
158 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
159 DCHECK(task_runner_->BelongsToCurrentThread());
160 base::AutoLock auto_lock(lock_);
161 DCHECK_EQ(state_, kInitializing);
163 if (!success) {
164 state_ = kUninitialized;
165 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
166 return;
169 // We're all good! Consider ourselves flushed. (ThreadMain() should never
170 // see us in the kUninitialized state).
171 // Since we had an initial Preroll(), we consider ourself flushed, because we
172 // have not populated any buffers yet.
173 state_ = kFlushed;
175 CreateVideoThread();
177 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
180 // PlatformThread::Delegate implementation.
181 void VideoRendererImpl::ThreadMain() {
182 base::PlatformThread::SetName("CrVideoRenderer");
184 // The number of milliseconds to idle when we do not have anything to do.
185 // Nothing special about the value, other than we're being more OS-friendly
186 // than sleeping for 1 millisecond.
188 // TODO(scherkus): switch to pure event-driven frame timing instead of this
189 // kIdleTimeDelta business http://crbug.com/106874
190 const base::TimeDelta kIdleTimeDelta =
191 base::TimeDelta::FromMilliseconds(10);
193 for (;;) {
194 base::AutoLock auto_lock(lock_);
196 // Thread exit condition.
197 if (is_shutting_down_)
198 return;
200 // Remain idle as long as we're not playing.
201 if (state_ != kPlaying || buffering_state_ != BUFFERING_HAVE_ENOUGH) {
202 UpdateStatsAndWait_Locked(kIdleTimeDelta);
203 continue;
206 base::TimeTicks now = tick_clock_->NowTicks();
208 // Remain idle until we have the next frame ready for rendering.
209 if (ready_frames_.empty()) {
210 base::TimeDelta wait_time = kIdleTimeDelta;
211 if (received_end_of_stream_) {
212 if (!rendered_end_of_stream_) {
213 rendered_end_of_stream_ = true;
214 task_runner_->PostTask(FROM_HERE, ended_cb_);
216 } else if (now >= latest_possible_paint_time_) {
217 // Declare HAVE_NOTHING if we don't have another frame by the time we
218 // are ready to paint the next one.
219 buffering_state_ = BUFFERING_HAVE_NOTHING;
220 task_runner_->PostTask(
221 FROM_HERE, base::Bind(buffering_state_cb_, BUFFERING_HAVE_NOTHING));
222 } else {
223 wait_time = std::min(kIdleTimeDelta, latest_possible_paint_time_ - now);
226 UpdateStatsAndWait_Locked(wait_time);
227 continue;
230 base::TimeTicks target_paint_time =
231 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp());
233 // If media time has stopped, don't attempt to paint any more frames.
234 if (target_paint_time.is_null()) {
235 UpdateStatsAndWait_Locked(kIdleTimeDelta);
236 continue;
239 // Deadline is defined as the duration between this frame and the next
240 // frame, using the delta between this frame and the previous frame as the
241 // assumption for frame duration.
243 // TODO(scherkus): This can be vastly improved. Use a histogram to measure
244 // the accuracy of our frame timing code. http://crbug.com/149829
245 if (last_media_time_.is_null()) {
246 latest_possible_paint_time_ = now;
247 } else {
248 base::TimeDelta duration = target_paint_time - last_media_time_;
249 latest_possible_paint_time_ = target_paint_time + duration;
252 // Remain idle until we've reached our target paint window.
253 if (now < target_paint_time) {
254 UpdateStatsAndWait_Locked(
255 std::min(target_paint_time - now, kIdleTimeDelta));
256 continue;
259 if (ready_frames_.size() > 1 && now > latest_possible_paint_time_ &&
260 drop_frames_) {
261 DropNextReadyFrame_Locked();
262 continue;
265 // Congratulations! You've made it past the video frame timing gauntlet.
267 // At this point enough time has passed that the next frame that ready for
268 // rendering.
269 PaintNextReadyFrame_Locked();
273 void VideoRendererImpl::SetTickClockForTesting(
274 scoped_ptr<base::TickClock> tick_clock) {
275 tick_clock_.swap(tick_clock);
278 void VideoRendererImpl::OnTimeStateChanged(bool time_progressing) {
279 // TODO(dalecurtis): Wire up to the VideoRendererSink once it's implemented.
282 void VideoRendererImpl::PaintNextReadyFrame_Locked() {
283 lock_.AssertAcquired();
285 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
286 ready_frames_.pop_front();
287 frames_decoded_++;
289 last_media_time_ = wall_clock_time_cb_.Run(next_frame->timestamp());
291 paint_cb_.Run(next_frame);
293 task_runner_->PostTask(
294 FROM_HERE,
295 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
298 void VideoRendererImpl::DropNextReadyFrame_Locked() {
299 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
301 lock_.AssertAcquired();
303 last_media_time_ =
304 wall_clock_time_cb_.Run(ready_frames_.front()->timestamp());
306 ready_frames_.pop_front();
307 frames_decoded_++;
308 frames_dropped_++;
310 task_runner_->PostTask(
311 FROM_HERE,
312 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
315 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
316 const scoped_refptr<VideoFrame>& frame) {
317 DCHECK(task_runner_->BelongsToCurrentThread());
318 base::AutoLock auto_lock(lock_);
319 DCHECK_NE(state_, kUninitialized);
320 DCHECK_NE(state_, kFlushed);
322 CHECK(pending_read_);
323 pending_read_ = false;
325 if (status == VideoFrameStream::DECODE_ERROR ||
326 status == VideoFrameStream::DECRYPT_ERROR) {
327 DCHECK(!frame.get());
328 PipelineStatus error = PIPELINE_ERROR_DECODE;
329 if (status == VideoFrameStream::DECRYPT_ERROR)
330 error = PIPELINE_ERROR_DECRYPT;
331 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
332 return;
335 // Already-queued VideoFrameStream ReadCB's can fire after various state
336 // transitions have happened; in that case just drop those frames immediately.
337 if (state_ == kFlushing)
338 return;
340 DCHECK_EQ(state_, kPlaying);
342 // Can happen when demuxers are preparing for a new Seek().
343 if (!frame.get()) {
344 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
345 return;
348 if (frame->end_of_stream()) {
349 DCHECK(!received_end_of_stream_);
350 received_end_of_stream_ = true;
351 } else {
352 // Maintain the latest frame decoded so the correct frame is displayed after
353 // prerolling has completed.
354 if (frame->timestamp() <= start_timestamp_)
355 ready_frames_.clear();
356 AddReadyFrame_Locked(frame);
359 // Signal buffering state if we've met our conditions for having enough data.
360 if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked())
361 TransitionToHaveEnough_Locked();
363 // Always request more decoded video if we have capacity. This serves two
364 // purposes:
365 // 1) Prerolling while paused
366 // 2) Keeps decoding going if video rendering thread starts falling behind
367 AttemptRead_Locked();
370 bool VideoRendererImpl::HaveEnoughData_Locked() {
371 DCHECK_EQ(state_, kPlaying);
372 return received_end_of_stream_ ||
373 !video_frame_stream_->CanReadWithoutStalling() ||
374 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) ||
375 (low_delay_ && ready_frames_.size() > 0);
378 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
379 DCHECK(task_runner_->BelongsToCurrentThread());
380 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
382 if (!ready_frames_.empty()) {
383 // Because the clock might remain paused in for an undetermined amount
384 // of time (e.g., seeking while paused), paint the first frame.
385 PaintNextReadyFrame_Locked();
388 buffering_state_ = BUFFERING_HAVE_ENOUGH;
389 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
392 void VideoRendererImpl::AddReadyFrame_Locked(
393 const scoped_refptr<VideoFrame>& frame) {
394 DCHECK(task_runner_->BelongsToCurrentThread());
395 lock_.AssertAcquired();
396 DCHECK(!frame->end_of_stream());
398 ready_frames_.push_back(frame);
399 DCHECK_LE(ready_frames_.size(),
400 static_cast<size_t>(limits::kMaxVideoFrames));
402 // Avoid needlessly waking up |thread_| unless playing.
403 if (state_ == kPlaying)
404 frame_available_.Signal();
407 void VideoRendererImpl::AttemptRead() {
408 base::AutoLock auto_lock(lock_);
409 AttemptRead_Locked();
412 void VideoRendererImpl::AttemptRead_Locked() {
413 DCHECK(task_runner_->BelongsToCurrentThread());
414 lock_.AssertAcquired();
416 if (pending_read_ || received_end_of_stream_ ||
417 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) {
418 return;
421 switch (state_) {
422 case kPlaying:
423 pending_read_ = true;
424 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
425 weak_factory_.GetWeakPtr()));
426 return;
428 case kUninitialized:
429 case kInitializing:
430 case kFlushing:
431 case kFlushed:
432 return;
436 void VideoRendererImpl::OnVideoFrameStreamResetDone() {
437 base::AutoLock auto_lock(lock_);
438 DCHECK_EQ(kFlushing, state_);
439 DCHECK(!pending_read_);
440 DCHECK(ready_frames_.empty());
441 DCHECK(!received_end_of_stream_);
442 DCHECK(!rendered_end_of_stream_);
443 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
445 state_ = kFlushed;
446 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks();
447 base::ResetAndReturn(&flush_cb_).Run();
450 void VideoRendererImpl::UpdateStatsAndWait_Locked(
451 base::TimeDelta wait_duration) {
452 lock_.AssertAcquired();
453 DCHECK_GE(frames_decoded_, 0);
454 DCHECK_LE(frames_dropped_, frames_decoded_);
456 if (frames_decoded_) {
457 PipelineStatistics statistics;
458 statistics.video_frames_decoded = frames_decoded_;
459 statistics.video_frames_dropped = frames_dropped_;
460 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics));
462 frames_decoded_ = 0;
463 frames_dropped_ = 0;
466 frame_available_.TimedWait(wait_duration);
469 } // namespace media