cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / media / renderers / video_renderer_impl.cc
blob19af7a1d34ed71cb776251a4b01cf5383c702def
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/limits.h"
20 #include "media/base/media_log.h"
21 #include "media/base/media_switches.h"
22 #include "media/base/pipeline.h"
23 #include "media/base/video_frame.h"
24 #include "media/renderers/gpu_video_accelerator_factories.h"
25 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
27 namespace media {
29 // TODO(dalecurtis): This experiment is temporary and should be removed once we
30 // have enough data to support the primacy of the new video rendering path; see
31 // http://crbug.com/485699 for details.
32 static bool ShouldUseVideoRenderingPath() {
33 // Note: It's important to query the field trial state first, to ensure that
34 // UMA reports the correct group.
35 const std::string group_name =
36 base::FieldTrialList::FindFullName("NewVideoRendererTrial");
37 const bool disabled_via_cli =
38 base::CommandLine::ForCurrentProcess()->HasSwitch(
39 switches::kDisableNewVideoRenderer);
40 return !disabled_via_cli &&
41 !base::StartsWith(group_name, "Disabled",
42 base::CompareCase::SENSITIVE);
45 VideoRendererImpl::VideoRendererImpl(
46 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
47 const scoped_refptr<base::TaskRunner>& worker_task_runner,
48 VideoRendererSink* sink,
49 ScopedVector<VideoDecoder> decoders,
50 bool drop_frames,
51 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories,
52 const scoped_refptr<MediaLog>& media_log)
53 : task_runner_(media_task_runner),
54 use_new_video_renderering_path_(ShouldUseVideoRenderingPath()),
55 sink_(sink),
56 sink_started_(false),
57 video_frame_stream_(
58 new VideoFrameStream(media_task_runner, decoders.Pass(), media_log)),
59 gpu_memory_buffer_pool_(nullptr),
60 media_log_(media_log),
61 low_delay_(false),
62 received_end_of_stream_(false),
63 rendered_end_of_stream_(false),
64 frame_available_(&lock_),
65 state_(kUninitialized),
66 sequence_token_(0),
67 thread_(),
68 pending_read_(false),
69 drop_frames_(drop_frames),
70 buffering_state_(BUFFERING_HAVE_NOTHING),
71 frames_decoded_(0),
72 frames_dropped_(0),
73 is_shutting_down_(false),
74 tick_clock_(new base::DefaultTickClock()),
75 was_background_rendering_(false),
76 time_progressing_(false),
77 render_first_frame_and_stop_(false),
78 posted_maybe_stop_after_first_paint_(false),
79 weak_factory_(this) {
80 if (gpu_factories &&
81 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames()) {
82 gpu_memory_buffer_pool_.reset(new GpuMemoryBufferVideoFramePool(
83 media_task_runner, worker_task_runner, gpu_factories));
87 VideoRendererImpl::~VideoRendererImpl() {
88 DCHECK(task_runner_->BelongsToCurrentThread());
90 if (!use_new_video_renderering_path_) {
91 base::AutoLock auto_lock(lock_);
92 is_shutting_down_ = true;
93 frame_available_.Signal();
96 if (!thread_.is_null())
97 base::PlatformThread::Join(thread_);
99 if (!init_cb_.is_null())
100 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
102 if (!flush_cb_.is_null())
103 base::ResetAndReturn(&flush_cb_).Run();
105 if (use_new_video_renderering_path_ && sink_started_)
106 StopSink();
109 void VideoRendererImpl::Flush(const base::Closure& callback) {
110 DVLOG(1) << __FUNCTION__;
111 DCHECK(task_runner_->BelongsToCurrentThread());
113 if (use_new_video_renderering_path_ && sink_started_)
114 StopSink();
116 base::AutoLock auto_lock(lock_);
117 DCHECK_EQ(state_, kPlaying);
118 flush_cb_ = callback;
119 state_ = kFlushing;
121 // This is necessary if the |video_frame_stream_| has already seen an end of
122 // stream and needs to drain it before flushing it.
123 ready_frames_.clear();
124 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
125 buffering_state_ = BUFFERING_HAVE_NOTHING;
126 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
128 received_end_of_stream_ = false;
129 rendered_end_of_stream_ = false;
131 if (use_new_video_renderering_path_)
132 algorithm_->Reset();
134 video_frame_stream_->Reset(
135 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone,
136 weak_factory_.GetWeakPtr()));
139 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
140 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")";
141 DCHECK(task_runner_->BelongsToCurrentThread());
142 base::AutoLock auto_lock(lock_);
143 DCHECK_EQ(state_, kFlushed);
144 DCHECK(!pending_read_);
145 DCHECK(ready_frames_.empty());
146 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
148 state_ = kPlaying;
149 start_timestamp_ = timestamp;
150 AttemptRead_Locked();
153 void VideoRendererImpl::Initialize(
154 DemuxerStream* stream,
155 const PipelineStatusCB& init_cb,
156 const SetDecryptorReadyCB& set_decryptor_ready_cb,
157 const StatisticsCB& statistics_cb,
158 const BufferingStateCB& buffering_state_cb,
159 const base::Closure& ended_cb,
160 const PipelineStatusCB& error_cb,
161 const TimeSource::WallClockTimeCB& wall_clock_time_cb,
162 const base::Closure& waiting_for_decryption_key_cb) {
163 DCHECK(task_runner_->BelongsToCurrentThread());
164 base::AutoLock auto_lock(lock_);
165 DCHECK(stream);
166 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
167 DCHECK(!init_cb.is_null());
168 DCHECK(!statistics_cb.is_null());
169 DCHECK(!buffering_state_cb.is_null());
170 DCHECK(!ended_cb.is_null());
171 DCHECK(!wall_clock_time_cb.is_null());
172 DCHECK_EQ(kUninitialized, state_);
173 DCHECK(!render_first_frame_and_stop_);
174 DCHECK(!posted_maybe_stop_after_first_paint_);
175 DCHECK(!was_background_rendering_);
176 DCHECK(!time_progressing_);
178 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE);
179 UMA_HISTOGRAM_BOOLEAN("Media.VideoRenderer.LowDelay", low_delay_);
180 if (low_delay_)
181 MEDIA_LOG(DEBUG, media_log_) << "Video rendering in low delay mode.";
183 // Always post |init_cb_| because |this| could be destroyed if initialization
184 // failed.
185 init_cb_ = BindToCurrentLoop(init_cb);
187 // Always post |buffering_state_cb_| because it may otherwise invoke reentrant
188 // calls to OnTimeStateChanged() under lock, which can deadlock the compositor
189 // and media threads.
190 buffering_state_cb_ = BindToCurrentLoop(buffering_state_cb);
192 statistics_cb_ = statistics_cb;
193 paint_cb_ = base::Bind(&VideoRendererSink::PaintFrameUsingOldRenderingPath,
194 base::Unretained(sink_));
195 ended_cb_ = ended_cb;
196 error_cb_ = error_cb;
197 wall_clock_time_cb_ = wall_clock_time_cb;
198 state_ = kInitializing;
200 video_frame_stream_->Initialize(
201 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
202 weak_factory_.GetWeakPtr()),
203 set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
206 scoped_refptr<VideoFrame> VideoRendererImpl::Render(
207 base::TimeTicks deadline_min,
208 base::TimeTicks deadline_max,
209 bool background_rendering) {
210 base::AutoLock auto_lock(lock_);
211 DCHECK(use_new_video_renderering_path_);
212 DCHECK_EQ(state_, kPlaying);
214 size_t frames_dropped = 0;
215 scoped_refptr<VideoFrame> result =
216 algorithm_->Render(deadline_min, deadline_max, &frames_dropped);
218 // Due to how the |algorithm_| holds frames, this should never be null if
219 // we've had a proper startup sequence.
220 DCHECK(result);
222 // Declare HAVE_NOTHING if we reach a state where we can't progress playback
223 // any further. We don't want to do this if we've already done so, reached
224 // end of stream, or have frames available. We also don't want to do this in
225 // background rendering mode unless this isn't the first background render
226 // tick and we haven't seen any decoded frames since the last one.
228 // We use the inverse of |render_first_frame_and_stop_| as a proxy for the
229 // value of |time_progressing_| here since we can't access it from the
230 // compositor thread. If we're here (in Render()) the sink must have been
231 // started -- but if it was started only to render the first frame and stop,
232 // then |time_progressing_| is likely false. If we're still in Render() when
233 // |render_first_frame_and_stop_| is false, then |time_progressing_| is true.
234 // If |time_progressing_| is actually true when |render_first_frame_and_stop_|
235 // is also true, then the ended callback will be harmlessly delayed until
236 // MaybeStopSinkAfterFirstPaint() runs and the next Render() call comes in.
237 const size_t effective_frames =
238 MaybeFireEndedCallback_Locked(!render_first_frame_and_stop_);
239 if (buffering_state_ == BUFFERING_HAVE_ENOUGH && !received_end_of_stream_ &&
240 !effective_frames && (!background_rendering ||
241 (!frames_decoded_ && was_background_rendering_))) {
242 // Do not set |buffering_state_| here as the lock in FrameReady() may be
243 // held already and it fire the state changes in the wrong order.
244 task_runner_->PostTask(
245 FROM_HERE, base::Bind(&VideoRendererImpl::TransitionToHaveNothing,
246 weak_factory_.GetWeakPtr()));
249 // We don't count dropped frames in the background to avoid skewing the count
250 // and impacting JavaScript visible metrics used by web developers.
252 // Just after resuming from background rendering, we also don't count the
253 // dropped frames since they are likely just dropped due to being too old.
254 if (!background_rendering && !was_background_rendering_)
255 frames_dropped_ += frames_dropped;
256 UpdateStatsAndWait_Locked(base::TimeDelta());
257 was_background_rendering_ = background_rendering;
259 // After painting the first frame, if playback hasn't started, we post a
260 // delayed task to request that the sink be stopped. The task is delayed to
261 // give videos with autoplay time to start.
263 // OnTimeStateChanged() will clear this flag if time starts before we get here
264 // and MaybeStopSinkAfterFirstPaint() will ignore this request if time starts
265 // before the call executes.
266 if (render_first_frame_and_stop_ && !posted_maybe_stop_after_first_paint_) {
267 posted_maybe_stop_after_first_paint_ = true;
268 task_runner_->PostDelayedTask(
269 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
270 weak_factory_.GetWeakPtr()),
271 base::TimeDelta::FromMilliseconds(250));
274 // Always post this task, it will acquire new frames if necessary and since it
275 // happens on another thread, even if we don't have room in the queue now, by
276 // the time it runs (may be delayed up to 50ms for complex decodes!) we might.
277 task_runner_->PostTask(FROM_HERE, base::Bind(&VideoRendererImpl::AttemptRead,
278 weak_factory_.GetWeakPtr()));
280 return result;
283 void VideoRendererImpl::OnFrameDropped() {
284 base::AutoLock auto_lock(lock_);
285 DCHECK(use_new_video_renderering_path_);
286 algorithm_->OnLastFrameDropped();
289 void VideoRendererImpl::CreateVideoThread() {
290 // This may fail and cause a crash if there are too many threads created in
291 // the current process. See http://crbug.com/443291
292 const base::ThreadPriority priority =
293 #if defined(OS_WIN)
294 // Bump up our priority so our sleeping is more accurate.
295 // TODO(scherkus): find out if this is necessary, but it seems to help.
296 base::ThreadPriority::DISPLAY;
297 #else
298 base::ThreadPriority::NORMAL;
299 #endif
300 CHECK(base::PlatformThread::CreateWithPriority(0, this, &thread_, priority));
303 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
304 DCHECK(task_runner_->BelongsToCurrentThread());
305 base::AutoLock auto_lock(lock_);
306 DCHECK_EQ(state_, kInitializing);
308 if (!success) {
309 state_ = kUninitialized;
310 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
311 return;
314 // We're all good! Consider ourselves flushed. (ThreadMain() should never
315 // see us in the kUninitialized state).
316 // Since we had an initial Preroll(), we consider ourself flushed, because we
317 // have not populated any buffers yet.
318 state_ = kFlushed;
320 if (use_new_video_renderering_path_) {
321 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_));
322 if (!drop_frames_)
323 algorithm_->disable_frame_dropping();
324 } else {
325 CreateVideoThread();
328 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
331 // PlatformThread::Delegate implementation.
332 void VideoRendererImpl::ThreadMain() {
333 DCHECK(!use_new_video_renderering_path_);
334 base::PlatformThread::SetName("CrVideoRenderer");
336 // The number of milliseconds to idle when we do not have anything to do.
337 // Nothing special about the value, other than we're being more OS-friendly
338 // than sleeping for 1 millisecond.
340 // TODO(scherkus): switch to pure event-driven frame timing instead of this
341 // kIdleTimeDelta business http://crbug.com/106874
342 const base::TimeDelta kIdleTimeDelta =
343 base::TimeDelta::FromMilliseconds(10);
345 for (;;) {
346 base::AutoLock auto_lock(lock_);
348 // Thread exit condition.
349 if (is_shutting_down_)
350 return;
352 // Remain idle as long as we're not playing.
353 if (state_ != kPlaying || buffering_state_ != BUFFERING_HAVE_ENOUGH) {
354 UpdateStatsAndWait_Locked(kIdleTimeDelta);
355 continue;
358 base::TimeTicks now = tick_clock_->NowTicks();
360 // Remain idle until we have the next frame ready for rendering.
361 if (ready_frames_.empty()) {
362 base::TimeDelta wait_time = kIdleTimeDelta;
363 if (received_end_of_stream_) {
364 if (!rendered_end_of_stream_) {
365 rendered_end_of_stream_ = true;
366 task_runner_->PostTask(FROM_HERE, ended_cb_);
368 } else if (now >= latest_possible_paint_time_) {
369 // Declare HAVE_NOTHING if we don't have another frame by the time we
370 // are ready to paint the next one.
371 buffering_state_ = BUFFERING_HAVE_NOTHING;
372 task_runner_->PostTask(
373 FROM_HERE, base::Bind(buffering_state_cb_, BUFFERING_HAVE_NOTHING));
374 } else {
375 wait_time = std::min(kIdleTimeDelta, latest_possible_paint_time_ - now);
378 UpdateStatsAndWait_Locked(wait_time);
379 continue;
382 base::TimeTicks target_paint_time =
383 ConvertMediaTimestamp(ready_frames_.front()->timestamp());
385 // If media time has stopped, don't attempt to paint any more frames.
386 if (target_paint_time.is_null()) {
387 UpdateStatsAndWait_Locked(kIdleTimeDelta);
388 continue;
391 // Deadline is defined as the duration between this frame and the next
392 // frame, using the delta between this frame and the previous frame as the
393 // assumption for frame duration.
395 // TODO(scherkus): This can be vastly improved. Use a histogram to measure
396 // the accuracy of our frame timing code. http://crbug.com/149829
397 if (last_media_time_.is_null()) {
398 latest_possible_paint_time_ = now;
399 } else {
400 base::TimeDelta duration = target_paint_time - last_media_time_;
401 latest_possible_paint_time_ = target_paint_time + duration;
404 // Remain idle until we've reached our target paint window.
405 if (now < target_paint_time) {
406 UpdateStatsAndWait_Locked(
407 std::min(target_paint_time - now, kIdleTimeDelta));
408 continue;
411 if (ready_frames_.size() > 1 && now > latest_possible_paint_time_ &&
412 drop_frames_) {
413 DropNextReadyFrame_Locked();
414 continue;
417 // Congratulations! You've made it past the video frame timing gauntlet.
419 // At this point enough time has passed that the next frame that ready for
420 // rendering.
421 PaintNextReadyFrame_Locked();
425 void VideoRendererImpl::SetTickClockForTesting(
426 scoped_ptr<base::TickClock> tick_clock) {
427 tick_clock_.swap(tick_clock);
430 void VideoRendererImpl::SetGpuMemoryBufferVideoForTesting(
431 scoped_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool) {
432 gpu_memory_buffer_pool_.swap(gpu_memory_buffer_pool);
435 void VideoRendererImpl::OnTimeStateChanged(bool time_progressing) {
436 DCHECK(task_runner_->BelongsToCurrentThread());
437 time_progressing_ = time_progressing;
439 // WARNING: Do not attempt to use |lock_| here as this may be a reentrant call
440 // in response to callbacks firing above.
442 if (!use_new_video_renderering_path_ || sink_started_ == time_progressing_)
443 return;
445 if (time_progressing_) {
446 // If only an EOS frame came in after a seek, the renderer may not have
447 // received the ended event yet though we've posted it.
448 if (!rendered_end_of_stream_)
449 StartSink();
450 } else {
451 StopSink();
455 void VideoRendererImpl::PaintNextReadyFrame_Locked() {
456 DCHECK(!use_new_video_renderering_path_);
457 lock_.AssertAcquired();
459 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
460 ready_frames_.pop_front();
462 last_media_time_ = ConvertMediaTimestamp(next_frame->timestamp());
464 paint_cb_.Run(next_frame);
466 task_runner_->PostTask(
467 FROM_HERE,
468 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
471 void VideoRendererImpl::DropNextReadyFrame_Locked() {
472 DCHECK(!use_new_video_renderering_path_);
473 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
475 lock_.AssertAcquired();
477 last_media_time_ = ConvertMediaTimestamp(ready_frames_.front()->timestamp());
479 ready_frames_.pop_front();
480 frames_dropped_++;
482 task_runner_->PostTask(
483 FROM_HERE,
484 base::Bind(&VideoRendererImpl::AttemptRead, weak_factory_.GetWeakPtr()));
487 void VideoRendererImpl::FrameReadyForCopyingToGpuMemoryBuffers(
488 VideoFrameStream::Status status,
489 const scoped_refptr<VideoFrame>& frame) {
490 if (status != VideoFrameStream::OK || start_timestamp_ > frame->timestamp()) {
491 VideoRendererImpl::FrameReady(sequence_token_, status, frame);
492 return;
495 DCHECK(frame);
496 gpu_memory_buffer_pool_->MaybeCreateHardwareFrame(
497 frame, base::Bind(&VideoRendererImpl::FrameReady,
498 weak_factory_.GetWeakPtr(), sequence_token_, status));
501 void VideoRendererImpl::FrameReady(uint32_t sequence_token,
502 VideoFrameStream::Status status,
503 const scoped_refptr<VideoFrame>& frame) {
504 DCHECK(task_runner_->BelongsToCurrentThread());
505 bool start_sink = false;
507 base::AutoLock auto_lock(lock_);
508 // Stream has been reset and this VideoFrame was decoded before the reset
509 // but the async copy finished after.
510 if (sequence_token != sequence_token_)
511 return;
513 DCHECK_NE(state_, kUninitialized);
514 DCHECK_NE(state_, kFlushed);
516 CHECK(pending_read_);
517 pending_read_ = false;
519 if (status == VideoFrameStream::DECODE_ERROR) {
520 DCHECK(!frame.get());
521 PipelineStatus error = PIPELINE_ERROR_DECODE;
522 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error));
523 return;
526 // Already-queued VideoFrameStream ReadCB's can fire after various state
527 // transitions have happened; in that case just drop those frames
528 // immediately.
529 if (state_ == kFlushing)
530 return;
532 DCHECK_EQ(state_, kPlaying);
534 // Can happen when demuxers are preparing for a new Seek().
535 if (!frame.get()) {
536 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
537 return;
540 // In low delay mode, don't accumulate frames that's earlier than the start
541 // time. Otherwise we could declare HAVE_ENOUGH_DATA and start playback
542 // prematurely.
543 if (low_delay_ &&
544 !frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM) &&
545 frame->timestamp() < start_timestamp_) {
546 AttemptRead_Locked();
547 return;
550 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
551 DCHECK(!received_end_of_stream_);
552 received_end_of_stream_ = true;
554 // See if we can fire EOS immediately instead of waiting for Render().
555 if (use_new_video_renderering_path_)
556 MaybeFireEndedCallback_Locked(time_progressing_);
557 } else {
558 // Maintain the latest frame decoded so the correct frame is displayed
559 // after prerolling has completed.
560 if (frame->timestamp() <= start_timestamp_) {
561 if (use_new_video_renderering_path_)
562 algorithm_->Reset();
563 ready_frames_.clear();
565 AddReadyFrame_Locked(frame);
568 // Background rendering updates may not be ticking fast enough by itself to
569 // remove expired frames, so give it a boost here by ensuring we don't exit
570 // the decoding cycle too early.
572 // Similarly, if we've paused for underflow, remove all frames which are
573 // before the current media time.
574 const bool have_nothing = buffering_state_ != BUFFERING_HAVE_ENOUGH;
575 const bool have_nothing_and_paused = have_nothing && !sink_started_;
576 if (was_background_rendering_ ||
577 (use_new_video_renderering_path_ && have_nothing_and_paused &&
578 drop_frames_)) {
579 base::TimeTicks expiry_time;
580 if (have_nothing_and_paused) {
581 // Use the current media wall clock time plus the frame duration since
582 // RemoveExpiredFrames() is expecting the end point of an interval (it
583 // will subtract from the given value).
584 std::vector<base::TimeTicks> current_time;
585 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), &current_time);
586 expiry_time = current_time[0] + algorithm_->average_frame_duration();
587 } else {
588 expiry_time = tick_clock_->NowTicks();
591 // Prior to rendering the first frame, |have_nothing_and_paused| will be
592 // true, correspondingly the |expiry_time| will be null; in this case
593 // there's no reason to try and remove any frames.
594 if (!expiry_time.is_null()) {
595 const size_t removed_frames =
596 algorithm_->RemoveExpiredFrames(expiry_time);
598 // Frames removed during underflow should be counted as dropped.
599 if (have_nothing_and_paused && removed_frames)
600 frames_dropped_ += removed_frames;
604 // Signal buffering state if we've met our conditions for having enough
605 // data.
606 if (have_nothing && HaveEnoughData_Locked()) {
607 TransitionToHaveEnough_Locked();
608 if (use_new_video_renderering_path_ && !sink_started_ &&
609 !rendered_end_of_stream_) {
610 start_sink = true;
611 render_first_frame_and_stop_ = true;
612 posted_maybe_stop_after_first_paint_ = false;
616 // Always request more decoded video if we have capacity. This serves two
617 // purposes:
618 // 1) Prerolling while paused
619 // 2) Keeps decoding going if video rendering thread starts falling behind
620 AttemptRead_Locked();
623 // If time is progressing, the sink has already been started; this may be true
624 // if we have previously underflowed, yet weren't stopped because of audio.
625 if (use_new_video_renderering_path_ && start_sink) {
626 DCHECK(!sink_started_);
627 StartSink();
631 bool VideoRendererImpl::HaveEnoughData_Locked() {
632 DCHECK_EQ(state_, kPlaying);
634 if (received_end_of_stream_ || !video_frame_stream_->CanReadWithoutStalling())
635 return true;
637 if (HaveReachedBufferingCap())
638 return true;
640 if (use_new_video_renderering_path_ && was_background_rendering_ &&
641 frames_decoded_) {
642 return true;
645 if (!low_delay_)
646 return false;
648 return ready_frames_.size() > 0 ||
649 (use_new_video_renderering_path_ && algorithm_->frames_queued() > 0);
652 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
653 DCHECK(task_runner_->BelongsToCurrentThread());
654 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
656 if (!ready_frames_.empty()) {
657 DCHECK(!use_new_video_renderering_path_);
658 // Because the clock might remain paused in for an undetermined amount
659 // of time (e.g., seeking while paused), paint the first frame.
660 PaintNextReadyFrame_Locked();
663 buffering_state_ = BUFFERING_HAVE_ENOUGH;
664 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
667 void VideoRendererImpl::TransitionToHaveNothing() {
668 DCHECK(task_runner_->BelongsToCurrentThread());
670 base::AutoLock auto_lock(lock_);
671 if (buffering_state_ != BUFFERING_HAVE_ENOUGH || HaveEnoughData_Locked())
672 return;
674 buffering_state_ = BUFFERING_HAVE_NOTHING;
675 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
678 void VideoRendererImpl::AddReadyFrame_Locked(
679 const scoped_refptr<VideoFrame>& frame) {
680 DCHECK(task_runner_->BelongsToCurrentThread());
681 lock_.AssertAcquired();
682 DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
684 frames_decoded_++;
686 if (use_new_video_renderering_path_) {
687 algorithm_->EnqueueFrame(frame);
688 return;
691 ready_frames_.push_back(frame);
692 DCHECK_LE(ready_frames_.size(),
693 static_cast<size_t>(limits::kMaxVideoFrames));
695 // Avoid needlessly waking up |thread_| unless playing.
696 if (state_ == kPlaying)
697 frame_available_.Signal();
700 void VideoRendererImpl::AttemptRead() {
701 base::AutoLock auto_lock(lock_);
702 AttemptRead_Locked();
705 void VideoRendererImpl::AttemptRead_Locked() {
706 DCHECK(task_runner_->BelongsToCurrentThread());
707 lock_.AssertAcquired();
709 if (pending_read_ || received_end_of_stream_)
710 return;
712 if (HaveReachedBufferingCap())
713 return;
715 switch (state_) {
716 case kPlaying:
717 pending_read_ = true;
718 if (gpu_memory_buffer_pool_) {
719 video_frame_stream_->Read(base::Bind(
720 &VideoRendererImpl::FrameReadyForCopyingToGpuMemoryBuffers,
721 weak_factory_.GetWeakPtr()));
722 } else {
723 video_frame_stream_->Read(base::Bind(&VideoRendererImpl::FrameReady,
724 weak_factory_.GetWeakPtr(),
725 sequence_token_));
727 return;
728 case kUninitialized:
729 case kInitializing:
730 case kFlushing:
731 case kFlushed:
732 return;
736 void VideoRendererImpl::OnVideoFrameStreamResetDone() {
737 base::AutoLock auto_lock(lock_);
738 DCHECK_EQ(kFlushing, state_);
739 DCHECK(ready_frames_.empty());
740 DCHECK(!received_end_of_stream_);
741 DCHECK(!rendered_end_of_stream_);
742 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
744 // Pending read might be true if an async video frame copy is in flight.
745 pending_read_ = false;
746 sequence_token_++;
747 state_ = kFlushed;
748 latest_possible_paint_time_ = last_media_time_ = base::TimeTicks();
749 base::ResetAndReturn(&flush_cb_).Run();
752 void VideoRendererImpl::UpdateStatsAndWait_Locked(
753 base::TimeDelta wait_duration) {
754 lock_.AssertAcquired();
755 DCHECK_GE(frames_decoded_, 0);
756 DCHECK_GE(frames_dropped_, 0);
758 if (frames_decoded_ || frames_dropped_) {
759 PipelineStatistics statistics;
760 statistics.video_frames_decoded = frames_decoded_;
761 statistics.video_frames_dropped = frames_dropped_;
762 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics));
764 frames_decoded_ = 0;
765 frames_dropped_ = 0;
768 if (wait_duration > base::TimeDelta())
769 frame_available_.TimedWait(wait_duration);
772 void VideoRendererImpl::MaybeStopSinkAfterFirstPaint() {
773 DCHECK(task_runner_->BelongsToCurrentThread());
774 DCHECK(use_new_video_renderering_path_);
776 if (!time_progressing_ && sink_started_)
777 StopSink();
779 base::AutoLock auto_lock(lock_);
780 render_first_frame_and_stop_ = false;
783 bool VideoRendererImpl::HaveReachedBufferingCap() {
784 DCHECK(task_runner_->BelongsToCurrentThread());
785 const size_t kMaxVideoFrames = limits::kMaxVideoFrames;
787 if (use_new_video_renderering_path_) {
788 // When the display rate is less than the frame rate, the effective frames
789 // queued may be much smaller than the actual number of frames queued. Here
790 // we ensure that frames_queued() doesn't get excessive.
791 return algorithm_->EffectiveFramesQueued() >= kMaxVideoFrames ||
792 algorithm_->frames_queued() >= 3 * kMaxVideoFrames;
795 return ready_frames_.size() >= kMaxVideoFrames;
798 void VideoRendererImpl::StartSink() {
799 DCHECK(task_runner_->BelongsToCurrentThread());
800 DCHECK_GT(algorithm_->frames_queued(), 0u);
801 sink_started_ = true;
802 was_background_rendering_ = false;
803 sink_->Start(this);
806 void VideoRendererImpl::StopSink() {
807 DCHECK(task_runner_->BelongsToCurrentThread());
808 sink_->Stop();
809 algorithm_->set_time_stopped();
810 sink_started_ = false;
811 was_background_rendering_ = false;
814 size_t VideoRendererImpl::MaybeFireEndedCallback_Locked(bool time_progressing) {
815 lock_.AssertAcquired();
817 // If there's only one frame in the video or Render() was never called, the
818 // algorithm will have one frame linger indefinitely. So in cases where the
819 // frame duration is unknown and we've received EOS, fire it once we get down
820 // to a single frame.
821 const size_t effective_frames = algorithm_->EffectiveFramesQueued();
823 // Don't fire ended if we haven't received EOS or have already done so.
824 if (!received_end_of_stream_ || rendered_end_of_stream_)
825 return effective_frames;
827 // Don't fire ended if time isn't moving and we have frames.
828 if (!time_progressing && algorithm_->frames_queued())
829 return effective_frames;
831 // Fire ended if we have no more effective frames or only ever had one frame.
832 if (!effective_frames ||
833 (algorithm_->frames_queued() == 1u &&
834 algorithm_->average_frame_duration() == base::TimeDelta())) {
835 rendered_end_of_stream_ = true;
836 task_runner_->PostTask(FROM_HERE, ended_cb_);
839 return effective_frames;
842 base::TimeTicks VideoRendererImpl::ConvertMediaTimestamp(
843 base::TimeDelta media_time) {
844 std::vector<base::TimeDelta> media_times(1, media_time);
845 std::vector<base::TimeTicks> wall_clock_times;
846 if (!wall_clock_time_cb_.Run(media_times, &wall_clock_times))
847 return base::TimeTicks();
848 return wall_clock_times[0];
851 } // namespace media