| 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/filters/video_renderer_impl.h" | 5 #include "media/filters/video_renderer_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 callback.Run(); | 78 callback.Run(); |
| 79 return; | 79 return; |
| 80 } | 80 } |
| 81 | 81 |
| 82 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing | 82 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing |
| 83 // task-running guards that check |state_| with DCHECK(). | 83 // task-running guards that check |state_| with DCHECK(). |
| 84 | 84 |
| 85 state_ = kStopped; | 85 state_ = kStopped; |
| 86 | 86 |
| 87 statistics_cb_.Reset(); | 87 statistics_cb_.Reset(); |
| 88 max_time_cb_.Reset(); | |
| 89 DoStopOrError_Locked(); | 88 DoStopOrError_Locked(); |
| 90 | 89 |
| 91 // Clean up our thread if present. | 90 // Clean up our thread if present. |
| 92 base::PlatformThreadHandle thread_to_join = base::PlatformThreadHandle(); | 91 base::PlatformThreadHandle thread_to_join = base::PlatformThreadHandle(); |
| 93 if (!thread_.is_null()) { | 92 if (!thread_.is_null()) { |
| 94 // Signal the thread since it's possible to get stopped with the video | 93 // Signal the thread since it's possible to get stopped with the video |
| 95 // thread waiting for a read to complete. | 94 // thread waiting for a read to complete. |
| 96 frame_available_.Signal(); | 95 frame_available_.Signal(); |
| 97 std::swap(thread_, thread_to_join); | 96 std::swap(thread_, thread_to_join); |
| 98 } | 97 } |
| 99 | 98 |
| 100 if (!thread_to_join.is_null()) { | 99 if (!thread_to_join.is_null()) { |
| 101 base::AutoUnlock auto_unlock(lock_); | 100 base::AutoUnlock auto_unlock(lock_); |
| 102 base::PlatformThread::Join(thread_to_join); | 101 base::PlatformThread::Join(thread_to_join); |
| 103 } | 102 } |
| 104 | 103 |
| 105 video_frame_stream_.Stop(callback); | 104 video_frame_stream_.Stop(callback); |
| 106 } | 105 } |
| 107 | 106 |
| 108 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { | 107 void VideoRendererImpl::StartPlaying() { |
| 109 DCHECK(task_runner_->BelongsToCurrentThread()); | 108 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 110 base::AutoLock auto_lock(lock_); | 109 base::AutoLock auto_lock(lock_); |
| 111 DCHECK_EQ(state_, kFlushed); | 110 DCHECK_EQ(state_, kFlushed); |
| 112 DCHECK(!pending_read_); | 111 DCHECK(!pending_read_); |
| 113 DCHECK(ready_frames_.empty()); | 112 DCHECK(ready_frames_.empty()); |
| 114 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 113 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
| 115 | 114 |
| 116 state_ = kPlaying; | 115 state_ = kPlaying; |
| 117 start_timestamp_ = timestamp; | 116 start_timestamp_ = get_time_cb_.Run(); |
| 118 AttemptRead_Locked(); | 117 AttemptRead_Locked(); |
| 119 } | 118 } |
| 120 | 119 |
| 121 void VideoRendererImpl::Initialize(DemuxerStream* stream, | 120 void VideoRendererImpl::Initialize(DemuxerStream* stream, |
| 122 bool low_delay, | 121 bool low_delay, |
| 123 const PipelineStatusCB& init_cb, | 122 const PipelineStatusCB& init_cb, |
| 124 const StatisticsCB& statistics_cb, | 123 const StatisticsCB& statistics_cb, |
| 125 const TimeCB& max_time_cb, | |
| 126 const BufferingStateCB& buffering_state_cb, | 124 const BufferingStateCB& buffering_state_cb, |
| 127 const base::Closure& ended_cb, | 125 const base::Closure& ended_cb, |
| 128 const PipelineStatusCB& error_cb, | 126 const PipelineStatusCB& error_cb, |
| 129 const TimeDeltaCB& get_time_cb, | 127 const TimeDeltaCB& get_time_cb, |
| 130 const TimeDeltaCB& get_duration_cb) { | 128 const TimeDeltaCB& get_duration_cb) { |
| 131 DCHECK(task_runner_->BelongsToCurrentThread()); | 129 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 132 base::AutoLock auto_lock(lock_); | 130 base::AutoLock auto_lock(lock_); |
| 133 DCHECK(stream); | 131 DCHECK(stream); |
| 134 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); | 132 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); |
| 135 DCHECK(!init_cb.is_null()); | 133 DCHECK(!init_cb.is_null()); |
| 136 DCHECK(!statistics_cb.is_null()); | 134 DCHECK(!statistics_cb.is_null()); |
| 137 DCHECK(!max_time_cb.is_null()); | |
| 138 DCHECK(!buffering_state_cb.is_null()); | 135 DCHECK(!buffering_state_cb.is_null()); |
| 139 DCHECK(!ended_cb.is_null()); | 136 DCHECK(!ended_cb.is_null()); |
| 140 DCHECK(!get_time_cb.is_null()); | 137 DCHECK(!get_time_cb.is_null()); |
| 141 DCHECK(!get_duration_cb.is_null()); | 138 DCHECK(!get_duration_cb.is_null()); |
| 142 DCHECK_EQ(kUninitialized, state_); | 139 DCHECK_EQ(kUninitialized, state_); |
| 143 | 140 |
| 144 low_delay_ = low_delay; | 141 low_delay_ = low_delay; |
| 145 | 142 |
| 146 init_cb_ = init_cb; | 143 init_cb_ = init_cb; |
| 147 statistics_cb_ = statistics_cb; | 144 statistics_cb_ = statistics_cb; |
| 148 max_time_cb_ = max_time_cb; | |
| 149 buffering_state_cb_ = buffering_state_cb; | 145 buffering_state_cb_ = buffering_state_cb; |
| 150 ended_cb_ = ended_cb; | 146 ended_cb_ = ended_cb; |
| 151 error_cb_ = error_cb; | 147 error_cb_ = error_cb; |
| 152 get_time_cb_ = get_time_cb; | 148 get_time_cb_ = get_time_cb; |
| 153 get_duration_cb_ = get_duration_cb; | 149 get_duration_cb_ = get_duration_cb; |
| 154 state_ = kInitializing; | 150 state_ = kInitializing; |
| 155 | 151 |
| 156 video_frame_stream_.Initialize( | 152 video_frame_stream_.Initialize( |
| 157 stream, | 153 stream, |
| 158 low_delay, | 154 low_delay, |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 DCHECK_EQ(state_, kPlaying); | 359 DCHECK_EQ(state_, kPlaying); |
| 364 return received_end_of_stream_ || | 360 return received_end_of_stream_ || |
| 365 !video_frame_stream_.CanReadWithoutStalling() || | 361 !video_frame_stream_.CanReadWithoutStalling() || |
| 366 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) || | 362 ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) || |
| 367 (low_delay_ && ready_frames_.size() > 0); | 363 (low_delay_ && ready_frames_.size() > 0); |
| 368 } | 364 } |
| 369 | 365 |
| 370 void VideoRendererImpl::TransitionToHaveEnough_Locked() { | 366 void VideoRendererImpl::TransitionToHaveEnough_Locked() { |
| 371 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 367 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
| 372 | 368 |
| 373 if (received_end_of_stream_) | |
| 374 max_time_cb_.Run(get_duration_cb_.Run()); | |
| 375 | |
| 376 if (!ready_frames_.empty()) { | 369 if (!ready_frames_.empty()) { |
| 377 // Max time isn't reported while we're in a have nothing state as we could | |
| 378 // be discarding frames to find |start_timestamp_|. | |
| 379 if (!received_end_of_stream_) { | |
| 380 base::TimeDelta max_timestamp = ready_frames_[0]->timestamp(); | |
| 381 for (size_t i = 1; i < ready_frames_.size(); ++i) { | |
| 382 if (ready_frames_[i]->timestamp() > max_timestamp) | |
| 383 max_timestamp = ready_frames_[i]->timestamp(); | |
| 384 } | |
| 385 max_time_cb_.Run(max_timestamp); | |
| 386 } | |
| 387 | |
| 388 // Because the clock might remain paused in for an undetermined amount | 370 // Because the clock might remain paused in for an undetermined amount |
| 389 // of time (e.g., seeking while paused), paint the first frame. | 371 // of time (e.g., seeking while paused), paint the first frame. |
| 390 PaintNextReadyFrame_Locked(); | 372 PaintNextReadyFrame_Locked(); |
| 391 } | 373 } |
| 392 | 374 |
| 393 buffering_state_ = BUFFERING_HAVE_ENOUGH; | 375 buffering_state_ = BUFFERING_HAVE_ENOUGH; |
| 394 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); | 376 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); |
| 395 } | 377 } |
| 396 | 378 |
| 397 void VideoRendererImpl::AddReadyFrame_Locked( | 379 void VideoRendererImpl::AddReadyFrame_Locked( |
| 398 const scoped_refptr<VideoFrame>& frame) { | 380 const scoped_refptr<VideoFrame>& frame) { |
| 399 lock_.AssertAcquired(); | 381 lock_.AssertAcquired(); |
| 400 DCHECK(!frame->end_of_stream()); | 382 DCHECK(!frame->end_of_stream()); |
| 401 | 383 |
| 402 // Adjust the incoming frame if its rendering stop time is past the duration | 384 // Adjust the incoming frame if its rendering stop time is past the duration |
| 403 // of the video itself. This is typically the last frame of the video and | 385 // of the video itself. This is typically the last frame of the video and |
| 404 // occurs if the container specifies a duration that isn't a multiple of the | 386 // occurs if the container specifies a duration that isn't a multiple of the |
| 405 // frame rate. Another way for this to happen is for the container to state | 387 // frame rate. Another way for this to happen is for the container to state |
| 406 // a smaller duration than the largest packet timestamp. | 388 // a smaller duration than the largest packet timestamp. |
| 407 base::TimeDelta duration = get_duration_cb_.Run(); | 389 base::TimeDelta duration = get_duration_cb_.Run(); |
| 408 if (frame->timestamp() > duration) { | 390 if (frame->timestamp() > duration) { |
| 409 frame->set_timestamp(duration); | 391 frame->set_timestamp(duration); |
| 410 } | 392 } |
| 411 | 393 |
| 412 ready_frames_.push_back(frame); | 394 ready_frames_.push_back(frame); |
| 413 DCHECK_LE(ready_frames_.size(), | 395 DCHECK_LE(ready_frames_.size(), |
| 414 static_cast<size_t>(limits::kMaxVideoFrames)); | 396 static_cast<size_t>(limits::kMaxVideoFrames)); |
| 415 | 397 |
| 416 // FrameReady() may add frames but discard them when we're decoding frames to | |
| 417 // reach |start_timestamp_|. In this case we'll only want to update the max | |
| 418 // time when we know we've reached |start_timestamp_| and have buffered enough | |
| 419 // frames to being playback. | |
| 420 if (buffering_state_ == BUFFERING_HAVE_ENOUGH) | |
| 421 max_time_cb_.Run(frame->timestamp()); | |
| 422 | |
| 423 // Avoid needlessly waking up |thread_| unless playing. | 398 // Avoid needlessly waking up |thread_| unless playing. |
| 424 if (state_ == kPlaying) | 399 if (state_ == kPlaying) |
| 425 frame_available_.Signal(); | 400 frame_available_.Signal(); |
| 426 } | 401 } |
| 427 | 402 |
| 428 void VideoRendererImpl::AttemptRead() { | 403 void VideoRendererImpl::AttemptRead() { |
| 429 base::AutoLock auto_lock(lock_); | 404 base::AutoLock auto_lock(lock_); |
| 430 AttemptRead_Locked(); | 405 AttemptRead_Locked(); |
| 431 } | 406 } |
| 432 | 407 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 statistics_cb_.Run(statistics); | 466 statistics_cb_.Run(statistics); |
| 492 | 467 |
| 493 frames_decoded_ = 0; | 468 frames_decoded_ = 0; |
| 494 frames_dropped_ = 0; | 469 frames_dropped_ = 0; |
| 495 } | 470 } |
| 496 | 471 |
| 497 frame_available_.TimedWait(wait_duration); | 472 frame_available_.TimedWait(wait_duration); |
| 498 } | 473 } |
| 499 | 474 |
| 500 } // namespace media | 475 } // namespace media |
| OLD | NEW |