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" |
11 #include "base/message_loop/message_loop.h" | 11 #include "base/location.h" |
| 12 #include "base/single_thread_task_runner.h" |
12 #include "base/threading/platform_thread.h" | 13 #include "base/threading/platform_thread.h" |
13 #include "media/base/buffers.h" | 14 #include "media/base/buffers.h" |
14 #include "media/base/limits.h" | 15 #include "media/base/limits.h" |
15 #include "media/base/pipeline.h" | 16 #include "media/base/pipeline.h" |
16 #include "media/base/video_frame.h" | 17 #include "media/base/video_frame.h" |
17 | 18 |
18 namespace media { | 19 namespace media { |
19 | 20 |
20 base::TimeDelta VideoRendererImpl::kMaxLastFrameDuration() { | 21 base::TimeDelta VideoRendererImpl::kMaxLastFrameDuration() { |
21 return base::TimeDelta::FromMilliseconds(250); | 22 return base::TimeDelta::FromMilliseconds(250); |
22 } | 23 } |
23 | 24 |
24 VideoRendererImpl::VideoRendererImpl( | 25 VideoRendererImpl::VideoRendererImpl( |
25 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 26 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
26 ScopedVector<VideoDecoder> decoders, | 27 ScopedVector<VideoDecoder> decoders, |
27 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 28 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
28 const PaintCB& paint_cb, | 29 const PaintCB& paint_cb, |
29 const SetOpaqueCB& set_opaque_cb, | 30 const SetOpaqueCB& set_opaque_cb, |
30 bool drop_frames) | 31 bool drop_frames) |
31 : message_loop_(message_loop), | 32 : task_runner_(task_runner), |
32 weak_factory_(this), | 33 weak_factory_(this), |
33 video_frame_stream_( | 34 video_frame_stream_( |
34 message_loop, decoders.Pass(), set_decryptor_ready_cb), | 35 task_runner, decoders.Pass(), set_decryptor_ready_cb), |
35 received_end_of_stream_(false), | 36 received_end_of_stream_(false), |
36 frame_available_(&lock_), | 37 frame_available_(&lock_), |
37 state_(kUninitialized), | 38 state_(kUninitialized), |
38 thread_(), | 39 thread_(), |
39 pending_read_(false), | 40 pending_read_(false), |
40 drop_frames_(drop_frames), | 41 drop_frames_(drop_frames), |
41 playback_rate_(0), | 42 playback_rate_(0), |
42 paint_cb_(paint_cb), | 43 paint_cb_(paint_cb), |
43 set_opaque_cb_(set_opaque_cb), | 44 set_opaque_cb_(set_opaque_cb), |
44 last_timestamp_(kNoTimestamp()), | 45 last_timestamp_(kNoTimestamp()), |
45 frames_decoded_(0), | 46 frames_decoded_(0), |
46 frames_dropped_(0) { | 47 frames_dropped_(0) { |
47 DCHECK(!paint_cb_.is_null()); | 48 DCHECK(!paint_cb_.is_null()); |
48 } | 49 } |
49 | 50 |
50 VideoRendererImpl::~VideoRendererImpl() { | 51 VideoRendererImpl::~VideoRendererImpl() { |
51 base::AutoLock auto_lock(lock_); | 52 base::AutoLock auto_lock(lock_); |
52 CHECK(state_ == kStopped || state_ == kUninitialized) << state_; | 53 CHECK(state_ == kStopped || state_ == kUninitialized) << state_; |
53 CHECK(thread_.is_null()); | 54 CHECK(thread_.is_null()); |
54 } | 55 } |
55 | 56 |
56 void VideoRendererImpl::Play(const base::Closure& callback) { | 57 void VideoRendererImpl::Play(const base::Closure& callback) { |
57 DCHECK(message_loop_->BelongsToCurrentThread()); | 58 DCHECK(task_runner_->BelongsToCurrentThread()); |
58 base::AutoLock auto_lock(lock_); | 59 base::AutoLock auto_lock(lock_); |
59 DCHECK_EQ(kPrerolled, state_); | 60 DCHECK_EQ(kPrerolled, state_); |
60 state_ = kPlaying; | 61 state_ = kPlaying; |
61 callback.Run(); | 62 callback.Run(); |
62 } | 63 } |
63 | 64 |
64 void VideoRendererImpl::Pause(const base::Closure& callback) { | 65 void VideoRendererImpl::Pause(const base::Closure& callback) { |
65 DCHECK(message_loop_->BelongsToCurrentThread()); | 66 DCHECK(task_runner_->BelongsToCurrentThread()); |
66 base::AutoLock auto_lock(lock_); | 67 base::AutoLock auto_lock(lock_); |
67 DCHECK(state_ != kUninitialized || state_ == kError); | 68 DCHECK(state_ != kUninitialized || state_ == kError); |
68 state_ = kPaused; | 69 state_ = kPaused; |
69 callback.Run(); | 70 callback.Run(); |
70 } | 71 } |
71 | 72 |
72 void VideoRendererImpl::Flush(const base::Closure& callback) { | 73 void VideoRendererImpl::Flush(const base::Closure& callback) { |
73 DCHECK(message_loop_->BelongsToCurrentThread()); | 74 DCHECK(task_runner_->BelongsToCurrentThread()); |
74 base::AutoLock auto_lock(lock_); | 75 base::AutoLock auto_lock(lock_); |
75 DCHECK_EQ(state_, kPaused); | 76 DCHECK_EQ(state_, kPaused); |
76 flush_cb_ = callback; | 77 flush_cb_ = callback; |
77 state_ = kFlushing; | 78 state_ = kFlushing; |
78 | 79 |
79 // This is necessary if the |video_frame_stream_| has already seen an end of | 80 // This is necessary if the |video_frame_stream_| has already seen an end of |
80 // stream and needs to drain it before flushing it. | 81 // stream and needs to drain it before flushing it. |
81 ready_frames_.clear(); | 82 ready_frames_.clear(); |
82 received_end_of_stream_ = false; | 83 received_end_of_stream_ = false; |
83 video_frame_stream_.Reset(base::Bind( | 84 video_frame_stream_.Reset(base::Bind( |
84 &VideoRendererImpl::OnVideoFrameStreamResetDone, weak_this_)); | 85 &VideoRendererImpl::OnVideoFrameStreamResetDone, weak_this_)); |
85 } | 86 } |
86 | 87 |
87 void VideoRendererImpl::Stop(const base::Closure& callback) { | 88 void VideoRendererImpl::Stop(const base::Closure& callback) { |
88 DCHECK(message_loop_->BelongsToCurrentThread()); | 89 DCHECK(task_runner_->BelongsToCurrentThread()); |
89 base::AutoLock auto_lock(lock_); | 90 base::AutoLock auto_lock(lock_); |
90 if (state_ == kUninitialized || state_ == kStopped) { | 91 if (state_ == kUninitialized || state_ == kStopped) { |
91 callback.Run(); | 92 callback.Run(); |
92 return; | 93 return; |
93 } | 94 } |
94 | 95 |
95 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing | 96 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing |
96 // task-running guards that check |state_| with DCHECK(). | 97 // task-running guards that check |state_| with DCHECK(). |
97 | 98 |
98 state_ = kStopped; | 99 state_ = kStopped; |
(...skipping 13 matching lines...) Expand all Loading... |
112 | 113 |
113 if (!thread_to_join.is_null()) { | 114 if (!thread_to_join.is_null()) { |
114 base::AutoUnlock auto_unlock(lock_); | 115 base::AutoUnlock auto_unlock(lock_); |
115 base::PlatformThread::Join(thread_to_join); | 116 base::PlatformThread::Join(thread_to_join); |
116 } | 117 } |
117 | 118 |
118 video_frame_stream_.Stop(callback); | 119 video_frame_stream_.Stop(callback); |
119 } | 120 } |
120 | 121 |
121 void VideoRendererImpl::SetPlaybackRate(float playback_rate) { | 122 void VideoRendererImpl::SetPlaybackRate(float playback_rate) { |
122 DCHECK(message_loop_->BelongsToCurrentThread()); | 123 DCHECK(task_runner_->BelongsToCurrentThread()); |
123 base::AutoLock auto_lock(lock_); | 124 base::AutoLock auto_lock(lock_); |
124 playback_rate_ = playback_rate; | 125 playback_rate_ = playback_rate; |
125 } | 126 } |
126 | 127 |
127 void VideoRendererImpl::Preroll(base::TimeDelta time, | 128 void VideoRendererImpl::Preroll(base::TimeDelta time, |
128 const PipelineStatusCB& cb) { | 129 const PipelineStatusCB& cb) { |
129 DCHECK(message_loop_->BelongsToCurrentThread()); | 130 DCHECK(task_runner_->BelongsToCurrentThread()); |
130 base::AutoLock auto_lock(lock_); | 131 base::AutoLock auto_lock(lock_); |
131 DCHECK(!cb.is_null()); | 132 DCHECK(!cb.is_null()); |
132 DCHECK(preroll_cb_.is_null()); | 133 DCHECK(preroll_cb_.is_null()); |
133 DCHECK(state_ == kFlushed || state_== kPaused) << "state_ " << state_; | 134 DCHECK(state_ == kFlushed || state_== kPaused) << "state_ " << state_; |
134 | 135 |
135 if (state_ == kFlushed) { | 136 if (state_ == kFlushed) { |
136 DCHECK(time != kNoTimestamp()); | 137 DCHECK(time != kNoTimestamp()); |
137 DCHECK(!pending_read_); | 138 DCHECK(!pending_read_); |
138 DCHECK(ready_frames_.empty()); | 139 DCHECK(ready_frames_.empty()); |
139 } else { | 140 } else { |
(...skipping 14 matching lines...) Expand all Loading... |
154 | 155 |
155 void VideoRendererImpl::Initialize(DemuxerStream* stream, | 156 void VideoRendererImpl::Initialize(DemuxerStream* stream, |
156 const PipelineStatusCB& init_cb, | 157 const PipelineStatusCB& init_cb, |
157 const StatisticsCB& statistics_cb, | 158 const StatisticsCB& statistics_cb, |
158 const TimeCB& max_time_cb, | 159 const TimeCB& max_time_cb, |
159 const NaturalSizeChangedCB& size_changed_cb, | 160 const NaturalSizeChangedCB& size_changed_cb, |
160 const base::Closure& ended_cb, | 161 const base::Closure& ended_cb, |
161 const PipelineStatusCB& error_cb, | 162 const PipelineStatusCB& error_cb, |
162 const TimeDeltaCB& get_time_cb, | 163 const TimeDeltaCB& get_time_cb, |
163 const TimeDeltaCB& get_duration_cb) { | 164 const TimeDeltaCB& get_duration_cb) { |
164 DCHECK(message_loop_->BelongsToCurrentThread()); | 165 DCHECK(task_runner_->BelongsToCurrentThread()); |
165 base::AutoLock auto_lock(lock_); | 166 base::AutoLock auto_lock(lock_); |
166 DCHECK(stream); | 167 DCHECK(stream); |
167 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); | 168 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); |
168 DCHECK(!init_cb.is_null()); | 169 DCHECK(!init_cb.is_null()); |
169 DCHECK(!statistics_cb.is_null()); | 170 DCHECK(!statistics_cb.is_null()); |
170 DCHECK(!max_time_cb.is_null()); | 171 DCHECK(!max_time_cb.is_null()); |
171 DCHECK(!size_changed_cb.is_null()); | 172 DCHECK(!size_changed_cb.is_null()); |
172 DCHECK(!ended_cb.is_null()); | 173 DCHECK(!ended_cb.is_null()); |
173 DCHECK(!get_time_cb.is_null()); | 174 DCHECK(!get_time_cb.is_null()); |
174 DCHECK(!get_duration_cb.is_null()); | 175 DCHECK(!get_duration_cb.is_null()); |
(...skipping 12 matching lines...) Expand all Loading... |
187 | 188 |
188 video_frame_stream_.Initialize( | 189 video_frame_stream_.Initialize( |
189 stream, | 190 stream, |
190 statistics_cb, | 191 statistics_cb, |
191 base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized, | 192 base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized, |
192 weak_this_)); | 193 weak_this_)); |
193 } | 194 } |
194 | 195 |
195 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success, | 196 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success, |
196 bool has_alpha) { | 197 bool has_alpha) { |
197 DCHECK(message_loop_->BelongsToCurrentThread()); | 198 DCHECK(task_runner_->BelongsToCurrentThread()); |
198 base::AutoLock auto_lock(lock_); | 199 base::AutoLock auto_lock(lock_); |
199 | 200 |
200 if (state_ == kStopped) | 201 if (state_ == kStopped) |
201 return; | 202 return; |
202 | 203 |
203 DCHECK_EQ(state_, kInitializing); | 204 DCHECK_EQ(state_, kInitializing); |
204 | 205 |
205 if (!success) { | 206 if (!success) { |
206 state_ = kUninitialized; | 207 state_ = kUninitialized; |
207 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 208 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 last_timestamp_ = next_frame->GetTimestamp(); | 325 last_timestamp_ = next_frame->GetTimestamp(); |
325 | 326 |
326 const gfx::Size& natural_size = next_frame->natural_size(); | 327 const gfx::Size& natural_size = next_frame->natural_size(); |
327 if (natural_size != last_natural_size_) { | 328 if (natural_size != last_natural_size_) { |
328 last_natural_size_ = natural_size; | 329 last_natural_size_ = natural_size; |
329 size_changed_cb_.Run(natural_size); | 330 size_changed_cb_.Run(natural_size); |
330 } | 331 } |
331 | 332 |
332 paint_cb_.Run(next_frame); | 333 paint_cb_.Run(next_frame); |
333 | 334 |
334 message_loop_->PostTask(FROM_HERE, base::Bind( | 335 task_runner_->PostTask(FROM_HERE, base::Bind( |
335 &VideoRendererImpl::AttemptRead, weak_this_)); | 336 &VideoRendererImpl::AttemptRead, weak_this_)); |
336 } | 337 } |
337 | 338 |
338 void VideoRendererImpl::DropNextReadyFrame_Locked() { | 339 void VideoRendererImpl::DropNextReadyFrame_Locked() { |
339 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped"); | 340 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped"); |
340 | 341 |
341 lock_.AssertAcquired(); | 342 lock_.AssertAcquired(); |
342 | 343 |
343 last_timestamp_ = ready_frames_.front()->GetTimestamp(); | 344 last_timestamp_ = ready_frames_.front()->GetTimestamp(); |
344 ready_frames_.pop_front(); | 345 ready_frames_.pop_front(); |
345 frames_decoded_++; | 346 frames_decoded_++; |
346 frames_dropped_++; | 347 frames_dropped_++; |
347 | 348 |
348 message_loop_->PostTask(FROM_HERE, base::Bind( | 349 task_runner_->PostTask(FROM_HERE, base::Bind( |
349 &VideoRendererImpl::AttemptRead, weak_this_)); | 350 &VideoRendererImpl::AttemptRead, weak_this_)); |
350 } | 351 } |
351 | 352 |
352 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status, | 353 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status, |
353 const scoped_refptr<VideoFrame>& frame) { | 354 const scoped_refptr<VideoFrame>& frame) { |
354 base::AutoLock auto_lock(lock_); | 355 base::AutoLock auto_lock(lock_); |
355 DCHECK_NE(state_, kUninitialized); | 356 DCHECK_NE(state_, kUninitialized); |
356 DCHECK_NE(state_, kFlushed); | 357 DCHECK_NE(state_, kFlushed); |
357 | 358 |
358 CHECK(pending_read_); | 359 CHECK(pending_read_); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 if (state_ == kPlaying) | 451 if (state_ == kPlaying) |
451 frame_available_.Signal(); | 452 frame_available_.Signal(); |
452 } | 453 } |
453 | 454 |
454 void VideoRendererImpl::AttemptRead() { | 455 void VideoRendererImpl::AttemptRead() { |
455 base::AutoLock auto_lock(lock_); | 456 base::AutoLock auto_lock(lock_); |
456 AttemptRead_Locked(); | 457 AttemptRead_Locked(); |
457 } | 458 } |
458 | 459 |
459 void VideoRendererImpl::AttemptRead_Locked() { | 460 void VideoRendererImpl::AttemptRead_Locked() { |
460 DCHECK(message_loop_->BelongsToCurrentThread()); | 461 DCHECK(task_runner_->BelongsToCurrentThread()); |
461 lock_.AssertAcquired(); | 462 lock_.AssertAcquired(); |
462 | 463 |
463 if (pending_read_ || received_end_of_stream_ || | 464 if (pending_read_ || received_end_of_stream_ || |
464 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) { | 465 ready_frames_.size() == static_cast<size_t>(limits::kMaxVideoFrames)) { |
465 return; | 466 return; |
466 } | 467 } |
467 | 468 |
468 switch (state_) { | 469 switch (state_) { |
469 case kPaused: | 470 case kPaused: |
470 case kPrerolling: | 471 case kPrerolling: |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 statistics_cb_.Run(statistics); | 549 statistics_cb_.Run(statistics); |
549 | 550 |
550 frames_decoded_ = 0; | 551 frames_decoded_ = 0; |
551 frames_dropped_ = 0; | 552 frames_dropped_ = 0; |
552 } | 553 } |
553 | 554 |
554 frame_available_.TimedWait(wait_duration); | 555 frame_available_.TimedWait(wait_duration); |
555 } | 556 } |
556 | 557 |
557 } // namespace media | 558 } // namespace media |
OLD | NEW |