| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_base.h" | 5 #include "media/filters/video_renderer_base.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/message_loop/message_loop.h" | 10 #include "base/location.h" |
| 11 #include "base/single_thread_task_runner.h" |
| 11 #include "base/threading/platform_thread.h" | 12 #include "base/threading/platform_thread.h" |
| 12 #include "media/base/buffers.h" | 13 #include "media/base/buffers.h" |
| 13 #include "media/base/limits.h" | 14 #include "media/base/limits.h" |
| 14 #include "media/base/pipeline.h" | 15 #include "media/base/pipeline.h" |
| 15 #include "media/base/video_frame.h" | 16 #include "media/base/video_frame.h" |
| 16 | 17 |
| 17 namespace media { | 18 namespace media { |
| 18 | 19 |
| 19 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() { | 20 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() { |
| 20 return base::TimeDelta::FromMilliseconds(250); | 21 return base::TimeDelta::FromMilliseconds(250); |
| 21 } | 22 } |
| 22 | 23 |
| 23 VideoRendererBase::VideoRendererBase( | 24 VideoRendererBase::VideoRendererBase( |
| 24 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 25 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 25 ScopedVector<VideoDecoder> decoders, | 26 ScopedVector<VideoDecoder> decoders, |
| 26 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 27 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
| 27 const PaintCB& paint_cb, | 28 const PaintCB& paint_cb, |
| 28 const SetOpaqueCB& set_opaque_cb, | 29 const SetOpaqueCB& set_opaque_cb, |
| 29 bool drop_frames) | 30 bool drop_frames) |
| 30 : message_loop_(message_loop), | 31 : task_runner_(task_runner), |
| 31 weak_factory_(this), | 32 weak_factory_(this), |
| 32 video_frame_stream_( | 33 video_frame_stream_( |
| 33 message_loop, decoders.Pass(), set_decryptor_ready_cb), | 34 task_runner, decoders.Pass(), set_decryptor_ready_cb), |
| 34 received_end_of_stream_(false), | 35 received_end_of_stream_(false), |
| 35 frame_available_(&lock_), | 36 frame_available_(&lock_), |
| 36 state_(kUninitialized), | 37 state_(kUninitialized), |
| 37 thread_(), | 38 thread_(), |
| 38 pending_read_(false), | 39 pending_read_(false), |
| 39 drop_frames_(drop_frames), | 40 drop_frames_(drop_frames), |
| 40 playback_rate_(0), | 41 playback_rate_(0), |
| 41 paint_cb_(paint_cb), | 42 paint_cb_(paint_cb), |
| 42 set_opaque_cb_(set_opaque_cb), | 43 set_opaque_cb_(set_opaque_cb), |
| 43 last_timestamp_(kNoTimestamp()), | 44 last_timestamp_(kNoTimestamp()), |
| 44 frames_decoded_(0), | 45 frames_decoded_(0), |
| 45 frames_dropped_(0) { | 46 frames_dropped_(0) { |
| 46 DCHECK(!paint_cb_.is_null()); | 47 DCHECK(!paint_cb_.is_null()); |
| 47 } | 48 } |
| 48 | 49 |
| 49 VideoRendererBase::~VideoRendererBase() { | 50 VideoRendererBase::~VideoRendererBase() { |
| 50 base::AutoLock auto_lock(lock_); | 51 base::AutoLock auto_lock(lock_); |
| 51 CHECK(state_ == kStopped || state_ == kUninitialized) << state_; | 52 CHECK(state_ == kStopped || state_ == kUninitialized) << state_; |
| 52 CHECK(thread_.is_null()); | 53 CHECK(thread_.is_null()); |
| 53 } | 54 } |
| 54 | 55 |
| 55 void VideoRendererBase::Play(const base::Closure& callback) { | 56 void VideoRendererBase::Play(const base::Closure& callback) { |
| 56 DCHECK(message_loop_->BelongsToCurrentThread()); | 57 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 57 base::AutoLock auto_lock(lock_); | 58 base::AutoLock auto_lock(lock_); |
| 58 DCHECK_EQ(kPrerolled, state_); | 59 DCHECK_EQ(kPrerolled, state_); |
| 59 state_ = kPlaying; | 60 state_ = kPlaying; |
| 60 callback.Run(); | 61 callback.Run(); |
| 61 } | 62 } |
| 62 | 63 |
| 63 void VideoRendererBase::Pause(const base::Closure& callback) { | 64 void VideoRendererBase::Pause(const base::Closure& callback) { |
| 64 DCHECK(message_loop_->BelongsToCurrentThread()); | 65 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 65 base::AutoLock auto_lock(lock_); | 66 base::AutoLock auto_lock(lock_); |
| 66 DCHECK(state_ != kUninitialized || state_ == kError); | 67 DCHECK(state_ != kUninitialized || state_ == kError); |
| 67 state_ = kPaused; | 68 state_ = kPaused; |
| 68 callback.Run(); | 69 callback.Run(); |
| 69 } | 70 } |
| 70 | 71 |
| 71 void VideoRendererBase::Flush(const base::Closure& callback) { | 72 void VideoRendererBase::Flush(const base::Closure& callback) { |
| 72 DCHECK(message_loop_->BelongsToCurrentThread()); | 73 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 73 base::AutoLock auto_lock(lock_); | 74 base::AutoLock auto_lock(lock_); |
| 74 DCHECK_EQ(state_, kPaused); | 75 DCHECK_EQ(state_, kPaused); |
| 75 flush_cb_ = callback; | 76 flush_cb_ = callback; |
| 76 state_ = kFlushing; | 77 state_ = kFlushing; |
| 77 | 78 |
| 78 // This is necessary if the |video_frame_stream_| has already seen an end of | 79 // This is necessary if the |video_frame_stream_| has already seen an end of |
| 79 // stream and needs to drain it before flushing it. | 80 // stream and needs to drain it before flushing it. |
| 80 ready_frames_.clear(); | 81 ready_frames_.clear(); |
| 81 received_end_of_stream_ = false; | 82 received_end_of_stream_ = false; |
| 82 video_frame_stream_.Reset(base::Bind( | 83 video_frame_stream_.Reset(base::Bind( |
| 83 &VideoRendererBase::OnVideoFrameStreamResetDone, weak_this_)); | 84 &VideoRendererBase::OnVideoFrameStreamResetDone, weak_this_)); |
| 84 } | 85 } |
| 85 | 86 |
| 86 void VideoRendererBase::Stop(const base::Closure& callback) { | 87 void VideoRendererBase::Stop(const base::Closure& callback) { |
| 87 DCHECK(message_loop_->BelongsToCurrentThread()); | 88 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 88 base::AutoLock auto_lock(lock_); | 89 base::AutoLock auto_lock(lock_); |
| 89 if (state_ == kUninitialized || state_ == kStopped) { | 90 if (state_ == kUninitialized || state_ == kStopped) { |
| 90 callback.Run(); | 91 callback.Run(); |
| 91 return; | 92 return; |
| 92 } | 93 } |
| 93 | 94 |
| 94 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing | 95 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing |
| 95 // task-running guards that check |state_| with DCHECK(). | 96 // task-running guards that check |state_| with DCHECK(). |
| 96 | 97 |
| 97 state_ = kStopped; | 98 state_ = kStopped; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 111 | 112 |
| 112 if (!thread_to_join.is_null()) { | 113 if (!thread_to_join.is_null()) { |
| 113 base::AutoUnlock auto_unlock(lock_); | 114 base::AutoUnlock auto_unlock(lock_); |
| 114 base::PlatformThread::Join(thread_to_join); | 115 base::PlatformThread::Join(thread_to_join); |
| 115 } | 116 } |
| 116 | 117 |
| 117 video_frame_stream_.Stop(callback); | 118 video_frame_stream_.Stop(callback); |
| 118 } | 119 } |
| 119 | 120 |
| 120 void VideoRendererBase::SetPlaybackRate(float playback_rate) { | 121 void VideoRendererBase::SetPlaybackRate(float playback_rate) { |
| 121 DCHECK(message_loop_->BelongsToCurrentThread()); | 122 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 122 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
| 123 playback_rate_ = playback_rate; | 124 playback_rate_ = playback_rate; |
| 124 } | 125 } |
| 125 | 126 |
| 126 void VideoRendererBase::Preroll(base::TimeDelta time, | 127 void VideoRendererBase::Preroll(base::TimeDelta time, |
| 127 const PipelineStatusCB& cb) { | 128 const PipelineStatusCB& cb) { |
| 128 DCHECK(message_loop_->BelongsToCurrentThread()); | 129 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 129 base::AutoLock auto_lock(lock_); | 130 base::AutoLock auto_lock(lock_); |
| 130 DCHECK_EQ(state_, kFlushed) << "Must flush prior to prerolling."; | 131 DCHECK_EQ(state_, kFlushed) << "Must flush prior to prerolling."; |
| 131 DCHECK(!cb.is_null()); | 132 DCHECK(!cb.is_null()); |
| 132 DCHECK(preroll_cb_.is_null()); | 133 DCHECK(preroll_cb_.is_null()); |
| 133 | 134 |
| 134 state_ = kPrerolling; | 135 state_ = kPrerolling; |
| 135 preroll_cb_ = cb; | 136 preroll_cb_ = cb; |
| 136 preroll_timestamp_ = time; | 137 preroll_timestamp_ = time; |
| 137 AttemptRead_Locked(); | 138 AttemptRead_Locked(); |
| 138 } | 139 } |
| 139 | 140 |
| 140 void VideoRendererBase::Initialize(DemuxerStream* stream, | 141 void VideoRendererBase::Initialize(DemuxerStream* stream, |
| 141 const PipelineStatusCB& init_cb, | 142 const PipelineStatusCB& init_cb, |
| 142 const StatisticsCB& statistics_cb, | 143 const StatisticsCB& statistics_cb, |
| 143 const TimeCB& max_time_cb, | 144 const TimeCB& max_time_cb, |
| 144 const NaturalSizeChangedCB& size_changed_cb, | 145 const NaturalSizeChangedCB& size_changed_cb, |
| 145 const base::Closure& ended_cb, | 146 const base::Closure& ended_cb, |
| 146 const PipelineStatusCB& error_cb, | 147 const PipelineStatusCB& error_cb, |
| 147 const TimeDeltaCB& get_time_cb, | 148 const TimeDeltaCB& get_time_cb, |
| 148 const TimeDeltaCB& get_duration_cb) { | 149 const TimeDeltaCB& get_duration_cb) { |
| 149 DCHECK(message_loop_->BelongsToCurrentThread()); | 150 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 150 base::AutoLock auto_lock(lock_); | 151 base::AutoLock auto_lock(lock_); |
| 151 DCHECK(stream); | 152 DCHECK(stream); |
| 152 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); | 153 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); |
| 153 DCHECK(!init_cb.is_null()); | 154 DCHECK(!init_cb.is_null()); |
| 154 DCHECK(!statistics_cb.is_null()); | 155 DCHECK(!statistics_cb.is_null()); |
| 155 DCHECK(!max_time_cb.is_null()); | 156 DCHECK(!max_time_cb.is_null()); |
| 156 DCHECK(!size_changed_cb.is_null()); | 157 DCHECK(!size_changed_cb.is_null()); |
| 157 DCHECK(!ended_cb.is_null()); | 158 DCHECK(!ended_cb.is_null()); |
| 158 DCHECK(!get_time_cb.is_null()); | 159 DCHECK(!get_time_cb.is_null()); |
| 159 DCHECK(!get_duration_cb.is_null()); | 160 DCHECK(!get_duration_cb.is_null()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 172 | 173 |
| 173 video_frame_stream_.Initialize( | 174 video_frame_stream_.Initialize( |
| 174 stream, | 175 stream, |
| 175 statistics_cb, | 176 statistics_cb, |
| 176 base::Bind(&VideoRendererBase::OnVideoFrameStreamInitialized, | 177 base::Bind(&VideoRendererBase::OnVideoFrameStreamInitialized, |
| 177 weak_this_)); | 178 weak_this_)); |
| 178 } | 179 } |
| 179 | 180 |
| 180 void VideoRendererBase::OnVideoFrameStreamInitialized(bool success, | 181 void VideoRendererBase::OnVideoFrameStreamInitialized(bool success, |
| 181 bool has_alpha) { | 182 bool has_alpha) { |
| 182 DCHECK(message_loop_->BelongsToCurrentThread()); | 183 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 183 base::AutoLock auto_lock(lock_); | 184 base::AutoLock auto_lock(lock_); |
| 184 | 185 |
| 185 if (state_ == kStopped) | 186 if (state_ == kStopped) |
| 186 return; | 187 return; |
| 187 | 188 |
| 188 DCHECK_EQ(state_, kInitializing); | 189 DCHECK_EQ(state_, kInitializing); |
| 189 | 190 |
| 190 if (!success) { | 191 if (!success) { |
| 191 state_ = kUninitialized; | 192 state_ = kUninitialized; |
| 192 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 193 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 last_timestamp_ = next_frame->GetTimestamp(); | 310 last_timestamp_ = next_frame->GetTimestamp(); |
| 310 | 311 |
| 311 const gfx::Size& natural_size = next_frame->natural_size(); | 312 const gfx::Size& natural_size = next_frame->natural_size(); |
| 312 if (natural_size != last_natural_size_) { | 313 if (natural_size != last_natural_size_) { |
| 313 last_natural_size_ = natural_size; | 314 last_natural_size_ = natural_size; |
| 314 size_changed_cb_.Run(natural_size); | 315 size_changed_cb_.Run(natural_size); |
| 315 } | 316 } |
| 316 | 317 |
| 317 paint_cb_.Run(next_frame); | 318 paint_cb_.Run(next_frame); |
| 318 | 319 |
| 319 message_loop_->PostTask(FROM_HERE, base::Bind( | 320 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 320 &VideoRendererBase::AttemptRead, weak_this_)); | 321 &VideoRendererBase::AttemptRead, weak_this_)); |
| 321 } | 322 } |
| 322 | 323 |
| 323 void VideoRendererBase::DropNextReadyFrame_Locked() { | 324 void VideoRendererBase::DropNextReadyFrame_Locked() { |
| 324 lock_.AssertAcquired(); | 325 lock_.AssertAcquired(); |
| 325 | 326 |
| 326 last_timestamp_ = ready_frames_.front()->GetTimestamp(); | 327 last_timestamp_ = ready_frames_.front()->GetTimestamp(); |
| 327 ready_frames_.pop_front(); | 328 ready_frames_.pop_front(); |
| 328 frames_decoded_++; | 329 frames_decoded_++; |
| 329 frames_dropped_++; | 330 frames_dropped_++; |
| 330 | 331 |
| 331 message_loop_->PostTask(FROM_HERE, base::Bind( | 332 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 332 &VideoRendererBase::AttemptRead, weak_this_)); | 333 &VideoRendererBase::AttemptRead, weak_this_)); |
| 333 } | 334 } |
| 334 | 335 |
| 335 void VideoRendererBase::FrameReady(VideoFrameStream::Status status, | 336 void VideoRendererBase::FrameReady(VideoFrameStream::Status status, |
| 336 const scoped_refptr<VideoFrame>& frame) { | 337 const scoped_refptr<VideoFrame>& frame) { |
| 337 base::AutoLock auto_lock(lock_); | 338 base::AutoLock auto_lock(lock_); |
| 338 DCHECK_NE(state_, kUninitialized); | 339 DCHECK_NE(state_, kUninitialized); |
| 339 DCHECK_NE(state_, kFlushed); | 340 DCHECK_NE(state_, kFlushed); |
| 340 | 341 |
| 341 CHECK(pending_read_); | 342 CHECK(pending_read_); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 if (state_ == kPlaying) | 431 if (state_ == kPlaying) |
| 431 frame_available_.Signal(); | 432 frame_available_.Signal(); |
| 432 } | 433 } |
| 433 | 434 |
| 434 void VideoRendererBase::AttemptRead() { | 435 void VideoRendererBase::AttemptRead() { |
| 435 base::AutoLock auto_lock(lock_); | 436 base::AutoLock auto_lock(lock_); |
| 436 AttemptRead_Locked(); | 437 AttemptRead_Locked(); |
| 437 } | 438 } |
| 438 | 439 |
| 439 void VideoRendererBase::AttemptRead_Locked() { | 440 void VideoRendererBase::AttemptRead_Locked() { |
| 440 DCHECK(message_loop_->BelongsToCurrentThread()); | 441 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 441 lock_.AssertAcquired(); | 442 lock_.AssertAcquired(); |
| 442 | 443 |
| 443 if (pending_read_ || received_end_of_stream_ || | 444 if (pending_read_ || received_end_of_stream_ || |
| 444 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) { | 445 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) { |
| 445 return; | 446 return; |
| 446 } | 447 } |
| 447 | 448 |
| 448 switch (state_) { | 449 switch (state_) { |
| 449 case kPaused: | 450 case kPaused: |
| 450 case kPrerolling: | 451 case kPrerolling: |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 statistics_cb_.Run(statistics); | 529 statistics_cb_.Run(statistics); |
| 529 | 530 |
| 530 frames_decoded_ = 0; | 531 frames_decoded_ = 0; |
| 531 frames_dropped_ = 0; | 532 frames_dropped_ = 0; |
| 532 } | 533 } |
| 533 | 534 |
| 534 frame_available_.TimedWait(wait_duration); | 535 frame_available_.TimedWait(wait_duration); |
| 535 } | 536 } |
| 536 | 537 |
| 537 } // namespace media | 538 } // namespace media |
| OLD | NEW |