| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/buffers.h" | 5 #include "media/base/buffers.h" |
| 6 #include "media/base/filter_host.h" | 6 #include "media/base/filter_host.h" |
| 7 #include "media/base/video_frame_impl.h" | 7 #include "media/base/video_frame_impl.h" |
| 8 #include "media/filters/video_renderer_base.h" | 8 #include "media/filters/video_renderer_base.h" |
| 9 | 9 |
| 10 namespace media { | 10 namespace media { |
| 11 | 11 |
| 12 // Limit our read ahead to three frames. One frame is typically in flux at all | 12 // Limit our read ahead to three frames. One frame is typically in flux at all |
| 13 // times, as in frame n is discarded at the top of ThreadMain() while frame | 13 // times, as in frame n is discarded at the top of ThreadMain() while frame |
| 14 // (n + kMaxFrames) is being asynchronously fetched. The remaining two frames | 14 // (n + kMaxFrames) is being asynchronously fetched. The remaining two frames |
| 15 // allow us to advance the current frame as well as read the timestamp of the | 15 // allow us to advance the current frame as well as read the timestamp of the |
| 16 // following frame for more accurate timing. | 16 // following frame for more accurate timing. |
| 17 // | 17 // |
| 18 // Increasing this number beyond 3 simply creates a larger buffer to work with | 18 // Increasing this number beyond 3 simply creates a larger buffer to work with |
| 19 // at the expense of memory (~0.5MB and ~1.3MB per frame for 480p and 720p | 19 // at the expense of memory (~0.5MB and ~1.3MB per frame for 480p and 720p |
| 20 // resolutions, respectively). This can help on lower-end systems if there are | 20 // resolutions, respectively). This can help on lower-end systems if there are |
| 21 // difficult sections in the movie and decoding slows down. | 21 // difficult sections in the movie and decoding slows down. |
| 22 static const size_t kMaxFrames = 3; | 22 static const size_t kMaxFrames = 3; |
| 23 | 23 |
| 24 // Sleeping for negative amounts actually hangs your thread on Windows! | 24 // This equates to ~16.67 fps, which is just slow enough to be tolerable when |
| 25 static const int64 kMinSleepMilliseconds = 0; | 25 // our video renderer is ahead of the audio playback. |
| 26 | 26 // |
| 27 // This equates to ~13.33 fps, which is just under the typical 15 fps that | 27 // A higher value will be a slower frame rate, which looks worse but allows the |
| 28 // lower quality cameras or shooting modes usually use for video encoding. | 28 // audio renderer to catch up faster. A lower value will be a smoother frame |
| 29 static const int64 kMaxSleepMilliseconds = 75; | 29 // rate, but results in the video being out of sync for longer. |
| 30 // |
| 31 // TODO(scherkus): what if the native frame rate is 15 or 10 fps? |
| 32 static const int64 kMaxSleepMilliseconds = 60; |
| 30 | 33 |
| 31 VideoRendererBase::VideoRendererBase() | 34 VideoRendererBase::VideoRendererBase() |
| 32 : width_(0), | 35 : width_(0), |
| 33 height_(0), | 36 height_(0), |
| 34 frame_available_(&lock_), | 37 frame_available_(&lock_), |
| 35 state_(kUninitialized), | 38 state_(kUninitialized), |
| 36 thread_(NULL), | 39 thread_(NULL), |
| 37 pending_reads_(0), | 40 pending_reads_(0), |
| 38 playback_rate_(0) { | 41 playback_rate_(0) { |
| 39 } | 42 } |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 continue; | 232 continue; |
| 230 } | 233 } |
| 231 | 234 |
| 232 // Update our current frame and attempt to grab the next frame. | 235 // Update our current frame and attempt to grab the next frame. |
| 233 current_frame_ = frames_.front(); | 236 current_frame_ = frames_.front(); |
| 234 if (frames_.size() >= 2) { | 237 if (frames_.size() >= 2) { |
| 235 next_frame = frames_[1]; | 238 next_frame = frames_[1]; |
| 236 } | 239 } |
| 237 } | 240 } |
| 238 | 241 |
| 242 // Calculate our sleep duration. |
| 243 base::TimeDelta sleep = CalculateSleepDuration(next_frame, playback_rate); |
| 244 int sleep_ms = static_cast<int>(sleep.InMilliseconds()); |
| 245 |
| 246 // If we're too far behind to catch up, simply drop the frame. |
| 247 // |
| 248 // This has the effect of potentially dropping a few frames when playback |
| 249 // resumes after being paused. The alternative (sleeping for 0 milliseconds |
| 250 // and trying to catch up) looks worse. |
| 251 if (sleep_ms < 0) |
| 252 continue; |
| 253 |
| 254 // To be safe, limit our sleep duration. |
| 255 // TODO(scherkus): handle seeking gracefully.. right now we tend to hit |
| 256 // kMaxSleepMilliseconds a lot when we seek backwards. |
| 257 if (sleep_ms > kMaxSleepMilliseconds) |
| 258 sleep_ms = kMaxSleepMilliseconds; |
| 259 |
| 239 // Notify subclass that |current_frame_| has been updated. | 260 // Notify subclass that |current_frame_| has been updated. |
| 240 OnFrameAvailable(); | 261 OnFrameAvailable(); |
| 241 | 262 |
| 242 // Calculate our sleep duration. | |
| 243 base::TimeDelta sleep = CalculateSleepDuration(next_frame, playback_rate); | |
| 244 | |
| 245 // To be safe, limit our sleep duration. | |
| 246 // TODO(scherkus): handle seeking gracefully.. right now a seek backwards | |
| 247 // will hit kMinSleepMilliseconds whereas a seek forward will hit | |
| 248 // kMaxSleepMilliseconds. | |
| 249 int sleep_ms = static_cast<int>(sleep.InMilliseconds()); | |
| 250 if (sleep_ms < kMinSleepMilliseconds) | |
| 251 sleep_ms = kMinSleepMilliseconds; | |
| 252 else if (sleep_ms > kMaxSleepMilliseconds) | |
| 253 sleep_ms = kMaxSleepMilliseconds; | |
| 254 | |
| 255 PlatformThread::Sleep(sleep_ms); | 263 PlatformThread::Sleep(sleep_ms); |
| 256 } | 264 } |
| 257 } | 265 } |
| 258 | 266 |
| 259 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { | 267 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { |
| 260 AutoLock auto_lock(lock_); | 268 AutoLock auto_lock(lock_); |
| 261 // We should have initialized and have the current frame. | 269 // We should have initialized and have the current frame. |
| 262 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying); | 270 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying); |
| 263 DCHECK(current_frame_); | 271 DCHECK(current_frame_); |
| 264 *frame_out = current_frame_; | 272 *frame_out = current_frame_; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 surface.data[VideoSurface::kVPlane] | 385 surface.data[VideoSurface::kVPlane] |
| 378 += surface.strides[VideoSurface::kVPlane]; | 386 += surface.strides[VideoSurface::kVPlane]; |
| 379 } | 387 } |
| 380 frame->Unlock(); | 388 frame->Unlock(); |
| 381 | 389 |
| 382 // Success! | 390 // Success! |
| 383 *frame_out = frame; | 391 *frame_out = frame; |
| 384 } | 392 } |
| 385 | 393 |
| 386 } // namespace media | 394 } // namespace media |
| OLD | NEW |