Permission messages: Add a bunch of missing combinations/suppressions.
[chromium-blink-merge.git] / media / renderers / video_renderer_impl.cc
blob4eeb1b95d255558d4ea63072cbd4280236a785bc
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/command_line.h"
11 #include "base/location.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/time/default_tick_clock.h"
17 #include "base/trace_event/trace_event.h"
18 #include "media/base/bind_to_current_loop.h"
19 #include "media/base/buffers.h"
20 #include "media/base/limits.h"
21 #include "media/base/media_log.h"
22 #include "media/base/media_switches.h"
23 #include "media/base/pipeline.h"
24 #include "media/base/video_frame.h"
25 #include "media/renderers/gpu_video_accelerator_factories.h"
26 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
28 namespace media {
30 // TODO(dalecurtis): This experiment is temporary and should be removed once we
31 // have enough data to support the primacy of the new video rendering path; see
32 // http://crbug.com/485699 for details.
33 static bool ShouldUseVideoRenderingPath() {
34 // Note: It's important to query the field trial state first, to ensure that
35 // UMA reports the correct group.
36 const std::string group_name =
37 base::FieldTrialList::FindFullName("NewVideoRendererTrial");
38 const bool disabled_via_cli =
39 base::CommandLine::ForCurrentProcess()->HasSwitch(
40 switches::kDisableNewVideoRenderer);
41 return !disabled_via_cli &&
42 !base::StartsWith(group_name, "Disabled",
43 base::CompareCase::SENSITIVE);
46 VideoRendererImpl::VideoRendererImpl(
47 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
48 const scoped_refptr<base::TaskRunner>& worker_task_runner,
49 VideoRendererSink* sink,
50 ScopedVector<VideoDecoder> decoders,
51 bool drop_frames,
52 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories,
53 const scoped_refptr<MediaLog>& media_log)
54 : task_runner_(media_task_runner),
55 use_new_video_renderering_path_(ShouldUseVideoRenderingPath()),
56 sink_(sink),
57 sink_started_(false),
58 video_frame_stream_(
59 new VideoFrameStream(media_task_runner, decoders.Pass(), media_log)),
60 gpu_memory_buffer_pool_(nullptr),
61 media_log_(media_log),
62 low_delay_(false),
63 received_end_of_stream_(false),
64 rendered_end_of_stream_(false),
65 frame_available_(&lock_),
66 state_(kUninitialized),
67 sequence_token_(0),
68 thread_(),
69 pending_read_(false),
70 drop_frames_(drop_frames),
71 buffering_state_(BUFFERING_HAVE_NOTHING),
72 frames_decoded_(0),
73 frames_dropped_(0),
74 is_shutting_down_(false),
75 tick_clock_(new base::DefaultTickClock()),
76 was_background_rendering_(false),
77 time_progressing_(false),
78 render_first_frame_and_stop_(false),
79 posted_maybe_stop_after_first_paint_(false),
80 weak_factory_(this) {
81 if (gpu_factories &&
82 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames()) {
83 gpu_memory_buffer_pool_.reset(new GpuMemoryBufferVideoFramePool(
84 media_task_runner, worker_task_runner, gpu_factories));
88 VideoRendererImpl::~VideoRendererImpl() {
89 DCHECK(task_runner_->BelongsToCurrentThread());
91 if (!use_new_video_renderering_path_) {
92 base::AutoLock auto_lock(lock_);
93 is_shutting_down_ = true;
94 frame_available_.Signal();
97 if (!thread_.is_null())
98 base::PlatformThread::Join(thread_);
100 if (!init_cb_.is_null())
101 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
103 if (!flush_cb_.is_null())
104 base::ResetAndReturn(&flush_cb_).Run();
106 if (use_new_video_renderering_path_ && sink_started_)
107 StopSink();
110 void VideoRendererImpl::Flush(const base::Closure& callback) {
111 DVLOG(1) << __FUNCTION__;
112 DCHECK(task_runner_->BelongsToCurrentThread());
114 if (use_new_video_renderering_path_ && sink_started_)
115 StopSink();
117 base::AutoLock auto_lock(lock_);
118 DCHECK_EQ(state_, kPlaying);
119 flush_cb_ = callback;
120 state_ = kFlushing;
122 // This is necessary if the |video_frame_stream_| has already seen an end of
123 // stream and needs to drain it before flushing it.
124 ready_frames_.clear();
125 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
126 buffering_state_ = BUFFERING_HAVE_NOTHING;
127 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
129 received_end_of_stream_ = false;
130 rendered_end_of_stream_ = false;
132 if (use_new_video_renderering_path_)
133 algorithm_->Reset();
135 video_frame_stream_->Reset(
136 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone,
137 weak_factory_.GetWeakPtr()));
140 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
141 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")";
142 DCHECK(task_runner_->BelongsToCurrentThread());
143 base::AutoLock auto_lock(lock_);
144 DCHECK_EQ(state_, kFlushed);
145 DCHECK(!pending_read_);
146 DCHECK(ready_frames_.empty());
147 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
149 state_ = kPlaying;
150 start_timestamp_ = timestamp;
151 AttemptRead_Locked();
154 void VideoRendererImpl::Initialize(
155 DemuxerStream* stream,
156 const PipelineStatusCB& init_cb,
157 const SetDecryptorReadyCB& set_decryptor_ready_cb,
158 const StatisticsCB& statistics_cb,
159 const BufferingStateCB& buffering_state_cb,
160 const base::Closure& ended_cb,
161 const PipelineStatusCB& error_cb,
162 const TimeSource::WallClockTimeCB& wall_clock_time_cb,
163 const base::Closure& waiting_for_decryption_key_cb) {
164 DCHECK(task_runner_->BelongsToCurrentThread());
165 base::AutoLock auto_lock(lock_);
166 DCHECK(stream);
167 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
168 DCHECK(!init_cb.is_null());
169 DCHECK(!statistics_cb.is_null());
170 DCHECK(!buffering_state_cb.is_null());
171 DCHECK(!ended_cb.is_null());
172 DCHECK(!wall_clock_time_cb.is_null());
173 DCHECK_EQ(kUninitialized, state_);
174 DCHECK(!render_first_frame_and_stop_);
175 DCHECK(!posted_maybe_stop_after_first_paint_);
176 DCHECK(!was_background_rendering_);
177 DCHECK(!time_progressing_);
179 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE);
180 UMA_HISTOGRAM_BOOLEAN("Media.VideoRenderer.LowDelay", low_delay_);
181 if (low_delay_)
182 MEDIA_LOG(DEBUG, media_log_) << "Video rendering in low delay mode.";
184 // Always post |init_cb_| because |this| could be destroyed if initialization
185 // failed.
186 init_cb_ = BindToCurrentLoop(init_cb);
188 // Always post |buffering_state_cb_| because it may otherwise invoke reentrant
189 // calls to OnTimeStateChanged() under lock, which can deadlock the compositor
190 // and media threads.
191 buffering_state_cb_ = BindToCurrentLoop(buffering_state_cb);
193 statistics_cb_ = statistics_cb;
194 paint_cb_ = base::Bind(&VideoRendererSink::PaintFrameUsingOldRenderingPath,
195 base::Unretained(sink_));
196 ended_cb_ = ended_cb;
197 error_cb_ = error_cb;
198 wall_clock_time_cb_ = wall_clock_time_cb;
199 state_ = kInitializing;
201 video_frame_stream_->Initialize(
202 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
203 weak_factory_.GetWeakPtr()),
204 set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
207 scoped_refptr<VideoFrame> VideoRendererImpl::Render(
208 base::TimeTicks deadline_min,
209 base::TimeTicks deadline_max,
210 bool background_rendering) {
211 base::AutoLock auto_lock(lock_);
212 DCHECK(use_new_video_renderering_path_);
213 DCHECK_EQ(state_, kPlaying);
215 size_t frames_dropped = 0;
216 scoped_refptr<VideoFrame> result =
217 algorithm_->Render(deadline_min, deadline_max, &frames_dropped);
219 // Due to how the |algorithm_| holds frames, this should never be null if
220 // we've had a proper startup sequence.
221 DCHECK(result);
223 // Declare HAVE_NOTHING if we reach a state where we can't progress playback
224 // any further. We don't want to do this if we've already done so, reached
225 // end of stream, or have frames available. We also don't want to do this in
226 // background rendering mode unless this isn't the first background render
227 // tick and we haven't seen any decoded frames since the last one.
229 // We use the inverse of |render_first_frame_and_stop_| as a proxy for the
230 // value of |time_progressing_| here since we can't access it from the
231 // compositor thread. If we're here (in Render()) the sink must have been
232 // started -- but if it was started only to render the first frame and stop,
233 // then |time_progressing_| is likely false. If we're still in Render() when
234 // |render_first_frame_and_stop_| is false, then |time_progressing_| is true.
235 // If |time_progressing_| is actually true when |render_first_frame_and_stop_|
236 // is also true, then the ended callback will be harmlessly delayed until
237 // MaybeStopSinkAfterFirstPaint() runs and the next Render() call comes in.
238 const size_t effective_frames =
239 MaybeFireEndedCallback_Locked(!render_first_frame_and_stop_);
240 if (buffering_state_ == BUFFERING_HAVE_ENOUGH && !received_end_of_stream_ &&
241 !effective_frames && (!background_rendering ||
242 (!frames_decoded_ && was_background_rendering_))) {
243 // Do not set |buffering_state_| here as the lock in FrameReady() may be
244 // held already and it fire the state changes in the wrong order.
245 task_runner_->PostTask(
246 FROM_HERE, base::Bind(&VideoRendererImpl::TransitionToHaveNothing,
247 weak_factory_.GetWeakPtr()));
250 // We don't count dropped frames in the background to avoid skewing the count
251 // and impacting JavaScript visible metrics used by web developers.
253 // Just after resuming from background rendering, we also don't count the
254 // dropped frames since they are likely just dropped due to being too old.
255 if (!background_rendering && !was_background_rendering_)
256 frames_dropped_ += frames_dropped;
257 UpdateStatsAndWait_Locked(base::TimeDelta());
258 was_background_rendering_ = background_rendering;
260 // After painting the first frame, if playback hasn't started, we post a
261 // delayed task to request that the sink be stopped. The task is delayed to
262 // give videos with autoplay time to start.
264 // OnTimeStateChanged() will clear this flag if time starts before we get here
265 // and MaybeStopSinkAfterFirstPaint() will ignore this request if time starts
266 // before the call executes.
267 if (render_first_frame_and_stop_ && !posted_maybe_stop_after_first_paint_) {
268 posted_maybe_stop_after_first_paint_ = true;
269 task_runner_->PostDelayedTask(
270 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
271 weak_factory_.GetWeakPtr()),
272 base::TimeDelta::FromMilliseconds(250));
275 // Always post this task, it will acquire new frames if necessary and since it
276 // happens on another thread, even if we don't have room in the queue now, by
277 // the time it runs (may be delayed up to 50ms for complex decodes!) we might.
278 task_runner_->PostTask(FROM_HERE, base::Bind(&VideoRendererImpl::AttemptRead,
279 weak_factory_.GetWeakPtr()));
281 return result;
284 void VideoRendererImpl::OnFrameDropped() {
285 base::AutoLock auto_lock(lock_);
286 DCHECK(use_new_video_renderering_path_);
287 algorithm_->OnLastFrameDropped();
290 void VideoRendererImpl::CreateVideoThread() {
291 // This may fail and cause a crash if there are too many threads created in
292 // the current process. See http://crbug.com/443291
293 const base::ThreadPriority priority =
294 #if defined(OS_WIN)
295 // Bump up our priority so our sleeping is more accurate.
296 // TODO(scherkus): find out if this is necessary, but it seems to help.
297 base::ThreadPriority::DISPLAY;
298 #else
299 base::ThreadPriority::NORMAL;
300 #endif
301 CHECK(base::PlatformThread::CreateWithPriority(0, this, &thread_, priority));
304 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
305 DCHECK(task_runner_->BelongsToCurrentThread());
306 base::AutoLock auto_lock(lock_);
307 DCHECK_EQ(state_, kInitializing);
309 if (!success) {
310 state_ = kUninitialized;
311 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
312 return;
315 // We're all good! Consider ourselves flushed. (ThreadMain() should never
316 // see us in the kUninitialized state).
317 // Since we had an initial Preroll(), we consider ourself flushed, because we
318 // have not populated any buffers yet.
319 state_ = kFlushed;
321 if (use_new_video_renderering_path_) {
322 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_));
323 if (!drop_frames_)
324 algorithm_->disable_frame_dropping();
325 } else {
326 CreateVideoThread();
329 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
332 // PlatformThread::Delegate implementation.
333 void VideoRendererImpl::ThreadMain() {
334 DCHECK(!use_new_video_renderering_path_);
335 base::PlatformThread::SetName("CrVideoRenderer");
337 // The number of milliseconds to idle when we do not have anything to do.
338 // Nothing special about the value, other than we're being more OS-friendly
339 // than sleeping for 1 millisecond.
341 // TODO(scherkus): switch to pure event-driven frame timing instead of this
342 // kIdleTimeDelta business http://crbug.com/106874
343 const base::TimeDelta kIdleTimeDelta =
344 base::TimeDelta::FromMilliseconds(10);
346 for (;;) {
347 base::AutoLock auto_lock(lock_);
349 // Thread exit condition.
350 if (is_shutting_down_)
351 return;
353 // Remain idle as long as we're not playing.
354 if (state_ != kPlaying || buffering_state_ != BUFFERING_HAVE_ENOUGH) {
355 UpdateStatsAndWait_Locked(kIdleTimeDelta);
356 continue;
359 base::TimeTicks now = tick_clock_->NowTicks();
361 // Remain idle until we have the next frame ready for rendering.
362 if (ready_frames_.empty()) {
363 base::TimeDelta wait_time = kIdleTimeDelta;
364 if (received_end_of_stream_) {
365 if (!rendered_end_of_stream_) {
366 rendered_end_of_stream_ = true;
367 task_runner_->PostTask(FROM_HERE, ended_cb_);
369 } else if (now >= latest_possible_paint_time_) {
370 // Declare HAVE_NOTHING if we don't have another frame by the time we
371 // are ready to paint the next one.
372 buffering_state_ = BUFFERING_HAVE_NOTHING;
373 task_runner_->PostTask(
374 FROM_HERE, base::Bind(buffering_state_cb_, BUFFERING_HAVE_NOTHING));
375 } else {
376 wait_time = std::min(kIdleTimeDelta, latest_possible_paint_time_ - now);
379 UpdateStatsAndWait_Locked(wait_time);
380 continue;
383 base::TimeTicks target_paint_time =
384 ConvertMediaTimestamp(ready_frames_.front()->timestamp());
386 // If media time has stopped, don't attempt to paint any more frames.
387 if (target_paint_time.is_null()) {
388 UpdateStatsAndWait_Locked(kIdleTimeDelta);
389 continue;
392 // Deadline is defined as the duration between this frame and the next
393 // frame, using the delta between this frame and the previous frame as the
394 // assumption for frame duration.
396 // TODO(scherkus): This can be vastly improved. Use a histogram to measure
397 // the accuracy of our frame timing code. http://crbug.com/149829
398 if (last_media_time_.is_null()) {
399 latest_possible_paint_time_ = now;
400 } else {
401 base::TimeDelta duration = target_paint_time - last_media_time_;
402 latest_possible_paint_time_ = target_paint_time + duration;
405 // Remain idle until we've reached our target paint window.
406 if (now < target_paint_time) {
407 UpdateStatsAndWait_Locked(
408 std::min(target_paint_time - now, kIdleTimeDelta));
409 continue;
412 if (ready_frames_.size() > 1 && now > latest_possible_paint_time_ &&
413 drop_frames_) {
414 DropNextReadyFrame_Locked();
415 continue;
418 // Congratulations! You've made it past the video frame timing gauntlet.
420 // At this point enough time has passed that the next frame that ready for
421 // rendering.
422 PaintNextReadyFrame_Locked();
426 void VideoRendererImpl::SetTickClockForTesting(
427 scoped_ptr<base::TickClock> tick_clock) {
428 tick_clock_.swap(tick_clock);
431 void VideoRendererImpl::SetGpuMemoryBufferVideoForTesting(
432 scoped_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool) {
433 gpu_memory_buffer_pool_.swap(gpu_memory_buffer_pool);
436 void VideoRendererImpl::OnTimeStateChanged(bool time_progressing) {
437 DCHECK(task_runner_->BelongsToCurrentThread());
438 time_progressing_ = time_progressing;
440 // WARNING: Do not attempt to use |lock_| here as this may be a reentrant call
441 // in response to callbacks firing above.
443 if (!use_new_video_renderering_path_ || sink_started_ == time_progressing_)
444 return;
446 if (time_progressing_) {
447 // If only an EOS frame came in after a seek, the renderer may not have
448 // received the ended event yet though we've posted it.
449 if (!rendered_end_of_stream_)
450 StartSink();
451 } else {
452 StopSink();
456 void VideoRendererImpl::PaintNextReadyFrame_Locked() {
457 DCHECK(!use_new_video_renderering_path_);
458 lock_.AssertAcquired();
460 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
461 ready_frames_.pop_front();
463 last_media_time_ = ConvertMediaTimestamp(next_frame->timestamp());
465 paint_cb_.Run(next_frame);
467 task_runner_->PostTask(
468 FROM_HERE,
469 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
472 void VideoRendererImpl::DropNextReadyFrame_Locked() {
473 DCHECK(!use_new_video_renderering_path_);
474 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
476 lock_.AssertAcquired();
478 last_media_time_ = ConvertMediaTimestamp(ready_frames_.front()->timestamp());
480 ready_frames_.pop_front();
481 frames_dropped_++;
483 task_runner_->PostTask(
484 FROM_HERE,
485 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
488 void VideoRendererImpl::FrameReadyForCopyingToGpuMemoryBuffers(
489 VideoFrameStream::Status status,
490 const scoped_refptr<VideoFrame>& frame) {
491 if (status != VideoFrameStream::OK || start_timestamp_ > frame->timestamp()) {
492 VideoRendererImpl::FrameReady(sequence_token_, status, frame);
493 return;
496 DCHECK(frame);
497 gpu_memory_buffer_pool_->MaybeCreateHardwareFrame(
498 frame, base::Bind(&VideoRendererImpl::FrameReady,
499 weak_factory_.GetWeakPtr(), sequence_token_, status));
502 void VideoRendererImpl::FrameReady(uint32_t sequence_token,
503 VideoFrameStream::Status status,
504 const scoped_refptr<VideoFrame>& frame) {
505 DCHECK(task_runner_->BelongsToCurrentThread());
506 bool start_sink = false;
508 base::AutoLock auto_lock(lock_);
509 // Stream has been reset and this VideoFrame was decoded before the reset
510 // but the async copy finished after.
511 if (sequence_token != sequence_token_)
512 return;
514 DCHECK_NE(state_, kUninitialized);
515 DCHECK_NE(state_, kFlushed);
517 CHECK(pending_read_);
518 pending_read_ = false;
520 if (status == VideoFrameStream::DECODE_ERROR) {
521 DCHECK(!frame.get());
522 PipelineStatus error = PIPELINE_ERROR_DECODE;
523 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
524 return;
527 // Already-queued VideoFrameStream ReadCB's can fire after various state
528 // transitions have happened; in that case just drop those frames
529 // immediately.
530 if (state_ == kFlushing)
531 return;
533 DCHECK_EQ(state_, kPlaying);
535 // Can happen when demuxers are preparing for a new Seek().
536 if (!frame.get()) {
537 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
538 return;
541 // In low delay mode, don't accumulate frames that's earlier than the start
542 // time. Otherwise we could declare HAVE_ENOUGH_DATA and start playback
543 // prematurely.
544 if (low_delay_ &&
545 !frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM) &&
546 frame->timestamp() < start_timestamp_) {
547 AttemptRead_Locked();
548 return;
551 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
552 DCHECK(!received_end_of_stream_);
553 received_end_of_stream_ = true;
555 // See if we can fire EOS immediately instead of waiting for Render().
556 if (use_new_video_renderering_path_)
557 MaybeFireEndedCallback_Locked(time_progressing_);
558 } else {
559 // Maintain the latest frame decoded so the correct frame is displayed
560 // after prerolling has completed.
561 if (frame->timestamp() <= start_timestamp_) {
562 if (use_new_video_renderering_path_)
563 algorithm_->Reset();
564 ready_frames_.clear();
566 AddReadyFrame_Locked(frame);
569 // Background rendering updates may not be ticking fast enough by itself to
570 // remove expired frames, so give it a boost here by ensuring we don't exit
571 // the decoding cycle too early.
573 // Similarly, if we've paused for underflow, remove all frames which are
574 // before the current media time.
575 const bool have_nothing = buffering_state_ != BUFFERING_HAVE_ENOUGH;
576 const bool have_nothing_and_paused = have_nothing && !sink_started_;
577 if (was_background_rendering_ ||
578 (use_new_video_renderering_path_ && have_nothing_and_paused &&
579 drop_frames_)) {
580 base::TimeTicks expiry_time;
581 if (have_nothing_and_paused) {
582 // Use the current media wall clock time plus the frame duration since
583 // RemoveExpiredFrames() is expecting the end point of an interval (it
584 // will subtract from the given value).
585 std::vector<base::TimeTicks> current_time;
586 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), &current_time);
587 expiry_time = current_time[0] + algorithm_->average_frame_duration();
588 } else {
589 expiry_time = tick_clock_->NowTicks();
592 // Prior to rendering the first frame, |have_nothing_and_paused| will be
593 // true, correspondingly the |expiry_time| will be null; in this case
594 // there's no reason to try and remove any frames.
595 if (!expiry_time.is_null()) {
596 const size_t removed_frames =
597 algorithm_->RemoveExpiredFrames(expiry_time);
599 // Frames removed during underflow should be counted as dropped.
600 if (have_nothing_and_paused && removed_frames)
601 frames_dropped_ += removed_frames;
605 // Signal buffering state if we've met our conditions for having enough
606 // data.
607 if (have_nothing && HaveEnoughData_Locked()) {
608 TransitionToHaveEnough_Locked();
609 if (use_new_video_renderering_path_ && !sink_started_ &&
610 !rendered_end_of_stream_) {
611 start_sink = true;
612 render_first_frame_and_stop_ = true;
613 posted_maybe_stop_after_first_paint_ = false;
617 // Always request more decoded video if we have capacity. This serves two
618 // purposes:
619 // 1) Prerolling while paused
620 // 2) Keeps decoding going if video rendering thread starts falling behind
621 AttemptRead_Locked();
624 // If time is progressing, the sink has already been started; this may be true
625 // if we have previously underflowed, yet weren't stopped because of audio.
626 if (use_new_video_renderering_path_ && start_sink) {
627 DCHECK(!sink_started_);
628 StartSink();
632 bool VideoRendererImpl::HaveEnoughData_Locked() {
633 DCHECK_EQ(state_, kPlaying);
635 if (received_end_of_stream_ || !video_frame_stream_->CanReadWithoutStalling())
636 return true;
638 if (HaveReachedBufferingCap())
639 return true;
641 if (use_new_video_renderering_path_ && was_background_rendering_ &&
642 frames_decoded_) {
643 return true;
646 if (!low_delay_)
647 return false;
649 return ready_frames_.size() > 0 ||
650 (use_new_video_renderering_path_ && algorithm_->frames_queued() > 0);
653 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
654 DCHECK(task_runner_->BelongsToCurrentThread());
655 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
657 if (!ready_frames_.empty()) {
658 DCHECK(!use_new_video_renderering_path_);
659 // Because the clock might remain paused in for an undetermined amount
660 // of time (e.g., seeking while paused), paint the first frame.
661 PaintNextReadyFrame_Locked();
664 buffering_state_ = BUFFERING_HAVE_ENOUGH;
665 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
668 void VideoRendererImpl::TransitionToHaveNothing() {
669 DCHECK(task_runner_->BelongsToCurrentThread());
671 base::AutoLock auto_lock(lock_);
672 if (buffering_state_ != BUFFERING_HAVE_ENOUGH || HaveEnoughData_Locked())
673 return;
675 buffering_state_ = BUFFERING_HAVE_NOTHING;
676 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
679 void VideoRendererImpl::AddReadyFrame_Locked(
680 const scoped_refptr<VideoFrame>& frame) {
681 DCHECK(task_runner_->BelongsToCurrentThread());
682 lock_.AssertAcquired();
683 DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
685 frames_decoded_++;
687 if (use_new_video_renderering_path_) {
688 algorithm_->EnqueueFrame(frame);
689 return;
692 ready_frames_.push_back(frame);
693 DCHECK_LE(ready_frames_.size(),
694 static_cast<size_t>(limits::kMaxVideoFrames));
696 // Avoid needlessly waking up |thread_| unless playing.
697 if (state_ == kPlaying)
698 frame_available_.Signal();
701 void VideoRendererImpl::AttemptRead() {
702 base::AutoLock auto_lock(lock_);
703 AttemptRead_Locked();
706 void VideoRendererImpl::AttemptRead_Locked() {
707 DCHECK(task_runner_->BelongsToCurrentThread());
708 lock_.AssertAcquired();
710 if (pending_read_ || received_end_of_stream_)
711 return;
713 if (HaveReachedBufferingCap())
714 return;
716 switch (state_) {
717 case kPlaying:
718 pending_read_ = true;
719 if (gpu_memory_buffer_pool_) {
720 video_frame_stream_->Read(base::Bind(
721 &VideoRendererImpl::FrameReadyForCopyingToGpuMemoryBuffers,
722 weak_factory_.GetWeakPtr()));
723 } else {
724 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
725 weak_factory_.GetWeakPtr(),
726 sequence_token_));
728 return;
729 case kUninitialized:
730 case kInitializing:
731 case kFlushing:
732 case kFlushed:
733 return;
737 void VideoRendererImpl::OnVideoFrameStreamResetDone() {
738 base::AutoLock auto_lock(lock_);
739 DCHECK_EQ(kFlushing, state_);
740 DCHECK(ready_frames_.empty());
741 DCHECK(!received_end_of_stream_);
742 DCHECK(!rendered_end_of_stream_);
743 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
745 // Pending read might be true if an async video frame copy is in flight.
746 pending_read_ = false;
747 sequence_token_++;
748 state_ = kFlushed;
749 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks();
750 base::ResetAndReturn(&flush_cb_).Run();
753 void VideoRendererImpl::UpdateStatsAndWait_Locked(
754 base::TimeDelta wait_duration) {
755 lock_.AssertAcquired();
756 DCHECK_GE(frames_decoded_, 0);
757 DCHECK_GE(frames_dropped_, 0);
759 if (frames_decoded_ || frames_dropped_) {
760 PipelineStatistics statistics;
761 statistics.video_frames_decoded = frames_decoded_;
762 statistics.video_frames_dropped = frames_dropped_;
763 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics));
765 frames_decoded_ = 0;
766 frames_dropped_ = 0;
769 if (wait_duration > base::TimeDelta())
770 frame_available_.TimedWait(wait_duration);
773 void VideoRendererImpl::MaybeStopSinkAfterFirstPaint() {
774 DCHECK(task_runner_->BelongsToCurrentThread());
775 DCHECK(use_new_video_renderering_path_);
777 if (!time_progressing_ && sink_started_)
778 StopSink();
780 base::AutoLock auto_lock(lock_);
781 render_first_frame_and_stop_ = false;
784 bool VideoRendererImpl::HaveReachedBufferingCap() {
785 DCHECK(task_runner_->BelongsToCurrentThread());
786 const size_t kMaxVideoFrames = limits::kMaxVideoFrames;
788 if (use_new_video_renderering_path_) {
789 // When the display rate is less than the frame rate, the effective frames
790 // queued may be much smaller than the actual number of frames queued. Here
791 // we ensure that frames_queued() doesn't get excessive.
792 return algorithm_->EffectiveFramesQueued() >= kMaxVideoFrames ||
793 algorithm_->frames_queued() >= 3 * kMaxVideoFrames;
796 return ready_frames_.size() >= kMaxVideoFrames;
799 void VideoRendererImpl::StartSink() {
800 DCHECK(task_runner_->BelongsToCurrentThread());
801 DCHECK_GT(algorithm_->frames_queued(), 0u);
802 sink_started_ = true;
803 was_background_rendering_ = false;
804 sink_->Start(this);
807 void VideoRendererImpl::StopSink() {
808 DCHECK(task_runner_->BelongsToCurrentThread());
809 sink_->Stop();
810 algorithm_->set_time_stopped();
811 sink_started_ = false;
812 was_background_rendering_ = false;
815 size_t VideoRendererImpl::MaybeFireEndedCallback_Locked(bool time_progressing) {
816 lock_.AssertAcquired();
818 // If there's only one frame in the video or Render() was never called, the
819 // algorithm will have one frame linger indefinitely. So in cases where the
820 // frame duration is unknown and we've received EOS, fire it once we get down
821 // to a single frame.
822 const size_t effective_frames = algorithm_->EffectiveFramesQueued();
824 // Don't fire ended if we haven't received EOS or have already done so.
825 if (!received_end_of_stream_ || rendered_end_of_stream_)
826 return effective_frames;
828 // Don't fire ended if time isn't moving and we have frames.
829 if (!time_progressing && algorithm_->frames_queued())
830 return effective_frames;
832 // Fire ended if we have no more effective frames or only ever had one frame.
833 if (!effective_frames ||
834 (algorithm_->frames_queued() == 1u &&
835 algorithm_->average_frame_duration() == base::TimeDelta())) {
836 rendered_end_of_stream_ = true;
837 task_runner_->PostTask(FROM_HERE, ended_cb_);
840 return effective_frames;
843 base::TimeTicks VideoRendererImpl::ConvertMediaTimestamp(
844 base::TimeDelta media_time) {
845 std::vector<base::TimeDelta> media_times(1, media_time);
846 std::vector<base::TimeTicks> wall_clock_times;
847 if (!wall_clock_time_cb_.Run(media_times, &wall_clock_times))
848 return base::TimeTicks();
849 return wall_clock_times[0];
852 } // namespace media