Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: media/filters/video_renderer_base.cc

Issue 12262058: Revert r180578, r180591, and r180604 from 1410 branch. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/1410/src/
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/video_renderer_base.h ('k') | media/filters/video_renderer_base_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/message_loop.h"
11 #include "base/threading/platform_thread.h" 11 #include "base/threading/platform_thread.h"
12 #include "media/base/buffers.h" 12 #include "media/base/buffers.h"
13 #include "media/base/limits.h" 13 #include "media/base/limits.h"
14 #include "media/base/pipeline.h" 14 #include "media/base/pipeline.h"
15 #include "media/base/video_frame.h" 15 #include "media/base/video_frame.h"
16 #include "media/filters/decrypting_demuxer_stream.h" 16 #include "media/filters/decrypting_demuxer_stream.h"
17 #include "media/filters/video_decoder_selector.h" 17 #include "media/filters/video_decoder_selector.h"
18 18
19 namespace media { 19 namespace media {
20 20
21 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() { 21 base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() {
22 return base::TimeDelta::FromMilliseconds(250); 22 return base::TimeDelta::FromMilliseconds(250);
23 } 23 }
24 24
25 VideoRendererBase::VideoRendererBase( 25 VideoRendererBase::VideoRendererBase(
26 const scoped_refptr<base::MessageLoopProxy>& message_loop, 26 const scoped_refptr<base::MessageLoopProxy>& message_loop,
27 const SetDecryptorReadyCB& set_decryptor_ready_cb, 27 const SetDecryptorReadyCB& set_decryptor_ready_cb,
28 const PaintCB& paint_cb, 28 const base::Closure& paint_cb,
29 const SetOpaqueCB& set_opaque_cb, 29 const SetOpaqueCB& set_opaque_cb,
30 bool drop_frames) 30 bool drop_frames)
31 : message_loop_(message_loop), 31 : message_loop_(message_loop),
32 weak_factory_(this),
33 set_decryptor_ready_cb_(set_decryptor_ready_cb), 32 set_decryptor_ready_cb_(set_decryptor_ready_cb),
34 frame_available_(&lock_), 33 frame_available_(&lock_),
35 state_(kUninitialized), 34 state_(kUninitialized),
36 thread_(base::kNullThreadHandle), 35 thread_(base::kNullThreadHandle),
37 pending_read_(false), 36 pending_read_(false),
37 pending_paint_(false),
38 pending_paint_with_last_available_(false),
38 drop_frames_(drop_frames), 39 drop_frames_(drop_frames),
39 playback_rate_(0), 40 playback_rate_(0),
40 paint_cb_(paint_cb), 41 paint_cb_(paint_cb),
41 set_opaque_cb_(set_opaque_cb), 42 set_opaque_cb_(set_opaque_cb) {
42 last_timestamp_(kNoTimestamp()) {
43 DCHECK(!paint_cb_.is_null()); 43 DCHECK(!paint_cb_.is_null());
44 } 44 }
45 45
46 VideoRendererBase::~VideoRendererBase() {
47 base::AutoLock auto_lock(lock_);
48 CHECK(state_ == kUninitialized || state_ == kStopped) << state_;
49 CHECK_EQ(thread_, base::kNullThreadHandle);
50 }
51
52 void VideoRendererBase::Play(const base::Closure& callback) { 46 void VideoRendererBase::Play(const base::Closure& callback) {
53 DCHECK(message_loop_->BelongsToCurrentThread()); 47 DCHECK(message_loop_->BelongsToCurrentThread());
54 base::AutoLock auto_lock(lock_); 48 base::AutoLock auto_lock(lock_);
55 DCHECK_EQ(kPrerolled, state_); 49 DCHECK_EQ(kPrerolled, state_);
56 state_ = kPlaying; 50 state_ = kPlaying;
57 callback.Run(); 51 callback.Run();
58 } 52 }
59 53
60 void VideoRendererBase::Pause(const base::Closure& callback) { 54 void VideoRendererBase::Pause(const base::Closure& callback) {
61 DCHECK(message_loop_->BelongsToCurrentThread()); 55 DCHECK(message_loop_->BelongsToCurrentThread());
62 base::AutoLock auto_lock(lock_); 56 base::AutoLock auto_lock(lock_);
63 DCHECK(state_ != kUninitialized || state_ == kError); 57 DCHECK(state_ != kUninitialized || state_ == kError);
64 state_ = kPaused; 58 state_ = kPaused;
65 callback.Run(); 59 callback.Run();
66 } 60 }
67 61
68 void VideoRendererBase::Flush(const base::Closure& callback) { 62 void VideoRendererBase::Flush(const base::Closure& callback) {
69 DCHECK(message_loop_->BelongsToCurrentThread()); 63 DCHECK(message_loop_->BelongsToCurrentThread());
70 base::AutoLock auto_lock(lock_); 64 base::AutoLock auto_lock(lock_);
71 DCHECK_EQ(state_, kPaused); 65 DCHECK_EQ(state_, kPaused);
72 flush_cb_ = callback; 66 flush_cb_ = callback;
73 state_ = kFlushingDecoder; 67 state_ = kFlushingDecoder;
74 68
75 if (decrypting_demuxer_stream_) { 69 if (decrypting_demuxer_stream_) {
76 decrypting_demuxer_stream_->Reset(base::Bind( 70 decrypting_demuxer_stream_->Reset(base::Bind(
77 &VideoRendererBase::ResetDecoder, weak_this_)); 71 &VideoRendererBase::ResetDecoder, this));
78 return; 72 return;
79 } 73 }
80 74
81 decoder_->Reset(base::Bind( 75 decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderResetDone, this));
82 &VideoRendererBase::OnDecoderResetDone, weak_this_));
83 } 76 }
84 77
85 void VideoRendererBase::ResetDecoder() { 78 void VideoRendererBase::ResetDecoder() {
86 DCHECK(message_loop_->BelongsToCurrentThread()); 79 DCHECK(message_loop_->BelongsToCurrentThread());
87 base::AutoLock auto_lock(lock_); 80 base::AutoLock auto_lock(lock_);
88 decoder_->Reset(base::Bind( 81 decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderResetDone, this));
89 &VideoRendererBase::OnDecoderResetDone, weak_this_));
90 } 82 }
91 83
92 void VideoRendererBase::Stop(const base::Closure& callback) { 84 void VideoRendererBase::Stop(const base::Closure& callback) {
93 DCHECK(message_loop_->BelongsToCurrentThread()); 85 DCHECK(message_loop_->BelongsToCurrentThread());
94 base::AutoLock auto_lock(lock_);
95 if (state_ == kUninitialized || state_ == kStopped) { 86 if (state_ == kUninitialized || state_ == kStopped) {
96 callback.Run(); 87 callback.Run();
97 return; 88 return;
98 } 89 }
99 90
100 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing 91 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle;
101 // task-running guards that check |state_| with DCHECK(). 92 {
93 base::AutoLock auto_lock(lock_);
94 state_ = kStopped;
102 95
103 state_ = kStopped; 96 statistics_cb_.Reset();
97 max_time_cb_.Reset();
98 if (!pending_paint_ && !pending_paint_with_last_available_)
99 DoStopOrError_Locked();
104 100
105 statistics_cb_.Reset(); 101 // Clean up our thread if present.
106 max_time_cb_.Reset(); 102 if (thread_ != base::kNullThreadHandle) {
107 DoStopOrError_Locked(); 103 // Signal the thread since it's possible to get stopped with the video
108 104 // thread waiting for a read to complete.
109 // Clean up our thread if present. 105 frame_available_.Signal();
110 base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; 106 thread_to_join = thread_;
111 if (thread_ != base::kNullThreadHandle) { 107 thread_ = base::kNullThreadHandle;
112 // Signal the thread since it's possible to get stopped with the video 108 }
113 // thread waiting for a read to complete.
114 frame_available_.Signal();
115 std::swap(thread_, thread_to_join);
116 } 109 }
117 110 if (thread_to_join != base::kNullThreadHandle)
118 if (thread_to_join != base::kNullThreadHandle) {
119 base::AutoUnlock auto_unlock(lock_);
120 base::PlatformThread::Join(thread_to_join); 111 base::PlatformThread::Join(thread_to_join);
121 }
122 112
123 if (decrypting_demuxer_stream_) { 113 if (decrypting_demuxer_stream_) {
124 decrypting_demuxer_stream_->Reset(base::Bind( 114 decrypting_demuxer_stream_->Reset(base::Bind(
125 &VideoRendererBase::StopDecoder, weak_this_, callback)); 115 &VideoRendererBase::StopDecoder, this, callback));
126 return; 116 return;
127 } 117 }
128 118
129 decoder_->Stop(callback); 119 decoder_->Stop(callback);
130 } 120 }
131 121
132 void VideoRendererBase::StopDecoder(const base::Closure& callback) { 122 void VideoRendererBase::StopDecoder(const base::Closure& callback) {
133 DCHECK(message_loop_->BelongsToCurrentThread()); 123 DCHECK(message_loop_->BelongsToCurrentThread());
134 base::AutoLock auto_lock(lock_); 124 base::AutoLock auto_lock(lock_);
135 decoder_->Stop(callback); 125 decoder_->Stop(callback);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); 163 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
174 DCHECK(!init_cb.is_null()); 164 DCHECK(!init_cb.is_null());
175 DCHECK(!statistics_cb.is_null()); 165 DCHECK(!statistics_cb.is_null());
176 DCHECK(!max_time_cb.is_null()); 166 DCHECK(!max_time_cb.is_null());
177 DCHECK(!size_changed_cb.is_null()); 167 DCHECK(!size_changed_cb.is_null());
178 DCHECK(!ended_cb.is_null()); 168 DCHECK(!ended_cb.is_null());
179 DCHECK(!get_time_cb.is_null()); 169 DCHECK(!get_time_cb.is_null());
180 DCHECK(!get_duration_cb.is_null()); 170 DCHECK(!get_duration_cb.is_null());
181 DCHECK_EQ(kUninitialized, state_); 171 DCHECK_EQ(kUninitialized, state_);
182 172
183 weak_this_ = weak_factory_.GetWeakPtr();
184 init_cb_ = init_cb; 173 init_cb_ = init_cb;
185 statistics_cb_ = statistics_cb; 174 statistics_cb_ = statistics_cb;
186 max_time_cb_ = max_time_cb; 175 max_time_cb_ = max_time_cb;
187 size_changed_cb_ = size_changed_cb; 176 size_changed_cb_ = size_changed_cb;
188 ended_cb_ = ended_cb; 177 ended_cb_ = ended_cb;
189 error_cb_ = error_cb; 178 error_cb_ = error_cb;
190 get_time_cb_ = get_time_cb; 179 get_time_cb_ = get_time_cb;
191 get_duration_cb_ = get_duration_cb; 180 get_duration_cb_ = get_duration_cb;
192 181
193 scoped_ptr<VideoDecoderSelector> decoder_selector( 182 scoped_ptr<VideoDecoderSelector> decoder_selector(
194 new VideoDecoderSelector(base::MessageLoopProxy::current(), 183 new VideoDecoderSelector(base::MessageLoopProxy::current(),
195 decoders, 184 decoders,
196 set_decryptor_ready_cb_)); 185 set_decryptor_ready_cb_));
197 186
198 // To avoid calling |decoder_selector| methods and passing ownership of 187 // To avoid calling |decoder_selector| methods and passing ownership of
199 // |decoder_selector| in the same line. 188 // |decoder_selector| in the same line.
200 VideoDecoderSelector* decoder_selector_ptr = decoder_selector.get(); 189 VideoDecoderSelector* decoder_selector_ptr = decoder_selector.get();
201 190
202 decoder_selector_ptr->SelectVideoDecoder( 191 decoder_selector_ptr->SelectVideoDecoder(
203 stream, 192 stream,
204 statistics_cb, 193 statistics_cb,
205 base::Bind(&VideoRendererBase::OnDecoderSelected, weak_this_, 194 base::Bind(&VideoRendererBase::OnDecoderSelected, this,
206 base::Passed(&decoder_selector))); 195 base::Passed(&decoder_selector)));
207 } 196 }
208 197
209 void VideoRendererBase::OnDecoderSelected( 198 void VideoRendererBase::OnDecoderSelected(
210 scoped_ptr<VideoDecoderSelector> decoder_selector, 199 scoped_ptr<VideoDecoderSelector> decoder_selector,
211 const scoped_refptr<VideoDecoder>& selected_decoder, 200 const scoped_refptr<VideoDecoder>& selected_decoder,
212 const scoped_refptr<DecryptingDemuxerStream>& decrypting_demuxer_stream) { 201 const scoped_refptr<DecryptingDemuxerStream>& decrypting_demuxer_stream) {
213 DCHECK(message_loop_->BelongsToCurrentThread()); 202 DCHECK(message_loop_->BelongsToCurrentThread());
214 base::AutoLock auto_lock(lock_); 203 base::AutoLock auto_lock(lock_);
215 204
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 245
257 // The number of milliseconds to idle when we do not have anything to do. 246 // The number of milliseconds to idle when we do not have anything to do.
258 // Nothing special about the value, other than we're being more OS-friendly 247 // Nothing special about the value, other than we're being more OS-friendly
259 // than sleeping for 1 millisecond. 248 // than sleeping for 1 millisecond.
260 // 249 //
261 // TOOD(scherkus): switch to pure event-driven frame timing instead of this 250 // TOOD(scherkus): switch to pure event-driven frame timing instead of this
262 // kIdleTimeDelta business http://crbug.com/106874 251 // kIdleTimeDelta business http://crbug.com/106874
263 const base::TimeDelta kIdleTimeDelta = 252 const base::TimeDelta kIdleTimeDelta =
264 base::TimeDelta::FromMilliseconds(10); 253 base::TimeDelta::FromMilliseconds(10);
265 254
255 uint32 frames_dropped = 0;
256
266 for (;;) { 257 for (;;) {
267 base::AutoLock auto_lock(lock_); 258 base::AutoLock auto_lock(lock_);
268 259
269 // Thread exit condition. 260 // Thread exit condition.
270 if (state_ == kStopped) 261 if (state_ == kStopped)
271 return; 262 return;
272 263
264 if (frames_dropped > 0) {
265 PipelineStatistics statistics;
266 statistics.video_frames_dropped = frames_dropped;
267 statistics_cb_.Run(statistics);
268
269 frames_dropped = 0;
270 }
271
273 // Remain idle as long as we're not playing. 272 // Remain idle as long as we're not playing.
274 if (state_ != kPlaying || playback_rate_ == 0) { 273 if (state_ != kPlaying || playback_rate_ == 0) {
275 frame_available_.TimedWait(kIdleTimeDelta); 274 frame_available_.TimedWait(kIdleTimeDelta);
276 continue; 275 continue;
277 } 276 }
278 277
279 // Remain idle until we have the next frame ready for rendering. 278 // Remain idle until we have the next frame ready for rendering.
280 if (ready_frames_.empty()) { 279 if (ready_frames_.empty()) {
281 frame_available_.TimedWait(kIdleTimeDelta); 280 frame_available_.TimedWait(kIdleTimeDelta);
282 continue; 281 continue;
283 } 282 }
284 283
285 // We've reached the end! 284 // Remain idle until we've initialized |current_frame_| via prerolling.
286 if (ready_frames_.front()->IsEndOfStream()) { 285 if (!current_frame_) {
287 state_ = kEnded; 286 // This can happen if our preroll only contains end of stream frames.
288 ready_frames_.clear(); 287 if (ready_frames_.front()->IsEndOfStream()) {
289 ended_cb_.Run(); 288 state_ = kEnded;
289 ended_cb_.Run();
290 ready_frames_.clear();
290 291
291 // No need to sleep here as we idle when |state_ != kPlaying|. 292 // No need to sleep here as we idle when |state_ != kPlaying|.
293 continue;
294 }
295
296 frame_available_.TimedWait(kIdleTimeDelta);
292 continue; 297 continue;
293 } 298 }
294 299
300 // Calculate how long until we should advance the frame, which is
301 // typically negative but for playback rates < 1.0f may be long enough
302 // that it makes more sense to idle and check again.
295 base::TimeDelta remaining_time = 303 base::TimeDelta remaining_time =
296 CalculateSleepDuration(ready_frames_.front(), playback_rate_); 304 CalculateSleepDuration(ready_frames_.front(), playback_rate_);
297 305
298 // Sleep up to a maximum of our idle time until we're within the time to 306 // Sleep up to a maximum of our idle time until we're within the time to
299 // render the next frame. 307 // render the next frame.
300 if (remaining_time.InMicroseconds() > 0) { 308 if (remaining_time.InMicroseconds() > 0) {
301 remaining_time = std::min(remaining_time, kIdleTimeDelta); 309 remaining_time = std::min(remaining_time, kIdleTimeDelta);
302 frame_available_.TimedWait(remaining_time); 310 frame_available_.TimedWait(remaining_time);
303 continue; 311 continue;
304 } 312 }
305 313
306 // Deadline is defined as the midpoint between this frame and the next 314
307 // frame, using the delta between this frame and the previous frame as the 315 // We're almost there!
308 // assumption for frame duration.
309 // 316 //
310 // TODO(scherkus): An improvement over midpoint might be selecting the 317 // At this point we've rendered |current_frame_| for the proper amount
311 // minimum and/or maximum between the midpoint and some constants. As a 318 // of time and also have the next frame that ready for rendering.
312 // thought experiment, consider what would be better than the midpoint 319
313 // for both the 1fps case and 120fps case. 320
321 // If the next frame is end of stream then we are truly at the end of the
322 // video stream.
314 // 323 //
315 // TODO(scherkus): This can be vastly improved. Use a histogram to measure 324 // TODO(scherkus): deduplicate this end of stream check after we get rid of
316 // the accuracy of our frame timing code. http://crbug.com/149829 325 // |current_frame_|.
317 if (drop_frames_ && last_timestamp_ != kNoTimestamp()) { 326 if (ready_frames_.front()->IsEndOfStream()) {
318 base::TimeDelta now = get_time_cb_.Run(); 327 state_ = kEnded;
319 base::TimeDelta deadline = ready_frames_.front()->GetTimestamp() + 328 ended_cb_.Run();
320 (ready_frames_.front()->GetTimestamp() - last_timestamp_) / 2; 329 ready_frames_.clear();
321 330
322 if (now > deadline) { 331 // No need to sleep here as we idle when |state_ != kPlaying|.
323 DropNextReadyFrame_Locked(); 332 continue;
324 continue; 333 }
334
335 // We cannot update |current_frame_| until we've completed the pending
336 // paint. Furthermore, the pending paint might be really slow: check to
337 // see if we have any ready frames that we can drop if they've already
338 // expired.
339 if (pending_paint_) {
340 while (!ready_frames_.empty()) {
341 // Can't drop anything if we're at the end.
342 if (ready_frames_.front()->IsEndOfStream())
343 break;
344
345 base::TimeDelta remaining_time =
346 ready_frames_.front()->GetTimestamp() - get_time_cb_.Run();
347
348 // Still a chance we can render the frame!
349 if (remaining_time.InMicroseconds() > 0)
350 break;
351
352 if (!drop_frames_)
353 break;
354
355 // Frame dropped: read again.
356 ++frames_dropped;
357 ready_frames_.pop_front();
358 message_loop_->PostTask(FROM_HERE, base::Bind(
359 &VideoRendererBase::AttemptRead, this));
325 } 360 }
361 // Continue waiting for the current paint to finish.
362 frame_available_.TimedWait(kIdleTimeDelta);
363 continue;
326 } 364 }
327 365
366
328 // Congratulations! You've made it past the video frame timing gauntlet. 367 // Congratulations! You've made it past the video frame timing gauntlet.
329 // 368 //
330 // At this point enough time has passed that the next frame that ready for 369 // We can now safely update the current frame, request another frame, and
331 // rendering. 370 // signal to the client that a new frame is available.
332 PaintNextReadyFrame_Locked(); 371 DCHECK(!pending_paint_);
372 DCHECK(!ready_frames_.empty());
373 SetCurrentFrameToNextReadyFrame();
374 message_loop_->PostTask(FROM_HERE, base::Bind(
375 &VideoRendererBase::AttemptRead, this));
376
377 base::AutoUnlock auto_unlock(lock_);
378 paint_cb_.Run();
333 } 379 }
334 } 380 }
335 381
336 void VideoRendererBase::PaintNextReadyFrame_Locked() { 382 void VideoRendererBase::SetCurrentFrameToNextReadyFrame() {
337 lock_.AssertAcquired(); 383 current_frame_ = ready_frames_.front();
338
339 scoped_refptr<VideoFrame> next_frame = ready_frames_.front();
340 ready_frames_.pop_front(); 384 ready_frames_.pop_front();
341 385
342 last_timestamp_ = next_frame->GetTimestamp(); 386 // Notify the pipeline of natural_size() changes.
387 const gfx::Size& natural_size = current_frame_->natural_size();
388 if (natural_size != last_natural_size_) {
389 size_changed_cb_.Run(natural_size);
390 last_natural_size_ = natural_size;
391 }
392 }
343 393
344 const gfx::Size& natural_size = next_frame->natural_size(); 394 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) {
345 if (natural_size != last_natural_size_) { 395 base::AutoLock auto_lock(lock_);
346 last_natural_size_ = natural_size; 396 DCHECK(!pending_paint_ && !pending_paint_with_last_available_);
347 size_changed_cb_.Run(natural_size); 397
398 if ((!current_frame_ || current_frame_->IsEndOfStream()) &&
399 (!last_available_frame_ || last_available_frame_->IsEndOfStream())) {
400 *frame_out = NULL;
401 return;
348 } 402 }
349 403
350 paint_cb_.Run(next_frame); 404 // We should have initialized and have the current frame.
405 DCHECK_NE(state_, kUninitialized);
406 DCHECK_NE(state_, kStopped);
407 DCHECK_NE(state_, kError);
351 408
352 message_loop_->PostTask(FROM_HERE, base::Bind( 409 if (current_frame_) {
353 &VideoRendererBase::AttemptRead, weak_this_)); 410 *frame_out = current_frame_;
411 last_available_frame_ = current_frame_;
412 pending_paint_ = true;
413 } else {
414 DCHECK(last_available_frame_);
415 *frame_out = last_available_frame_;
416 pending_paint_with_last_available_ = true;
417 }
354 } 418 }
355 419
356 void VideoRendererBase::DropNextReadyFrame_Locked() { 420 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) {
357 lock_.AssertAcquired(); 421 base::AutoLock auto_lock(lock_);
358 422
359 last_timestamp_ = ready_frames_.front()->GetTimestamp(); 423 // Note that we do not claim |pending_paint_| when we return NULL frame, in
360 ready_frames_.pop_front(); 424 // that case, |current_frame_| could be changed before PutCurrentFrame.
425 if (pending_paint_) {
426 DCHECK_EQ(current_frame_, frame);
427 DCHECK(!pending_paint_with_last_available_);
428 pending_paint_ = false;
429 } else if (pending_paint_with_last_available_) {
430 DCHECK_EQ(last_available_frame_, frame);
431 DCHECK(!pending_paint_);
432 pending_paint_with_last_available_ = false;
433 } else {
434 DCHECK(!frame);
435 }
361 436
362 PipelineStatistics statistics; 437 // We had cleared the |pending_paint_| flag, there are chances that current
363 statistics.video_frames_dropped = 1; 438 // frame is timed-out. We will wake up our main thread to advance the current
364 statistics_cb_.Run(statistics); 439 // frame when this is true.
440 frame_available_.Signal();
441 if (state_ == kFlushingDecoder)
442 return;
365 443
366 message_loop_->PostTask(FROM_HERE, base::Bind( 444 if (state_ == kFlushing) {
367 &VideoRendererBase::AttemptRead, weak_this_)); 445 AttemptFlush_Locked();
446 return;
447 }
448
449 if (state_ == kError || state_ == kStopped) {
450 DoStopOrError_Locked();
451 }
452 }
453
454 VideoRendererBase::~VideoRendererBase() {
455 base::AutoLock auto_lock(lock_);
456 CHECK(state_ == kUninitialized || state_ == kStopped) << state_;
457 CHECK_EQ(thread_, base::kNullThreadHandle);
368 } 458 }
369 459
370 void VideoRendererBase::FrameReady(VideoDecoder::Status status, 460 void VideoRendererBase::FrameReady(VideoDecoder::Status status,
371 const scoped_refptr<VideoFrame>& frame) { 461 const scoped_refptr<VideoFrame>& frame) {
372 base::AutoLock auto_lock(lock_); 462 base::AutoLock auto_lock(lock_);
373 DCHECK_NE(state_, kUninitialized); 463 DCHECK_NE(state_, kUninitialized);
374 464
375 CHECK(pending_read_); 465 CHECK(pending_read_);
376 pending_read_ = false; 466 pending_read_ = false;
377 467
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 // purposes: 526 // purposes:
437 // 1) Prerolling while paused 527 // 1) Prerolling while paused
438 // 2) Keeps decoding going if video rendering thread starts falling behind 528 // 2) Keeps decoding going if video rendering thread starts falling behind
439 if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) { 529 if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) {
440 AttemptRead_Locked(); 530 AttemptRead_Locked();
441 return; 531 return;
442 } 532 }
443 533
444 // If we're at capacity or end of stream while prerolling we need to 534 // If we're at capacity or end of stream while prerolling we need to
445 // transition to prerolled. 535 // transition to prerolled.
446 if (state_ != kPrerolling) 536 if (state_ == kPrerolling) {
447 return; 537 DCHECK(!current_frame_);
538 state_ = kPrerolled;
448 539
449 state_ = kPrerolled; 540 // Because we might remain in the prerolled state for an undetermined amount
541 // of time (i.e., we were not playing before we started prerolling), we'll
542 // manually update the current frame and notify the subclass below.
543 if (!ready_frames_.front()->IsEndOfStream())
544 SetCurrentFrameToNextReadyFrame();
450 545
451 // Because we might remain in the prerolled state for an undetermined amount 546 // ...and we're done prerolling!
452 // of time (e.g., we seeked while paused), we'll paint the first prerolled 547 DCHECK(!preroll_cb_.is_null());
453 // frame. 548 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK);
454 if (!ready_frames_.front()->IsEndOfStream())
455 PaintNextReadyFrame_Locked();
456 549
457 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK); 550 base::AutoUnlock ul(lock_);
551 paint_cb_.Run();
552 }
458 } 553 }
459 554
460 void VideoRendererBase::AddReadyFrame(const scoped_refptr<VideoFrame>& frame) { 555 void VideoRendererBase::AddReadyFrame(const scoped_refptr<VideoFrame>& frame) {
461 // Adjust the incoming frame if its rendering stop time is past the duration 556 // Adjust the incoming frame if its rendering stop time is past the duration
462 // of the video itself. This is typically the last frame of the video and 557 // of the video itself. This is typically the last frame of the video and
463 // occurs if the container specifies a duration that isn't a multiple of the 558 // occurs if the container specifies a duration that isn't a multiple of the
464 // frame rate. Another way for this to happen is for the container to state a 559 // frame rate. Another way for this to happen is for the container to state a
465 // smaller duration than the largest packet timestamp. 560 // smaller duration than the largest packet timestamp.
466 base::TimeDelta duration = get_duration_cb_.Run(); 561 base::TimeDelta duration = get_duration_cb_.Run();
467 if (frame->IsEndOfStream()) { 562 if (frame->IsEndOfStream()) {
468 base::TimeDelta end_timestamp = kNoTimestamp(); 563 base::TimeDelta end_timestamp = kNoTimestamp();
469 if (!ready_frames_.empty()) { 564 if (!ready_frames_.empty()) {
470 end_timestamp = std::min( 565 end_timestamp = std::min(
471 duration, 566 duration,
472 ready_frames_.back()->GetTimestamp() + kMaxLastFrameDuration()); 567 ready_frames_.back()->GetTimestamp() + kMaxLastFrameDuration());
473 } else if (last_timestamp_ != kNoTimestamp()) { 568 } else if (current_frame_) {
474 end_timestamp = 569 end_timestamp =
475 std::min(duration, last_timestamp_ + kMaxLastFrameDuration()); 570 std::min(duration,
571 current_frame_->GetTimestamp() + kMaxLastFrameDuration());
476 } 572 }
477 frame->SetTimestamp(end_timestamp); 573 frame->SetTimestamp(end_timestamp);
478 } else if (frame->GetTimestamp() > duration) { 574 } else if (frame->GetTimestamp() > duration) {
479 frame->SetTimestamp(duration); 575 frame->SetTimestamp(duration);
480 } 576 }
481 577
482 ready_frames_.push_back(frame); 578 ready_frames_.push_back(frame);
483 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames); 579 DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames);
484 580
485 base::TimeDelta max_clock_time = 581 base::TimeDelta max_clock_time =
(...skipping 18 matching lines...) Expand all
504 (!ready_frames_.empty() && ready_frames_.back()->IsEndOfStream())) { 600 (!ready_frames_.empty() && ready_frames_.back()->IsEndOfStream())) {
505 return; 601 return;
506 } 602 }
507 603
508 switch (state_) { 604 switch (state_) {
509 case kPaused: 605 case kPaused:
510 case kFlushing: 606 case kFlushing:
511 case kPrerolling: 607 case kPrerolling:
512 case kPlaying: 608 case kPlaying:
513 pending_read_ = true; 609 pending_read_ = true;
514 decoder_->Read(base::Bind(&VideoRendererBase::FrameReady, weak_this_)); 610 decoder_->Read(base::Bind(&VideoRendererBase::FrameReady, this));
515 return; 611 return;
516 612
517 case kUninitialized: 613 case kUninitialized:
518 case kPrerolled: 614 case kPrerolled:
519 case kFlushingDecoder: 615 case kFlushingDecoder:
520 case kFlushed: 616 case kFlushed:
521 case kEnded: 617 case kEnded:
522 case kStopped: 618 case kStopped:
523 case kError: 619 case kError:
524 return; 620 return;
525 } 621 }
526 } 622 }
527 623
528 void VideoRendererBase::OnDecoderResetDone() { 624 void VideoRendererBase::OnDecoderResetDone() {
529 base::AutoLock auto_lock(lock_); 625 base::AutoLock auto_lock(lock_);
530 DCHECK_EQ(kFlushingDecoder, state_); 626 DCHECK_EQ(kFlushingDecoder, state_);
531 DCHECK(!pending_read_); 627 DCHECK(!pending_read_);
532 628
533 state_ = kFlushing; 629 state_ = kFlushing;
534 AttemptFlush_Locked(); 630 AttemptFlush_Locked();
535 } 631 }
536 632
537 void VideoRendererBase::AttemptFlush_Locked() { 633 void VideoRendererBase::AttemptFlush_Locked() {
538 lock_.AssertAcquired(); 634 lock_.AssertAcquired();
539 DCHECK_EQ(kFlushing, state_); 635 DCHECK_EQ(kFlushing, state_);
540 636
541 prerolling_delayed_frame_ = NULL; 637 prerolling_delayed_frame_ = NULL;
542 ready_frames_.clear(); 638 ready_frames_.clear();
543 639
544 if (pending_read_) 640 if (!pending_paint_ && !pending_read_) {
545 return; 641 state_ = kFlushed;
546 642 current_frame_ = NULL;
547 state_ = kFlushed; 643 base::ResetAndReturn(&flush_cb_).Run();
548 last_timestamp_ = kNoTimestamp(); 644 }
549 base::ResetAndReturn(&flush_cb_).Run();
550 } 645 }
551 646
552 base::TimeDelta VideoRendererBase::CalculateSleepDuration( 647 base::TimeDelta VideoRendererBase::CalculateSleepDuration(
553 const scoped_refptr<VideoFrame>& next_frame, 648 const scoped_refptr<VideoFrame>& next_frame,
554 float playback_rate) { 649 float playback_rate) {
555 // Determine the current and next presentation timestamps. 650 // Determine the current and next presentation timestamps.
556 base::TimeDelta now = get_time_cb_.Run(); 651 base::TimeDelta now = get_time_cb_.Run();
557 base::TimeDelta next_pts = next_frame->GetTimestamp(); 652 base::TimeDelta next_pts = next_frame->GetTimestamp();
558 653
559 // Scale our sleep based on the playback rate. 654 // Scale our sleep based on the playback rate.
560 base::TimeDelta sleep = next_pts - now; 655 base::TimeDelta sleep = next_pts - now;
561 return base::TimeDelta::FromMicroseconds( 656 return base::TimeDelta::FromMicroseconds(
562 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); 657 static_cast<int64>(sleep.InMicroseconds() / playback_rate));
563 } 658 }
564 659
565 void VideoRendererBase::DoStopOrError_Locked() { 660 void VideoRendererBase::DoStopOrError_Locked() {
661 DCHECK(!pending_paint_);
662 DCHECK(!pending_paint_with_last_available_);
566 lock_.AssertAcquired(); 663 lock_.AssertAcquired();
567 last_timestamp_ = kNoTimestamp(); 664 current_frame_ = NULL;
665 last_available_frame_ = NULL;
568 ready_frames_.clear(); 666 ready_frames_.clear();
569 } 667 }
570 668
571 int VideoRendererBase::NumFrames_Locked() const { 669 int VideoRendererBase::NumFrames_Locked() const {
572 lock_.AssertAcquired(); 670 lock_.AssertAcquired();
573 return ready_frames_.size(); 671 int outstanding_frames =
672 (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) +
673 (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0);
674 return ready_frames_.size() + outstanding_frames;
574 } 675 }
575 676
576 } // namespace media 677 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/video_renderer_base.h ('k') | media/filters/video_renderer_base_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698