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

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

Issue 390733002: Revert of Remove media::VideoRenderer::SetPlaybackRate(). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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_impl.h ('k') | media/filters/video_renderer_impl_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 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"
(...skipping 16 matching lines...) Expand all
27 : task_runner_(task_runner), 27 : task_runner_(task_runner),
28 video_frame_stream_(task_runner, decoders.Pass(), set_decryptor_ready_cb), 28 video_frame_stream_(task_runner, decoders.Pass(), set_decryptor_ready_cb),
29 low_delay_(false), 29 low_delay_(false),
30 received_end_of_stream_(false), 30 received_end_of_stream_(false),
31 rendered_end_of_stream_(false), 31 rendered_end_of_stream_(false),
32 frame_available_(&lock_), 32 frame_available_(&lock_),
33 state_(kUninitialized), 33 state_(kUninitialized),
34 thread_(), 34 thread_(),
35 pending_read_(false), 35 pending_read_(false),
36 drop_frames_(drop_frames), 36 drop_frames_(drop_frames),
37 playback_rate_(0),
37 buffering_state_(BUFFERING_HAVE_NOTHING), 38 buffering_state_(BUFFERING_HAVE_NOTHING),
38 paint_cb_(paint_cb), 39 paint_cb_(paint_cb),
39 last_timestamp_(kNoTimestamp()), 40 last_timestamp_(kNoTimestamp()),
40 frames_decoded_(0), 41 frames_decoded_(0),
41 frames_dropped_(0), 42 frames_dropped_(0),
42 weak_factory_(this) { 43 weak_factory_(this) {
43 DCHECK(!paint_cb_.is_null()); 44 DCHECK(!paint_cb_.is_null());
44 } 45 }
45 46
46 VideoRendererImpl::~VideoRendererImpl() { 47 VideoRendererImpl::~VideoRendererImpl() {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 } 99 }
99 100
100 if (!thread_to_join.is_null()) { 101 if (!thread_to_join.is_null()) {
101 base::AutoUnlock auto_unlock(lock_); 102 base::AutoUnlock auto_unlock(lock_);
102 base::PlatformThread::Join(thread_to_join); 103 base::PlatformThread::Join(thread_to_join);
103 } 104 }
104 105
105 video_frame_stream_.Stop(callback); 106 video_frame_stream_.Stop(callback);
106 } 107 }
107 108
109 void VideoRendererImpl::SetPlaybackRate(float playback_rate) {
110 DCHECK(task_runner_->BelongsToCurrentThread());
111 base::AutoLock auto_lock(lock_);
112 playback_rate_ = playback_rate;
113 }
114
108 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { 115 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
109 DCHECK(task_runner_->BelongsToCurrentThread()); 116 DCHECK(task_runner_->BelongsToCurrentThread());
110 base::AutoLock auto_lock(lock_); 117 base::AutoLock auto_lock(lock_);
111 DCHECK_EQ(state_, kFlushed); 118 DCHECK_EQ(state_, kFlushed);
112 DCHECK(!pending_read_); 119 DCHECK(!pending_read_);
113 DCHECK(ready_frames_.empty()); 120 DCHECK(ready_frames_.empty());
114 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 121 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
115 122
116 state_ = kPlaying; 123 state_ = kPlaying;
117 start_timestamp_ = timestamp; 124 start_timestamp_ = timestamp;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 base::TimeDelta::FromMilliseconds(10); 214 base::TimeDelta::FromMilliseconds(10);
208 215
209 for (;;) { 216 for (;;) {
210 base::AutoLock auto_lock(lock_); 217 base::AutoLock auto_lock(lock_);
211 218
212 // Thread exit condition. 219 // Thread exit condition.
213 if (state_ == kStopped) 220 if (state_ == kStopped)
214 return; 221 return;
215 222
216 // Remain idle as long as we're not playing. 223 // Remain idle as long as we're not playing.
217 if (state_ != kPlaying || buffering_state_ != BUFFERING_HAVE_ENOUGH) { 224 if (state_ != kPlaying || playback_rate_ == 0 ||
225 buffering_state_ != BUFFERING_HAVE_ENOUGH) {
218 UpdateStatsAndWait_Locked(kIdleTimeDelta); 226 UpdateStatsAndWait_Locked(kIdleTimeDelta);
219 continue; 227 continue;
220 } 228 }
221 229
222 // Remain idle until we have the next frame ready for rendering. 230 // Remain idle until we have the next frame ready for rendering.
223 if (ready_frames_.empty()) { 231 if (ready_frames_.empty()) {
224 if (received_end_of_stream_ && !rendered_end_of_stream_) { 232 if (received_end_of_stream_ && !rendered_end_of_stream_) {
225 rendered_end_of_stream_ = true; 233 rendered_end_of_stream_ = true;
226 ended_cb_.Run(); 234 ended_cb_.Run();
227 } 235 }
228 236
229 UpdateStatsAndWait_Locked(kIdleTimeDelta); 237 UpdateStatsAndWait_Locked(kIdleTimeDelta);
230 continue; 238 continue;
231 } 239 }
232 240
233 base::TimeDelta now = get_time_cb_.Run(); 241 base::TimeDelta remaining_time =
234 base::TimeDelta target_timestamp = ready_frames_.front()->timestamp(); 242 CalculateSleepDuration(ready_frames_.front(), playback_rate_);
235 base::TimeDelta earliest_paint_timestamp; 243
236 base::TimeDelta latest_paint_timestamp; 244 // Sleep up to a maximum of our idle time until we're within the time to
245 // render the next frame.
246 if (remaining_time.InMicroseconds() > 0) {
247 remaining_time = std::min(remaining_time, kIdleTimeDelta);
248 UpdateStatsAndWait_Locked(remaining_time);
249 continue;
250 }
237 251
238 // Deadline is defined as the midpoint between this frame and the next 252 // Deadline is defined as the midpoint between this frame and the next
239 // frame, using the delta between this frame and the previous frame as the 253 // frame, using the delta between this frame and the previous frame as the
240 // assumption for frame duration. 254 // assumption for frame duration.
241 // 255 //
242 // TODO(scherkus): An improvement over midpoint might be selecting the 256 // TODO(scherkus): An improvement over midpoint might be selecting the
243 // minimum and/or maximum between the midpoint and some constants. As a 257 // minimum and/or maximum between the midpoint and some constants. As a
244 // thought experiment, consider what would be better than the midpoint 258 // thought experiment, consider what would be better than the midpoint
245 // for both the 1fps case and 120fps case. 259 // for both the 1fps case and 120fps case.
246 // 260 //
247 // TODO(scherkus): This can be vastly improved. Use a histogram to measure 261 // TODO(scherkus): This can be vastly improved. Use a histogram to measure
248 // the accuracy of our frame timing code. http://crbug.com/149829 262 // the accuracy of our frame timing code. http://crbug.com/149829
249 if (last_timestamp_ == kNoTimestamp()) { 263 if (drop_frames_ && last_timestamp_ != kNoTimestamp()) {
250 earliest_paint_timestamp = target_timestamp; 264 base::TimeDelta now = get_time_cb_.Run();
251 latest_paint_timestamp = base::TimeDelta::Max(); 265 base::TimeDelta deadline = ready_frames_.front()->timestamp() +
252 } else { 266 (ready_frames_.front()->timestamp() - last_timestamp_) / 2;
253 base::TimeDelta duration = target_timestamp - last_timestamp_;
254 earliest_paint_timestamp = target_timestamp - duration / 2;
255 latest_paint_timestamp = target_timestamp + duration / 2;
256 }
257 267
258 // Remain idle until we've reached our target paint window. 268 if (now > deadline) {
259 if (now < earliest_paint_timestamp) { 269 DropNextReadyFrame_Locked();
260 UpdateStatsAndWait_Locked(kIdleTimeDelta); 270 continue;
261 continue; 271 }
262 }
263
264 if (now > latest_paint_timestamp && drop_frames_) {
265 DropNextReadyFrame_Locked();
266 continue;
267 } 272 }
268 273
269 // Congratulations! You've made it past the video frame timing gauntlet. 274 // Congratulations! You've made it past the video frame timing gauntlet.
270 // 275 //
271 // At this point enough time has passed that the next frame that ready for 276 // At this point enough time has passed that the next frame that ready for
272 // rendering. 277 // rendering.
273 PaintNextReadyFrame_Locked(); 278 PaintNextReadyFrame_Locked();
274 } 279 }
275 } 280 }
276 281
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 DCHECK(ready_frames_.empty()); 470 DCHECK(ready_frames_.empty());
466 DCHECK(!received_end_of_stream_); 471 DCHECK(!received_end_of_stream_);
467 DCHECK(!rendered_end_of_stream_); 472 DCHECK(!rendered_end_of_stream_);
468 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 473 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
469 474
470 state_ = kFlushed; 475 state_ = kFlushed;
471 last_timestamp_ = kNoTimestamp(); 476 last_timestamp_ = kNoTimestamp();
472 base::ResetAndReturn(&flush_cb_).Run(); 477 base::ResetAndReturn(&flush_cb_).Run();
473 } 478 }
474 479
480 base::TimeDelta VideoRendererImpl::CalculateSleepDuration(
481 const scoped_refptr<VideoFrame>& next_frame,
482 float playback_rate) {
483 // Determine the current and next presentation timestamps.
484 base::TimeDelta now = get_time_cb_.Run();
485 base::TimeDelta next_pts = next_frame->timestamp();
486
487 // Scale our sleep based on the playback rate.
488 base::TimeDelta sleep = next_pts - now;
489 return base::TimeDelta::FromMicroseconds(
490 static_cast<int64>(sleep.InMicroseconds() / playback_rate));
491 }
492
475 void VideoRendererImpl::DoStopOrError_Locked() { 493 void VideoRendererImpl::DoStopOrError_Locked() {
476 lock_.AssertAcquired(); 494 lock_.AssertAcquired();
477 last_timestamp_ = kNoTimestamp(); 495 last_timestamp_ = kNoTimestamp();
478 ready_frames_.clear(); 496 ready_frames_.clear();
479 } 497 }
480 498
481 void VideoRendererImpl::UpdateStatsAndWait_Locked( 499 void VideoRendererImpl::UpdateStatsAndWait_Locked(
482 base::TimeDelta wait_duration) { 500 base::TimeDelta wait_duration) {
483 lock_.AssertAcquired(); 501 lock_.AssertAcquired();
484 DCHECK_GE(frames_decoded_, 0); 502 DCHECK_GE(frames_decoded_, 0);
485 DCHECK_LE(frames_dropped_, frames_decoded_); 503 DCHECK_LE(frames_dropped_, frames_decoded_);
486 504
487 if (frames_decoded_) { 505 if (frames_decoded_) {
488 PipelineStatistics statistics; 506 PipelineStatistics statistics;
489 statistics.video_frames_decoded = frames_decoded_; 507 statistics.video_frames_decoded = frames_decoded_;
490 statistics.video_frames_dropped = frames_dropped_; 508 statistics.video_frames_dropped = frames_dropped_;
491 statistics_cb_.Run(statistics); 509 statistics_cb_.Run(statistics);
492 510
493 frames_decoded_ = 0; 511 frames_decoded_ = 0;
494 frames_dropped_ = 0; 512 frames_dropped_ = 0;
495 } 513 }
496 514
497 frame_available_.TimedWait(wait_duration); 515 frame_available_.TimedWait(wait_duration);
498 } 516 }
499 517
500 } // namespace media 518 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/video_renderer_impl.h ('k') | media/filters/video_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698