OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/renderers/video_renderer_impl.h" | 5 #include "media/renderers/video_renderer_impl.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
52 drop_frames_(drop_frames), | 52 drop_frames_(drop_frames), |
53 buffering_state_(BUFFERING_HAVE_NOTHING), | 53 buffering_state_(BUFFERING_HAVE_NOTHING), |
54 frames_decoded_(0), | 54 frames_decoded_(0), |
55 frames_dropped_(0), | 55 frames_dropped_(0), |
56 tick_clock_(new base::DefaultTickClock()), | 56 tick_clock_(new base::DefaultTickClock()), |
57 was_background_rendering_(false), | 57 was_background_rendering_(false), |
58 time_progressing_(false), | 58 time_progressing_(false), |
59 last_video_memory_usage_(0), | 59 last_video_memory_usage_(0), |
60 have_renderered_frames_(false), | 60 have_renderered_frames_(false), |
61 last_frame_opaque_(false), | 61 last_frame_opaque_(false), |
62 painted_first_frame_(false), | |
62 weak_factory_(this), | 63 weak_factory_(this), |
63 frame_callback_weak_factory_(this) { | 64 frame_callback_weak_factory_(this) { |
64 if (gpu_factories && | 65 if (gpu_factories && |
65 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames()) { | 66 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames()) { |
66 gpu_memory_buffer_pool_.reset(new GpuMemoryBufferVideoFramePool( | 67 gpu_memory_buffer_pool_.reset(new GpuMemoryBufferVideoFramePool( |
67 media_task_runner, worker_task_runner, gpu_factories)); | 68 media_task_runner, worker_task_runner, gpu_factories)); |
68 } | 69 } |
69 } | 70 } |
70 | 71 |
71 VideoRendererImpl::~VideoRendererImpl() { | 72 VideoRendererImpl::~VideoRendererImpl() { |
72 DCHECK(task_runner_->BelongsToCurrentThread()); | 73 DCHECK(task_runner_->BelongsToCurrentThread()); |
73 | 74 |
74 if (!init_cb_.is_null()) | 75 if (!init_cb_.is_null()) |
75 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); | 76 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); |
76 | 77 |
77 if (!flush_cb_.is_null()) | 78 if (!flush_cb_.is_null()) |
78 base::ResetAndReturn(&flush_cb_).Run(); | 79 base::ResetAndReturn(&flush_cb_).Run(); |
79 | 80 |
80 if (sink_started_) | 81 if (sink_started_) |
81 StopSink(); | 82 StopSink(); |
82 } | 83 } |
83 | 84 |
84 void VideoRendererImpl::Flush(const base::Closure& callback) { | 85 void VideoRendererImpl::Flush(const base::Closure& callback) { |
chcunningham
2016/10/21 20:27:22
should you reset painted_first_frame_ here?
DaleCurtis
2016/10/21 21:51:17
Yup, done.
| |
85 DVLOG(1) << __func__; | 86 DVLOG(1) << __func__; |
86 DCHECK(task_runner_->BelongsToCurrentThread()); | 87 DCHECK(task_runner_->BelongsToCurrentThread()); |
87 | 88 |
88 if (sink_started_) | 89 if (sink_started_) |
89 StopSink(); | 90 StopSink(); |
90 | 91 |
91 base::AutoLock auto_lock(lock_); | 92 base::AutoLock auto_lock(lock_); |
92 DCHECK_EQ(state_, kPlaying); | 93 DCHECK_EQ(state_, kPlaying); |
93 flush_cb_ = callback; | 94 flush_cb_ = callback; |
94 state_ = kFlushing; | 95 state_ = kFlushing; |
(...skipping 24 matching lines...) Expand all Loading... | |
119 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { | 120 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { |
120 DVLOG(1) << __func__ << "(" << timestamp.InMicroseconds() << ")"; | 121 DVLOG(1) << __func__ << "(" << timestamp.InMicroseconds() << ")"; |
121 DCHECK(task_runner_->BelongsToCurrentThread()); | 122 DCHECK(task_runner_->BelongsToCurrentThread()); |
122 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
123 DCHECK_EQ(state_, kFlushed); | 124 DCHECK_EQ(state_, kFlushed); |
124 DCHECK(!pending_read_); | 125 DCHECK(!pending_read_); |
125 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 126 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
126 | 127 |
127 state_ = kPlaying; | 128 state_ = kPlaying; |
128 start_timestamp_ = timestamp; | 129 start_timestamp_ = timestamp; |
130 painted_first_frame_ = false; | |
129 AttemptRead_Locked(); | 131 AttemptRead_Locked(); |
130 } | 132 } |
131 | 133 |
132 void VideoRendererImpl::Initialize( | 134 void VideoRendererImpl::Initialize( |
133 DemuxerStream* stream, | 135 DemuxerStream* stream, |
134 CdmContext* cdm_context, | 136 CdmContext* cdm_context, |
135 RendererClient* client, | 137 RendererClient* client, |
136 const TimeSource::WallClockTimeCB& wall_clock_time_cb, | 138 const TimeSource::WallClockTimeCB& wall_clock_time_cb, |
137 const PipelineStatusCB& init_cb) { | 139 const PipelineStatusCB& init_cb) { |
138 DCHECK(task_runner_->BelongsToCurrentThread()); | 140 DCHECK(task_runner_->BelongsToCurrentThread()); |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
393 // Attempt to purge bad frames in case of underflow or backgrounding. | 395 // Attempt to purge bad frames in case of underflow or backgrounding. |
394 RemoveFramesForUnderflowOrBackgroundRendering(); | 396 RemoveFramesForUnderflowOrBackgroundRendering(); |
395 | 397 |
396 // We may have removed all frames above and have reached end of stream. | 398 // We may have removed all frames above and have reached end of stream. |
397 MaybeFireEndedCallback_Locked(time_progressing_); | 399 MaybeFireEndedCallback_Locked(time_progressing_); |
398 | 400 |
399 // Update statistics here instead of during Render() when the sink is stopped. | 401 // Update statistics here instead of during Render() when the sink is stopped. |
400 if (!sink_started_) | 402 if (!sink_started_) |
401 UpdateStats_Locked(); | 403 UpdateStats_Locked(); |
402 | 404 |
403 // Paint the first frame if possible and necessary. PaintSingleFrame() will | 405 // Paint the first frame if possible and necessary. Paint ahead of |
404 // ignore repeated calls for the same frame. Paint ahead of HAVE_ENOUGH_DATA | 406 // HAVE_ENOUGH_DATA to ensure the user sees the frame as early as possible. |
405 // to ensure the user sees the frame as early as possible. | 407 if (!sink_started_ && algorithm_->frames_queued() && !painted_first_frame_) { |
406 if (!sink_started_ && algorithm_->frames_queued()) { | |
407 // We want to paint the first frame under two conditions: Either (1) we have | 408 // We want to paint the first frame under two conditions: Either (1) we have |
408 // enough frames to know it's definitely the first frame or (2) there may be | 409 // enough frames to know it's definitely the first frame or (2) there may be |
409 // no more frames coming (sometimes unless we paint one of them). | 410 // no more frames coming (sometimes unless we paint one of them). |
410 // | 411 // |
411 // For the first condition, we need at least two frames or the first frame | 412 // For the first condition, we need at least two frames or the first frame |
412 // must have a timestamp >= |start_timestamp_|, since otherwise we may be | 413 // must have a timestamp >= |start_timestamp_|, since otherwise we may be |
413 // prerolling frames before the actual start time that will be dropped. | 414 // prerolling frames before the actual start time that will be dropped. |
414 if (algorithm_->frames_queued() > 1 || received_end_of_stream_ || | 415 if (algorithm_->frames_queued() > 1 || received_end_of_stream_ || |
415 algorithm_->first_frame()->timestamp() >= start_timestamp_ || | 416 frame->timestamp() >= start_timestamp_ || low_delay_ || |
416 low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) { | 417 !video_frame_stream_->CanReadWithoutStalling()) { |
417 scoped_refptr<VideoFrame> frame = algorithm_->first_frame(); | 418 scoped_refptr<VideoFrame> first_frame = |
418 CheckForMetadataChanges(frame->format(), frame->natural_size()); | 419 algorithm_->Render(base::TimeTicks(), base::TimeTicks(), nullptr); |
419 sink_->PaintSingleFrame(frame); | 420 CheckForMetadataChanges(first_frame->format(), |
421 first_frame->natural_size()); | |
422 sink_->PaintSingleFrame(first_frame); | |
423 painted_first_frame_ = true; | |
420 } | 424 } |
421 } | 425 } |
422 | 426 |
423 // Signal buffering state if we've met our conditions. | 427 // Signal buffering state if we've met our conditions. |
424 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) | 428 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) |
425 TransitionToHaveEnough_Locked(); | 429 TransitionToHaveEnough_Locked(); |
426 | 430 |
427 // Always request more decoded video if we have capacity. | 431 // Always request more decoded video if we have capacity. |
428 AttemptRead_Locked(); | 432 AttemptRead_Locked(); |
429 } | 433 } |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
666 frames_dropped_ += algorithm_->RemoveExpiredFrames( | 670 frames_dropped_ += algorithm_->RemoveExpiredFrames( |
667 current_time + algorithm_->average_frame_duration()); | 671 current_time + algorithm_->average_frame_duration()); |
668 | 672 |
669 // If we've paused for underflow, and still have no effective frames, clear | 673 // If we've paused for underflow, and still have no effective frames, clear |
670 // the entire queue. Note: this may cause slight inaccuracies in the number | 674 // the entire queue. Note: this may cause slight inaccuracies in the number |
671 // of dropped frames since the frame may have been rendered before. | 675 // of dropped frames since the frame may have been rendered before. |
672 if (!sink_started_ && !algorithm_->effective_frames_queued()) { | 676 if (!sink_started_ && !algorithm_->effective_frames_queued()) { |
673 frames_dropped_ += algorithm_->frames_queued(); | 677 frames_dropped_ += algorithm_->frames_queued(); |
674 algorithm_->Reset( | 678 algorithm_->Reset( |
675 VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates); | 679 VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates); |
680 painted_first_frame_ = false; | |
chcunningham
2016/10/21 20:27:22
to be sure I follow, the idea of resetting here is
DaleCurtis
2016/10/21 21:51:17
Correct.
| |
676 | 681 |
677 // It's possible in the background rendering case for us to expire enough | 682 // It's possible in the background rendering case for us to expire enough |
678 // frames that we need to transition from HAVE_ENOUGH => HAVE_NOTHING. Just | 683 // frames that we need to transition from HAVE_ENOUGH => HAVE_NOTHING. Just |
679 // calling this function will check if we need to transition or not. | 684 // calling this function will check if we need to transition or not. |
680 if (buffering_state_ == BUFFERING_HAVE_ENOUGH) | 685 if (buffering_state_ == BUFFERING_HAVE_ENOUGH) |
681 TransitionToHaveNothing_Locked(); | 686 TransitionToHaveNothing_Locked(); |
682 } | 687 } |
683 } | 688 } |
684 | 689 |
685 void VideoRendererImpl::CheckForMetadataChanges(VideoPixelFormat pixel_format, | 690 void VideoRendererImpl::CheckForMetadataChanges(VideoPixelFormat pixel_format, |
(...skipping 18 matching lines...) Expand all Loading... | |
704 | 709 |
705 void VideoRendererImpl::AttemptReadAndCheckForMetadataChanges( | 710 void VideoRendererImpl::AttemptReadAndCheckForMetadataChanges( |
706 VideoPixelFormat pixel_format, | 711 VideoPixelFormat pixel_format, |
707 const gfx::Size& natural_size) { | 712 const gfx::Size& natural_size) { |
708 base::AutoLock auto_lock(lock_); | 713 base::AutoLock auto_lock(lock_); |
709 CheckForMetadataChanges(pixel_format, natural_size); | 714 CheckForMetadataChanges(pixel_format, natural_size); |
710 AttemptRead_Locked(); | 715 AttemptRead_Locked(); |
711 } | 716 } |
712 | 717 |
713 } // namespace media | 718 } // namespace media |
OLD | NEW |