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.h" | |
10 #include "base/threading/platform_thread.h" | 11 #include "base/threading/platform_thread.h" |
11 #include "media/base/buffers.h" | 12 #include "media/base/buffers.h" |
12 #include "media/base/limits.h" | 13 #include "media/base/limits.h" |
13 #include "media/base/pipeline.h" | 14 #include "media/base/pipeline.h" |
14 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
15 | 16 |
16 namespace media { | 17 namespace media { |
17 | 18 |
18 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() { | 19 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() { |
19 return base::TimeDelta::FromMilliseconds(250); | 20 return base::TimeDelta::FromMilliseconds(250); |
20 } | 21 } |
21 | 22 |
22 VideoRendererBase::VideoRendererBase(const base::Closure& paint_cb, | 23 VideoRendererBase::VideoRendererBase( |
23 const SetOpaqueCB& set_opaque_cb, | 24 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
24 bool drop_frames) | 25 const base::Closure& paint_cb, |
25 : frame_available_(&lock_), | 26 const SetOpaqueCB& set_opaque_cb, |
27 bool drop_frames) | |
28 : message_loop_(message_loop), | |
29 frame_available_(&lock_), | |
26 state_(kUninitialized), | 30 state_(kUninitialized), |
27 thread_(base::kNullThreadHandle), | 31 thread_(base::kNullThreadHandle), |
28 pending_read_(false), | 32 pending_read_(false), |
29 pending_paint_(false), | 33 pending_paint_(false), |
30 pending_paint_with_last_available_(false), | 34 pending_paint_with_last_available_(false), |
31 drop_frames_(drop_frames), | 35 drop_frames_(drop_frames), |
32 playback_rate_(0), | 36 playback_rate_(0), |
33 paint_cb_(paint_cb), | 37 paint_cb_(paint_cb), |
34 set_opaque_cb_(set_opaque_cb) { | 38 set_opaque_cb_(set_opaque_cb) { |
35 DCHECK(!paint_cb_.is_null()); | 39 DCHECK(!paint_cb_.is_null()); |
36 } | 40 } |
37 | 41 |
38 void VideoRendererBase::Play(const base::Closure& callback) { | 42 void VideoRendererBase::Play(const base::Closure& callback) { |
43 DCHECK(message_loop_->BelongsToCurrentThread()); | |
39 base::AutoLock auto_lock(lock_); | 44 base::AutoLock auto_lock(lock_); |
40 DCHECK_EQ(kPrerolled, state_); | 45 DCHECK_EQ(kPrerolled, state_); |
41 state_ = kPlaying; | 46 state_ = kPlaying; |
42 callback.Run(); | 47 callback.Run(); |
43 } | 48 } |
44 | 49 |
45 void VideoRendererBase::Pause(const base::Closure& callback) { | 50 void VideoRendererBase::Pause(const base::Closure& callback) { |
51 DCHECK(message_loop_->BelongsToCurrentThread()); | |
46 base::AutoLock auto_lock(lock_); | 52 base::AutoLock auto_lock(lock_); |
47 DCHECK(state_ != kUninitialized || state_ == kError); | 53 DCHECK(state_ != kUninitialized || state_ == kError); |
48 state_ = kPaused; | 54 state_ = kPaused; |
49 callback.Run(); | 55 callback.Run(); |
50 } | 56 } |
51 | 57 |
52 void VideoRendererBase::Flush(const base::Closure& callback) { | 58 void VideoRendererBase::Flush(const base::Closure& callback) { |
59 DCHECK(message_loop_->BelongsToCurrentThread()); | |
53 base::AutoLock auto_lock(lock_); | 60 base::AutoLock auto_lock(lock_); |
54 DCHECK_EQ(state_, kPaused); | 61 DCHECK_EQ(state_, kPaused); |
55 flush_cb_ = callback; | 62 flush_cb_ = callback; |
56 state_ = kFlushingDecoder; | 63 state_ = kFlushingDecoder; |
57 | 64 |
58 // We must unlock here because the callback might run within the Flush() | 65 decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderResetDone, this)); |
59 // call. | |
60 // TODO: Remove this line when fixing http://crbug.com/125020 | |
61 base::AutoUnlock auto_unlock(lock_); | |
62 decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderFlushDone, this)); | |
63 } | 66 } |
64 | 67 |
65 void VideoRendererBase::Stop(const base::Closure& callback) { | 68 void VideoRendererBase::Stop(const base::Closure& callback) { |
69 DCHECK(message_loop_->BelongsToCurrentThread()); | |
66 if (state_ == kStopped) { | 70 if (state_ == kStopped) { |
67 callback.Run(); | 71 callback.Run(); |
68 return; | 72 return; |
69 } | 73 } |
70 | 74 |
71 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; | 75 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; |
72 { | 76 { |
73 base::AutoLock auto_lock(lock_); | 77 base::AutoLock auto_lock(lock_); |
74 state_ = kStopped; | 78 state_ = kStopped; |
75 | 79 |
(...skipping 11 matching lines...) Expand all Loading... | |
87 thread_ = base::kNullThreadHandle; | 91 thread_ = base::kNullThreadHandle; |
88 } | 92 } |
89 } | 93 } |
90 if (thread_to_join != base::kNullThreadHandle) | 94 if (thread_to_join != base::kNullThreadHandle) |
91 base::PlatformThread::Join(thread_to_join); | 95 base::PlatformThread::Join(thread_to_join); |
92 | 96 |
93 decoder_->Stop(callback); | 97 decoder_->Stop(callback); |
94 } | 98 } |
95 | 99 |
96 void VideoRendererBase::SetPlaybackRate(float playback_rate) { | 100 void VideoRendererBase::SetPlaybackRate(float playback_rate) { |
101 DCHECK(message_loop_->BelongsToCurrentThread()); | |
97 base::AutoLock auto_lock(lock_); | 102 base::AutoLock auto_lock(lock_); |
98 playback_rate_ = playback_rate; | 103 playback_rate_ = playback_rate; |
99 } | 104 } |
100 | 105 |
101 void VideoRendererBase::Preroll(base::TimeDelta time, | 106 void VideoRendererBase::Preroll(base::TimeDelta time, |
102 const PipelineStatusCB& cb) { | 107 const PipelineStatusCB& cb) { |
108 DCHECK(message_loop_->BelongsToCurrentThread()); | |
103 base::AutoLock auto_lock(lock_); | 109 base::AutoLock auto_lock(lock_); |
104 DCHECK_EQ(state_, kFlushed) << "Must flush prior to prerolling."; | 110 DCHECK_EQ(state_, kFlushed) << "Must flush prior to prerolling."; |
105 DCHECK(!cb.is_null()); | 111 DCHECK(!cb.is_null()); |
106 DCHECK(preroll_cb_.is_null()); | 112 DCHECK(preroll_cb_.is_null()); |
107 | 113 |
108 state_ = kPrerolling; | 114 state_ = kPrerolling; |
109 preroll_cb_ = cb; | 115 preroll_cb_ = cb; |
110 preroll_timestamp_ = time; | 116 preroll_timestamp_ = time; |
111 prerolling_delayed_frame_ = NULL; | 117 prerolling_delayed_frame_ = NULL; |
112 AttemptRead_Locked(); | 118 AttemptRead_Locked(); |
113 } | 119 } |
114 | 120 |
115 void VideoRendererBase::Initialize(const scoped_refptr<DemuxerStream>& stream, | 121 void VideoRendererBase::Initialize(const scoped_refptr<DemuxerStream>& stream, |
116 const VideoDecoderList& decoders, | 122 const VideoDecoderList& decoders, |
117 const PipelineStatusCB& init_cb, | 123 const PipelineStatusCB& init_cb, |
118 const StatisticsCB& statistics_cb, | 124 const StatisticsCB& statistics_cb, |
119 const TimeCB& max_time_cb, | 125 const TimeCB& max_time_cb, |
120 const NaturalSizeChangedCB& size_changed_cb, | 126 const NaturalSizeChangedCB& size_changed_cb, |
121 const base::Closure& ended_cb, | 127 const base::Closure& ended_cb, |
122 const PipelineStatusCB& error_cb, | 128 const PipelineStatusCB& error_cb, |
123 const TimeDeltaCB& get_time_cb, | 129 const TimeDeltaCB& get_time_cb, |
124 const TimeDeltaCB& get_duration_cb) { | 130 const TimeDeltaCB& get_duration_cb) { |
131 DCHECK(message_loop_->BelongsToCurrentThread()); | |
125 base::AutoLock auto_lock(lock_); | 132 base::AutoLock auto_lock(lock_); |
126 DCHECK(stream); | 133 DCHECK(stream); |
127 DCHECK(!decoders.empty()); | 134 DCHECK(!decoders.empty()); |
128 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); | 135 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); |
129 DCHECK(!init_cb.is_null()); | 136 DCHECK(!init_cb.is_null()); |
130 DCHECK(!statistics_cb.is_null()); | 137 DCHECK(!statistics_cb.is_null()); |
131 DCHECK(!max_time_cb.is_null()); | 138 DCHECK(!max_time_cb.is_null()); |
132 DCHECK(!size_changed_cb.is_null()); | 139 DCHECK(!size_changed_cb.is_null()); |
133 DCHECK(!ended_cb.is_null()); | 140 DCHECK(!ended_cb.is_null()); |
134 DCHECK(!get_time_cb.is_null()); | 141 DCHECK(!get_time_cb.is_null()); |
135 DCHECK(!get_duration_cb.is_null()); | 142 DCHECK(!get_duration_cb.is_null()); |
136 DCHECK_EQ(kUninitialized, state_); | 143 DCHECK_EQ(kUninitialized, state_); |
137 | 144 |
138 init_cb_ = init_cb; | 145 init_cb_ = init_cb; |
139 statistics_cb_ = statistics_cb; | 146 statistics_cb_ = statistics_cb; |
140 max_time_cb_ = max_time_cb; | 147 max_time_cb_ = max_time_cb; |
141 size_changed_cb_ = size_changed_cb; | 148 size_changed_cb_ = size_changed_cb; |
142 ended_cb_ = ended_cb; | 149 ended_cb_ = ended_cb; |
143 error_cb_ = error_cb; | 150 error_cb_ = error_cb; |
144 get_time_cb_ = get_time_cb; | 151 get_time_cb_ = get_time_cb; |
145 get_duration_cb_ = get_duration_cb; | 152 get_duration_cb_ = get_duration_cb; |
146 | 153 |
147 scoped_ptr<VideoDecoderList> decoder_list(new VideoDecoderList(decoders)); | 154 scoped_ptr<VideoDecoderList> decoder_list(new VideoDecoderList(decoders)); |
148 InitializeNextDecoder(stream, decoder_list.Pass()); | 155 InitializeNextDecoder(stream, decoder_list.Pass()); |
149 } | 156 } |
150 | 157 |
151 void VideoRendererBase::InitializeNextDecoder( | 158 void VideoRendererBase::InitializeNextDecoder( |
152 const scoped_refptr<DemuxerStream>& demuxer_stream, | 159 const scoped_refptr<DemuxerStream>& demuxer_stream, |
153 scoped_ptr<VideoDecoderList> decoders) { | 160 scoped_ptr<VideoDecoderList> decoders) { |
161 DCHECK(message_loop_->BelongsToCurrentThread()); | |
154 lock_.AssertAcquired(); | 162 lock_.AssertAcquired(); |
155 DCHECK(!decoders->empty()); | 163 DCHECK(!decoders->empty()); |
156 | 164 |
157 scoped_refptr<VideoDecoder> decoder = decoders->front(); | 165 scoped_refptr<VideoDecoder> decoder = decoders->front(); |
158 decoders->pop_front(); | 166 decoders->pop_front(); |
159 | 167 |
160 DCHECK(decoder); | 168 DCHECK(decoder); |
161 decoder_ = decoder; | 169 decoder_ = decoder; |
162 | 170 |
163 base::AutoUnlock auto_unlock(lock_); | 171 base::AutoUnlock auto_unlock(lock_); |
164 decoder->Initialize( | 172 decoder->Initialize( |
165 demuxer_stream, | 173 demuxer_stream, |
166 base::Bind(&VideoRendererBase::OnDecoderInitDone, this, | 174 base::Bind(&VideoRendererBase::OnDecoderInitDone, this, |
167 demuxer_stream, | 175 demuxer_stream, |
168 base::Passed(&decoders)), | 176 base::Passed(&decoders)), |
169 statistics_cb_); | 177 statistics_cb_); |
170 } | 178 } |
171 | 179 |
172 void VideoRendererBase::OnDecoderInitDone( | 180 void VideoRendererBase::OnDecoderInitDone( |
173 const scoped_refptr<DemuxerStream>& demuxer_stream, | 181 const scoped_refptr<DemuxerStream>& demuxer_stream, |
174 scoped_ptr<VideoDecoderList> decoders, | 182 scoped_ptr<VideoDecoderList> decoders, |
175 PipelineStatus status) { | 183 PipelineStatus status) { |
184 DCHECK(message_loop_->BelongsToCurrentThread()); | |
176 base::AutoLock auto_lock(lock_); | 185 base::AutoLock auto_lock(lock_); |
177 | 186 |
178 if (state_ == kStopped) | 187 if (state_ == kStopped) |
179 return; | 188 return; |
180 | 189 |
181 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { | 190 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { |
182 InitializeNextDecoder(demuxer_stream, decoders.Pass()); | 191 InitializeNextDecoder(demuxer_stream, decoders.Pass()); |
183 return; | 192 return; |
184 } | 193 } |
185 | 194 |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 // Still a chance we can render the frame! | 332 // Still a chance we can render the frame! |
324 if (remaining_time.InMicroseconds() > 0) | 333 if (remaining_time.InMicroseconds() > 0) |
325 break; | 334 break; |
326 | 335 |
327 if (!drop_frames_) | 336 if (!drop_frames_) |
328 break; | 337 break; |
329 | 338 |
330 // Frame dropped: read again. | 339 // Frame dropped: read again. |
331 ++frames_dropped; | 340 ++frames_dropped; |
332 ready_frames_.pop_front(); | 341 ready_frames_.pop_front(); |
333 AttemptRead_Locked(); | 342 message_loop_->PostTask(FROM_HERE, base::Bind( |
343 &VideoRendererBase::AttemptRead, this)); | |
334 } | 344 } |
335 // Continue waiting for the current paint to finish. | 345 // Continue waiting for the current paint to finish. |
336 frame_available_.TimedWait(kIdleTimeDelta); | 346 frame_available_.TimedWait(kIdleTimeDelta); |
337 continue; | 347 continue; |
338 } | 348 } |
339 | 349 |
340 | 350 |
341 // Congratulations! You've made it past the video frame timing gauntlet. | 351 // Congratulations! You've made it past the video frame timing gauntlet. |
342 // | 352 // |
343 // We can now safely update the current frame, request another frame, and | 353 // We can now safely update the current frame, request another frame, and |
344 // signal to the client that a new frame is available. | 354 // signal to the client that a new frame is available. |
345 DCHECK(!pending_paint_); | 355 DCHECK(!pending_paint_); |
346 DCHECK(!ready_frames_.empty()); | 356 DCHECK(!ready_frames_.empty()); |
347 SetCurrentFrameToNextReadyFrame(); | 357 SetCurrentFrameToNextReadyFrame(); |
348 AttemptRead_Locked(); | 358 message_loop_->PostTask(FROM_HERE, base::Bind( |
359 &VideoRendererBase::AttemptRead, this)); | |
349 | 360 |
350 base::AutoUnlock auto_unlock(lock_); | 361 base::AutoUnlock auto_unlock(lock_); |
351 paint_cb_.Run(); | 362 paint_cb_.Run(); |
352 } | 363 } |
353 } | 364 } |
354 | 365 |
355 void VideoRendererBase::SetCurrentFrameToNextReadyFrame() { | 366 void VideoRendererBase::SetCurrentFrameToNextReadyFrame() { |
356 current_frame_ = ready_frames_.front(); | 367 current_frame_ = ready_frames_.front(); |
357 ready_frames_.pop_front(); | 368 ready_frames_.pop_front(); |
358 | 369 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
551 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); | 562 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); |
552 | 563 |
553 base::TimeDelta max_clock_time = | 564 base::TimeDelta max_clock_time = |
554 frame->IsEndOfStream() ? duration : frame->GetTimestamp(); | 565 frame->IsEndOfStream() ? duration : frame->GetTimestamp(); |
555 DCHECK(max_clock_time != kNoTimestamp()); | 566 DCHECK(max_clock_time != kNoTimestamp()); |
556 max_time_cb_.Run(max_clock_time); | 567 max_time_cb_.Run(max_clock_time); |
557 | 568 |
558 frame_available_.Signal(); | 569 frame_available_.Signal(); |
559 } | 570 } |
560 | 571 |
572 void VideoRendererBase::AttemptRead() { | |
573 base::AutoLock auto_lock(lock_); | |
574 AttemptRead_Locked(); | |
575 } | |
576 | |
561 void VideoRendererBase::AttemptRead_Locked() { | 577 void VideoRendererBase::AttemptRead_Locked() { |
578 DCHECK(message_loop_->BelongsToCurrentThread()); | |
562 lock_.AssertAcquired(); | 579 lock_.AssertAcquired(); |
563 DCHECK_NE(kEnded, state_); | |
564 | 580 |
565 if (pending_read_ || | 581 if (pending_read_ || |
566 NumFrames_Locked() == limits::kMaxVideoFrames || | 582 NumFrames_Locked() == limits::kMaxVideoFrames || |
567 (!ready_frames_.empty() && ready_frames_.back()->IsEndOfStream()) || | 583 (!ready_frames_.empty() && ready_frames_.back()->IsEndOfStream()) || |
568 state_ == kFlushingDecoder || | 584 state_ == kFlushingDecoder || |
569 state_ == kFlushing) { | 585 state_ == kFlushing || |
586 state_ == kEnded) { | |
scherkus (not reviewing)
2012/12/06 21:22:14
due to task-posting it's possible to run AttemptRe
| |
570 return; | 587 return; |
571 } | 588 } |
572 | 589 |
573 pending_read_ = true; | 590 pending_read_ = true; |
574 decoder_->Read(base::Bind(&VideoRendererBase::FrameReady, this)); | 591 decoder_->Read(base::Bind(&VideoRendererBase::FrameReady, this)); |
575 } | 592 } |
576 | 593 |
577 void VideoRendererBase::OnDecoderFlushDone() { | 594 void VideoRendererBase::OnDecoderResetDone() { |
578 base::AutoLock auto_lock(lock_); | 595 base::AutoLock auto_lock(lock_); |
579 DCHECK_EQ(kFlushingDecoder, state_); | 596 DCHECK_EQ(kFlushingDecoder, state_); |
580 DCHECK(!pending_read_); | 597 DCHECK(!pending_read_); |
581 | 598 |
582 state_ = kFlushing; | 599 state_ = kFlushing; |
583 AttemptFlush_Locked(); | 600 AttemptFlush_Locked(); |
584 } | 601 } |
585 | 602 |
586 void VideoRendererBase::AttemptFlush_Locked() { | 603 void VideoRendererBase::AttemptFlush_Locked() { |
587 lock_.AssertAcquired(); | 604 lock_.AssertAcquired(); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
621 | 638 |
622 int VideoRendererBase::NumFrames_Locked() const { | 639 int VideoRendererBase::NumFrames_Locked() const { |
623 lock_.AssertAcquired(); | 640 lock_.AssertAcquired(); |
624 int outstanding_frames = | 641 int outstanding_frames = |
625 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) + | 642 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) + |
626 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0); | 643 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0); |
627 return ready_frames_.size() + outstanding_frames; | 644 return ready_frames_.size() + outstanding_frames; |
628 } | 645 } |
629 | 646 |
630 } // namespace media | 647 } // namespace media |
OLD | NEW |