Revert of Set defaultPageScaleLimits before setIgnoreViewportTagScaleLimits (patchset...
[chromium-blink-merge.git] / media / filters / video_renderer_impl.cc
blob482d54e844632093692c93b6d828fd74fb6a050c
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/filters/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/trace_event/trace_event.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/buffers.h"
16 #include "media/base/limits.h"
17 #include "media/base/pipeline.h"
18 #include "media/base/video_frame.h"
20 namespace media {
22 VideoRendererImpl::VideoRendererImpl(
23 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
24 ScopedVector<VideoDecoder> decoders,
25 bool drop_frames,
26 const scoped_refptr<MediaLog>& media_log)
27 : task_runner_(task_runner),
28 video_frame_stream_(
29 new VideoFrameStream(task_runner, decoders.Pass(), media_log)),
30 low_delay_(false),
31 received_end_of_stream_(false),
32 rendered_end_of_stream_(false),
33 frame_available_(&lock_),
34 state_(kUninitialized),
35 thread_(),
36 pending_read_(false),
37 drop_frames_(drop_frames),
38 buffering_state_(BUFFERING_HAVE_NOTHING),
39 last_timestamp_(kNoTimestamp()),
40 last_painted_timestamp_(kNoTimestamp()),
41 frames_decoded_(0),
42 frames_dropped_(0),
43 is_shutting_down_(false),
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 TimeDeltaCB& get_time_cb) {
113 DCHECK(task_runner_->BelongsToCurrentThread());
114 base::AutoLock auto_lock(lock_);
115 DCHECK(stream);
116 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
117 DCHECK(!init_cb.is_null());
118 DCHECK(!statistics_cb.is_null());
119 DCHECK(!buffering_state_cb.is_null());
120 DCHECK(!paint_cb.is_null());
121 DCHECK(!ended_cb.is_null());
122 DCHECK(!get_time_cb.is_null());
123 DCHECK_EQ(kUninitialized, state_);
125 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE);
127 // Always post |init_cb_| because |this| could be destroyed if initialization
128 // failed.
129 init_cb_ = BindToCurrentLoop(init_cb);
131 statistics_cb_ = statistics_cb;
132 buffering_state_cb_ = buffering_state_cb;
133 paint_cb_ = paint_cb,
134 ended_cb_ = ended_cb;
135 error_cb_ = error_cb;
136 get_time_cb_ = get_time_cb;
137 state_ = kInitializing;
139 video_frame_stream_->Initialize(
140 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
141 weak_factory_.GetWeakPtr()),
142 set_decryptor_ready_cb, statistics_cb);
145 void VideoRendererImpl::CreateVideoThread() {
146 // This may fail and cause a crash if there are too many threads created in
147 // the current process. See http://crbug.com/443291
148 CHECK(base::PlatformThread::Create(0, this, &thread_));
150 #if defined(OS_WIN)
151 // Bump up our priority so our sleeping is more accurate.
152 // TODO(scherkus): find out if this is necessary, but it seems to help.
153 ::SetThreadPriority(thread_.platform_handle(), THREAD_PRIORITY_ABOVE_NORMAL);
154 #endif // defined(OS_WIN)
157 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
158 DCHECK(task_runner_->BelongsToCurrentThread());
159 base::AutoLock auto_lock(lock_);
160 DCHECK_EQ(state_, kInitializing);
162 if (!success) {
163 state_ = kUninitialized;
164 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
165 return;
168 // We're all good! Consider ourselves flushed. (ThreadMain() should never
169 // see us in the kUninitialized state).
170 // Since we had an initial Preroll(), we consider ourself flushed, because we
171 // have not populated any buffers yet.
172 state_ = kFlushed;
174 CreateVideoThread();
176 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
179 // PlatformThread::Delegate implementation.
180 void VideoRendererImpl::ThreadMain() {
181 base::PlatformThread::SetName("CrVideoRenderer");
183 // The number of milliseconds to idle when we do not have anything to do.
184 // Nothing special about the value, other than we're being more OS-friendly
185 // than sleeping for 1 millisecond.
187 // TODO(scherkus): switch to pure event-driven frame timing instead of this
188 // kIdleTimeDelta business http://crbug.com/106874
189 const base::TimeDelta kIdleTimeDelta =
190 base::TimeDelta::FromMilliseconds(10);
192 // If we have no frames and haven't painted any frame for certain amount of
193 // time, declare BUFFERING_HAVE_NOTHING.
194 const base::TimeDelta kTimeToDeclareHaveNothing =
195 base::TimeDelta::FromSeconds(3);
197 for (;;) {
198 base::AutoLock auto_lock(lock_);
200 // Thread exit condition.
201 if (is_shutting_down_)
202 return;
204 // Remain idle as long as we're not playing.
205 if (state_ != kPlaying || buffering_state_ != BUFFERING_HAVE_ENOUGH) {
206 UpdateStatsAndWait_Locked(kIdleTimeDelta);
207 continue;
210 base::TimeDelta now = get_time_cb_.Run();
212 // Remain idle until we have the next frame ready for rendering.
213 if (ready_frames_.empty()) {
214 if (received_end_of_stream_) {
215 if (!rendered_end_of_stream_) {
216 rendered_end_of_stream_ = true;
217 task_runner_->PostTask(FROM_HERE, ended_cb_);
219 } else if (last_painted_timestamp_ != kNoTimestamp() &&
220 now - last_painted_timestamp_ >= kTimeToDeclareHaveNothing) {
221 buffering_state_ = BUFFERING_HAVE_NOTHING;
222 task_runner_->PostTask(
223 FROM_HERE, base::Bind(buffering_state_cb_, BUFFERING_HAVE_NOTHING));
226 UpdateStatsAndWait_Locked(kIdleTimeDelta);
227 continue;
230 base::TimeDelta target_paint_timestamp = ready_frames_.front()->timestamp();
231 base::TimeDelta latest_paint_timestamp;
233 // Deadline is defined as the duration between this frame and the next
234 // frame, using the delta between this frame and the previous frame as the
235 // assumption for frame duration.
237 // TODO(scherkus): This can be vastly improved. Use a histogram to measure
238 // the accuracy of our frame timing code. http://crbug.com/149829
239 if (last_timestamp_ == kNoTimestamp()) {
240 latest_paint_timestamp = base::TimeDelta::Max();
241 } else {
242 base::TimeDelta duration = target_paint_timestamp - last_timestamp_;
243 latest_paint_timestamp = target_paint_timestamp + duration;
246 // Remain idle until we've reached our target paint window.
247 if (now < target_paint_timestamp) {
248 UpdateStatsAndWait_Locked(kIdleTimeDelta);
249 continue;
252 if (now > latest_paint_timestamp && drop_frames_) {
253 DropNextReadyFrame_Locked();
254 continue;
257 // Congratulations! You've made it past the video frame timing gauntlet.
259 // At this point enough time has passed that the next frame that ready for
260 // rendering.
261 PaintNextReadyFrame_Locked();
265 void VideoRendererImpl::PaintNextReadyFrame_Locked() {
266 lock_.AssertAcquired();
268 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
269 ready_frames_.pop_front();
270 frames_decoded_++;
272 last_timestamp_ = next_frame->timestamp();
273 last_painted_timestamp_ = next_frame->timestamp();
275 paint_cb_.Run(next_frame);
277 task_runner_->PostTask(
278 FROM_HERE,
279 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
282 void VideoRendererImpl::DropNextReadyFrame_Locked() {
283 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
285 lock_.AssertAcquired();
287 last_timestamp_ = ready_frames_.front()->timestamp();
288 ready_frames_.pop_front();
289 frames_decoded_++;
290 frames_dropped_++;
292 task_runner_->PostTask(
293 FROM_HERE,
294 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
297 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status,
298 const scoped_refptr<VideoFrame>& frame) {
299 DCHECK(task_runner_->BelongsToCurrentThread());
300 base::AutoLock auto_lock(lock_);
301 DCHECK_NE(state_, kUninitialized);
302 DCHECK_NE(state_, kFlushed);
304 CHECK(pending_read_);
305 pending_read_ = false;
307 if (status == VideoFrameStream::DECODE_ERROR ||
308 status == VideoFrameStream::DECRYPT_ERROR) {
309 DCHECK(!frame.get());
310 PipelineStatus error = PIPELINE_ERROR_DECODE;
311 if (status == VideoFrameStream::DECRYPT_ERROR)
312 error = PIPELINE_ERROR_DECRYPT;
313 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
314 return;
317 // Already-queued VideoFrameStream ReadCB's can fire after various state
318 // transitions have happened; in that case just drop those frames immediately.
319 if (state_ == kFlushing)
320 return;
322 DCHECK_EQ(state_, kPlaying);
324 // Can happen when demuxers are preparing for a new Seek().
325 if (!frame.get()) {
326 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
327 return;
330 if (frame->end_of_stream()) {
331 DCHECK(!received_end_of_stream_);
332 received_end_of_stream_ = true;
333 } else {
334 // Maintain the latest frame decoded so the correct frame is displayed after
335 // prerolling has completed.
336 if (frame->timestamp() <= start_timestamp_)
337 ready_frames_.clear();
338 AddReadyFrame_Locked(frame);
341 // Signal buffering state if we've met our conditions for having enough data.
342 if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked())
343 TransitionToHaveEnough_Locked();
345 // Always request more decoded video if we have capacity. This serves two
346 // purposes:
347 // 1) Prerolling while paused
348 // 2) Keeps decoding going if video rendering thread starts falling behind
349 AttemptRead_Locked();
352 bool VideoRendererImpl::HaveEnoughData_Locked() {
353 DCHECK_EQ(state_, kPlaying);
354 return received_end_of_stream_ ||
355 !video_frame_stream_->CanReadWithoutStalling() ||
356 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) ||
357 (low_delay_ && ready_frames_.size() > 0);
360 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
361 DCHECK(task_runner_->BelongsToCurrentThread());
362 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
364 if (!ready_frames_.empty()) {
365 // Because the clock might remain paused in for an undetermined amount
366 // of time (e.g., seeking while paused), paint the first frame.
367 PaintNextReadyFrame_Locked();
370 buffering_state_ = BUFFERING_HAVE_ENOUGH;
371 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
374 void VideoRendererImpl::AddReadyFrame_Locked(
375 const scoped_refptr<VideoFrame>& frame) {
376 DCHECK(task_runner_->BelongsToCurrentThread());
377 lock_.AssertAcquired();
378 DCHECK(!frame->end_of_stream());
380 ready_frames_.push_back(frame);
381 DCHECK_LE(ready_frames_.size(),
382 static_cast<size_t>(limits::kMaxVideoFrames));
384 // Avoid needlessly waking up |thread_| unless playing.
385 if (state_ == kPlaying)
386 frame_available_.Signal();
389 void VideoRendererImpl::AttemptRead() {
390 base::AutoLock auto_lock(lock_);
391 AttemptRead_Locked();
394 void VideoRendererImpl::AttemptRead_Locked() {
395 DCHECK(task_runner_->BelongsToCurrentThread());
396 lock_.AssertAcquired();
398 if (pending_read_ || received_end_of_stream_ ||
399 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) {
400 return;
403 switch (state_) {
404 case kPlaying:
405 pending_read_ = true;
406 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
407 weak_factory_.GetWeakPtr()));
408 return;
410 case kUninitialized:
411 case kInitializing:
412 case kFlushing:
413 case kFlushed:
414 return;
418 void VideoRendererImpl::OnVideoFrameStreamResetDone() {
419 base::AutoLock auto_lock(lock_);
420 DCHECK_EQ(kFlushing, state_);
421 DCHECK(!pending_read_);
422 DCHECK(ready_frames_.empty());
423 DCHECK(!received_end_of_stream_);
424 DCHECK(!rendered_end_of_stream_);
425 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
427 state_ = kFlushed;
428 last_timestamp_ = kNoTimestamp();
429 last_painted_timestamp_ = kNoTimestamp();
430 base::ResetAndReturn(&flush_cb_).Run();
433 void VideoRendererImpl::UpdateStatsAndWait_Locked(
434 base::TimeDelta wait_duration) {
435 lock_.AssertAcquired();
436 DCHECK_GE(frames_decoded_, 0);
437 DCHECK_LE(frames_dropped_, frames_decoded_);
439 if (frames_decoded_) {
440 PipelineStatistics statistics;
441 statistics.video_frames_decoded = frames_decoded_;
442 statistics.video_frames_dropped = frames_dropped_;
443 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics));
445 frames_decoded_ = 0;
446 frames_dropped_ = 0;
449 frame_available_.TimedWait(wait_duration);
452 } // namespace media