| 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" |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
| 15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 16 #include "base/time/default_tick_clock.h" | 16 #include "base/time/default_tick_clock.h" |
| 17 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" |
| 18 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
| 19 #include "media/base/limits.h" | 19 #include "media/base/limits.h" |
| 20 #include "media/base/media_log.h" | 20 #include "media/base/media_log.h" |
| 21 #include "media/base/media_switches.h" | 21 #include "media/base/media_switches.h" |
| 22 #include "media/base/pipeline_status.h" | 22 #include "media/base/pipeline_status.h" |
| 23 #include "media/base/renderer_client.h" | 23 #include "media/base/renderer_client.h" |
| 24 #include "media/base/stream_position.h" |
| 24 #include "media/base/video_frame.h" | 25 #include "media/base/video_frame.h" |
| 25 #include "media/renderers/gpu_video_accelerator_factories.h" | 26 #include "media/renderers/gpu_video_accelerator_factories.h" |
| 26 #include "media/video/gpu_memory_buffer_video_frame_pool.h" | 27 #include "media/video/gpu_memory_buffer_video_frame_pool.h" |
| 27 | 28 |
| 28 namespace media { | 29 namespace media { |
| 29 | 30 |
| 30 VideoRendererImpl::VideoRendererImpl( | 31 VideoRendererImpl::VideoRendererImpl( |
| 31 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 32 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| 32 const scoped_refptr<base::TaskRunner>& worker_task_runner, | 33 const scoped_refptr<base::TaskRunner>& worker_task_runner, |
| 33 VideoRendererSink* sink, | 34 VideoRendererSink* sink, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 44 media_log)), | 45 media_log)), |
| 45 gpu_memory_buffer_pool_(nullptr), | 46 gpu_memory_buffer_pool_(nullptr), |
| 46 media_log_(media_log), | 47 media_log_(media_log), |
| 47 low_delay_(false), | 48 low_delay_(false), |
| 48 received_end_of_stream_(false), | 49 received_end_of_stream_(false), |
| 49 rendered_end_of_stream_(false), | 50 rendered_end_of_stream_(false), |
| 50 state_(kUninitialized), | 51 state_(kUninitialized), |
| 51 pending_read_(false), | 52 pending_read_(false), |
| 52 drop_frames_(drop_frames), | 53 drop_frames_(drop_frames), |
| 53 buffering_state_(BUFFERING_HAVE_NOTHING), | 54 buffering_state_(BUFFERING_HAVE_NOTHING), |
| 55 start_rendering_from_first_frame_(false), |
| 54 frames_decoded_(0), | 56 frames_decoded_(0), |
| 55 frames_dropped_(0), | 57 frames_dropped_(0), |
| 56 tick_clock_(new base::DefaultTickClock()), | 58 tick_clock_(new base::DefaultTickClock()), |
| 57 was_background_rendering_(false), | 59 was_background_rendering_(false), |
| 58 time_progressing_(false), | 60 time_progressing_(false), |
| 59 last_video_memory_usage_(0), | 61 last_video_memory_usage_(0), |
| 60 have_renderered_frames_(false), | 62 have_renderered_frames_(false), |
| 61 last_frame_opaque_(false), | 63 last_frame_opaque_(false), |
| 62 weak_factory_(this), | 64 weak_factory_(this), |
| 63 frame_callback_weak_factory_(this) { | 65 frame_callback_weak_factory_(this) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone, | 111 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone, |
| 110 weak_factory_.GetWeakPtr())); | 112 weak_factory_.GetWeakPtr())); |
| 111 | 113 |
| 112 // To avoid unnecessary work by VDAs, only delete queued frames after | 114 // To avoid unnecessary work by VDAs, only delete queued frames after |
| 113 // resetting |video_frame_stream_|. If this is done in the opposite order VDAs | 115 // resetting |video_frame_stream_|. If this is done in the opposite order VDAs |
| 114 // will get a bunch of ReusePictureBuffer() calls before the Reset(), which | 116 // will get a bunch of ReusePictureBuffer() calls before the Reset(), which |
| 115 // they may use to output more frames that won't be used. | 117 // they may use to output more frames that won't be used. |
| 116 algorithm_->Reset(); | 118 algorithm_->Reset(); |
| 117 } | 119 } |
| 118 | 120 |
| 119 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { | 121 void VideoRendererImpl::StartPlayingFrom(StreamPosition position) { |
| 120 DVLOG(1) << __func__ << "(" << timestamp.InMicroseconds() << ")"; | 122 DVLOG(1) << __func__ << "(" << ToString(position) << ")"; |
| 121 DCHECK(task_runner_->BelongsToCurrentThread()); | 123 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 122 base::AutoLock auto_lock(lock_); | 124 base::AutoLock auto_lock(lock_); |
| 123 DCHECK_EQ(state_, kFlushed); | 125 DCHECK_EQ(state_, kFlushed); |
| 124 DCHECK(!pending_read_); | 126 DCHECK(!pending_read_); |
| 125 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 127 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
| 126 | 128 |
| 127 state_ = kPlaying; | 129 state_ = kPlaying; |
| 128 start_timestamp_ = timestamp; | 130 start_timestamp_ = position.time; |
| 131 start_rendering_from_first_frame_ = |
| 132 position.kind == StreamPosition::Kind::KEY_FRAME_PRECEDING_TIME; |
| 129 AttemptRead_Locked(); | 133 AttemptRead_Locked(); |
| 130 } | 134 } |
| 131 | 135 |
| 132 void VideoRendererImpl::Initialize( | 136 void VideoRendererImpl::Initialize( |
| 133 DemuxerStream* stream, | 137 DemuxerStream* stream, |
| 134 CdmContext* cdm_context, | 138 CdmContext* cdm_context, |
| 135 RendererClient* client, | 139 RendererClient* client, |
| 136 const TimeSource::WallClockTimeCB& wall_clock_time_cb, | 140 const TimeSource::WallClockTimeCB& wall_clock_time_cb, |
| 137 const PipelineStatusCB& init_cb) { | 141 const PipelineStatusCB& init_cb) { |
| 138 DCHECK(task_runner_->BelongsToCurrentThread()); | 142 DCHECK(task_runner_->BelongsToCurrentThread()); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 DCHECK(task_runner_->BelongsToCurrentThread()); | 234 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 231 base::AutoLock auto_lock(lock_); | 235 base::AutoLock auto_lock(lock_); |
| 232 DCHECK_EQ(state_, kInitializing); | 236 DCHECK_EQ(state_, kInitializing); |
| 233 | 237 |
| 234 if (!success) { | 238 if (!success) { |
| 235 state_ = kUninitialized; | 239 state_ = kUninitialized; |
| 236 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 240 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
| 237 return; | 241 return; |
| 238 } | 242 } |
| 239 | 243 |
| 240 // We're all good! Consider ourselves flushed. (ThreadMain() should never | 244 // We're all good! Consider ourselves flushed because we have not populated |
| 241 // see us in the kUninitialized state). | 245 // any buffers yet. |
| 242 // Since we had an initial Preroll(), we consider ourself flushed, because we | |
| 243 // have not populated any buffers yet. | |
| 244 state_ = kFlushed; | 246 state_ = kFlushed; |
| 245 | 247 |
| 246 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_)); | 248 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_)); |
| 247 if (!drop_frames_) | 249 if (!drop_frames_) |
| 248 algorithm_->disable_frame_dropping(); | 250 algorithm_->disable_frame_dropping(); |
| 249 | 251 |
| 250 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 252 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 251 } | 253 } |
| 252 | 254 |
| 253 void VideoRendererImpl::OnPlaybackError(PipelineStatus error) { | 255 void VideoRendererImpl::OnPlaybackError(PipelineStatus error) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 | 359 |
| 358 // Can happen when demuxers are preparing for a new Seek(). | 360 // Can happen when demuxers are preparing for a new Seek(). |
| 359 if (!frame) { | 361 if (!frame) { |
| 360 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED); | 362 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED); |
| 361 return; | 363 return; |
| 362 } | 364 } |
| 363 | 365 |
| 364 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) { | 366 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) { |
| 365 DCHECK(!received_end_of_stream_); | 367 DCHECK(!received_end_of_stream_); |
| 366 received_end_of_stream_ = true; | 368 received_end_of_stream_ = true; |
| 369 } else if (start_rendering_from_first_frame_) { |
| 370 start_timestamp_ = frame->timestamp(); |
| 371 start_rendering_from_first_frame_ = false; |
| 372 client_->OnFirstVideoFrameTimestampKnown(frame->timestamp()); |
| 373 AddReadyFrame_Locked(frame); |
| 367 } else if ((low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) && | 374 } else if ((low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) && |
| 368 IsBeforeStartTime(frame->timestamp())) { | 375 IsBeforeStartTime(frame->timestamp())) { |
| 369 // Don't accumulate frames that are earlier than the start time if we | 376 // Don't accumulate frames that are earlier than the start time if we |
| 370 // won't have a chance for a better frame, otherwise we could declare | 377 // won't have a chance for a better frame, otherwise we could declare |
| 371 // HAVE_ENOUGH_DATA and start playback prematurely. | 378 // HAVE_ENOUGH_DATA and start playback prematurely. |
| 372 AttemptRead_Locked(); | 379 AttemptRead_Locked(); |
| 373 return; | 380 return; |
| 374 } else { | 381 } else { |
| 375 // If the sink hasn't been started, we still have time to release less | 382 // If the sink hasn't been started, we still have time to release less |
| 376 // than ideal frames prior to startup. We don't use IsBeforeStartTime() | 383 // than ideal frames prior to startup. We don't use IsBeforeStartTime() |
| 377 // here since it's based on a duration estimate and we can be exact here. | 384 // here since it's based on a duration estimate and we can be exact here. |
| 378 if (!sink_started_ && frame->timestamp() <= start_timestamp_) | 385 if (!sink_started_ && frame->timestamp() <= start_timestamp_) { |
| 379 algorithm_->Reset(); | 386 algorithm_->Reset(); |
| 387 } |
| 380 | 388 |
| 381 AddReadyFrame_Locked(frame); | 389 AddReadyFrame_Locked(frame); |
| 382 } | 390 } |
| 383 | 391 |
| 384 // Attempt to purge bad frames in case of underflow or backgrounding. | 392 // Attempt to purge bad frames in case of underflow or backgrounding. |
| 385 RemoveFramesForUnderflowOrBackgroundRendering(); | 393 RemoveFramesForUnderflowOrBackgroundRendering(); |
| 386 | 394 |
| 387 // We may have removed all frames above and have reached end of stream. | 395 // We may have removed all frames above and have reached end of stream. |
| 388 MaybeFireEndedCallback_Locked(time_progressing_); | 396 MaybeFireEndedCallback_Locked(time_progressing_); |
| 389 | 397 |
| 390 // Update statistics here instead of during Render() when the sink is stopped. | 398 // Update statistics here instead of during Render() when the sink is stopped. |
| 391 if (!sink_started_) | 399 if (!sink_started_) |
| 392 UpdateStats_Locked(); | 400 UpdateStats_Locked(); |
| 393 | 401 |
| 394 // Paint the first frame if possible and necessary. PaintSingleFrame() will | 402 // Paint the first frame if possible and necessary. PaintSingleFrame() will |
| 395 // ignore repeated calls for the same frame. Paint ahead of HAVE_ENOUGH_DATA | 403 // ignore repeated calls for the same frame. Paint ahead of HAVE_ENOUGH_DATA |
| 396 // to ensure the user sees the frame as early as possible. | 404 // to ensure the user sees the frame as early as possible. |
| 397 if (!sink_started_ && algorithm_->frames_queued()) { | 405 if (!sink_started_ && algorithm_->frames_queued()) { |
| 398 // We want to paint the first frame under two conditions: Either (1) we have | 406 // We want to paint the first frame under two conditions: Either (1) we have |
| 399 // enough frames to know it's definitely the first frame or (2) there may be | 407 // enough frames to know it's definitely the first frame or (2) there may be |
| 400 // no more frames coming (sometimes unless we paint one of them). | 408 // no more frames coming (sometimes unless we paint one of them). |
| 401 // | 409 // |
| 402 // For the first condition, we need at least two frames or the first frame | |
| 403 // must have a timestamp >= |start_timestamp_|, since otherwise we may be | |
| 404 // prerolling frames before the actual start time that will be dropped. | |
| 405 if (algorithm_->frames_queued() > 1 || received_end_of_stream_ || | 410 if (algorithm_->frames_queued() > 1 || received_end_of_stream_ || |
| 406 algorithm_->first_frame()->timestamp() >= start_timestamp_ || | 411 algorithm_->first_frame()->timestamp() >= start_timestamp_ || |
| 407 low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) { | 412 low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) { |
| 408 scoped_refptr<VideoFrame> frame = algorithm_->first_frame(); | 413 scoped_refptr<VideoFrame> frame = algorithm_->first_frame(); |
| 409 CheckForMetadataChanges(frame->format(), frame->natural_size()); | 414 CheckForMetadataChanges(frame->format(), frame->natural_size()); |
| 410 sink_->PaintSingleFrame(frame); | 415 sink_->PaintSingleFrame(frame); |
| 411 } | 416 } |
| 412 } | 417 } |
| 413 | 418 |
| 414 // Signal buffering state if we've met our conditions. | 419 // Signal buffering state if we've met our conditions. |
| 415 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) | 420 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) |
| 416 TransitionToHaveEnough_Locked(); | 421 TransitionToHaveEnough_Locked(); |
| 417 | 422 |
| 418 // Always request more decoded video if we have capacity. This serves two | 423 // Always request more decoded video if we have capacity. |
| 419 // purposes: | |
| 420 // 1) Prerolling while paused | |
| 421 // 2) Keeps decoding going if video rendering thread starts falling behind | |
| 422 AttemptRead_Locked(); | 424 AttemptRead_Locked(); |
| 423 } | 425 } |
| 424 | 426 |
| 425 bool VideoRendererImpl::HaveEnoughData_Locked() { | 427 bool VideoRendererImpl::HaveEnoughData_Locked() { |
| 426 DCHECK_EQ(state_, kPlaying); | 428 DCHECK_EQ(state_, kPlaying); |
| 427 lock_.AssertAcquired(); | 429 lock_.AssertAcquired(); |
| 428 | 430 |
| 429 if (received_end_of_stream_) | 431 if (received_end_of_stream_) |
| 430 return true; | 432 return true; |
| 431 | 433 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 return wall_clock_times[0]; | 618 return wall_clock_times[0]; |
| 617 } | 619 } |
| 618 | 620 |
| 619 base::TimeTicks VideoRendererImpl::GetCurrentMediaTimeAsWallClockTime() { | 621 base::TimeTicks VideoRendererImpl::GetCurrentMediaTimeAsWallClockTime() { |
| 620 std::vector<base::TimeTicks> current_time; | 622 std::vector<base::TimeTicks> current_time; |
| 621 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), ¤t_time); | 623 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), ¤t_time); |
| 622 return current_time[0]; | 624 return current_time[0]; |
| 623 } | 625 } |
| 624 | 626 |
| 625 bool VideoRendererImpl::IsBeforeStartTime(base::TimeDelta timestamp) { | 627 bool VideoRendererImpl::IsBeforeStartTime(base::TimeDelta timestamp) { |
| 628 if (start_rendering_from_first_frame_) |
| 629 return false; |
| 626 return timestamp + video_frame_stream_->AverageDuration() < start_timestamp_; | 630 return timestamp + video_frame_stream_->AverageDuration() < start_timestamp_; |
| 627 } | 631 } |
| 628 | 632 |
| 629 void VideoRendererImpl::RemoveFramesForUnderflowOrBackgroundRendering() { | 633 void VideoRendererImpl::RemoveFramesForUnderflowOrBackgroundRendering() { |
| 630 // Nothing to do if we're not underflowing, background rendering, or frame | 634 // Nothing to do if we're not underflowing, background rendering, or frame |
| 631 // dropping is disabled (test only). | 635 // dropping is disabled (test only). |
| 632 const bool have_nothing = buffering_state_ == BUFFERING_HAVE_NOTHING; | 636 const bool have_nothing = buffering_state_ == BUFFERING_HAVE_NOTHING; |
| 633 if (!was_background_rendering_ && !have_nothing && !drop_frames_) | 637 if (!was_background_rendering_ && !have_nothing && !drop_frames_) |
| 634 return; | 638 return; |
| 635 | 639 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 | 702 |
| 699 void VideoRendererImpl::AttemptReadAndCheckForMetadataChanges( | 703 void VideoRendererImpl::AttemptReadAndCheckForMetadataChanges( |
| 700 VideoPixelFormat pixel_format, | 704 VideoPixelFormat pixel_format, |
| 701 const gfx::Size& natural_size) { | 705 const gfx::Size& natural_size) { |
| 702 base::AutoLock auto_lock(lock_); | 706 base::AutoLock auto_lock(lock_); |
| 703 CheckForMetadataChanges(pixel_format, natural_size); | 707 CheckForMetadataChanges(pixel_format, natural_size); |
| 704 AttemptRead_Locked(); | 708 AttemptRead_Locked(); |
| 705 } | 709 } |
| 706 | 710 |
| 707 } // namespace media | 711 } // namespace media |
| OLD | NEW |