| 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/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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |