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

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

Issue 3014059: media: recycle buffers/direct rendering etc. (third patch) (Closed)
Patch Set: code review Created 10 years, 3 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
« 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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "base/callback.h" 5 #include "base/callback.h"
6 #include "media/base/buffers.h" 6 #include "media/base/buffers.h"
7 #include "media/base/callback.h" 7 #include "media/base/callback.h"
8 #include "media/base/filter_host.h" 8 #include "media/base/filter_host.h"
9 #include "media/base/limits.h"
9 #include "media/base/video_frame.h" 10 #include "media/base/video_frame.h"
10 #include "media/filters/video_renderer_base.h" 11 #include "media/filters/video_renderer_base.h"
11 12
12 namespace media { 13 namespace media {
13 14
14 // Limit our read ahead to at least 3 frames. One frame is typically in flux at
15 // all times, as in frame n is discarded at the top of ThreadMain() while frame
16 // (n + kMaxFrames) is being asynchronously fetched. The remaining two frames
17 // allow us to advance the current frame as well as read the timestamp of the
18 // following frame for more accurate timing.
19 //
20 // Increasing this number beyond 3 simply creates a larger buffer to work with
21 // at the expense of memory (~0.5MB and ~1.3MB per frame for 480p and 720p
22 // resolutions, respectively). This can help on lower-end systems if there are
23 // difficult sections in the movie and decoding slows down.
24 //
25 // Set to 4 because some vendor's driver doesn't allow buffer count to go below
26 // preset limit, e.g., EGLImage path.
27 static const size_t kMaxFrames = 4;
28
29 // This equates to ~16.67 fps, which is just slow enough to be tolerable when 15 // This equates to ~16.67 fps, which is just slow enough to be tolerable when
30 // our video renderer is ahead of the audio playback. 16 // our video renderer is ahead of the audio playback.
31 // 17 //
32 // A higher value will be a slower frame rate, which looks worse but allows the 18 // A higher value will be a slower frame rate, which looks worse but allows the
33 // audio renderer to catch up faster. A lower value will be a smoother frame 19 // audio renderer to catch up faster. A lower value will be a smoother frame
34 // rate, but results in the video being out of sync for longer. 20 // rate, but results in the video being out of sync for longer.
35 static const int64 kMaxSleepMilliseconds = 60; 21 static const int64 kMaxSleepMilliseconds = 60;
36 22
37 // The number of milliseconds to idle when we do not have anything to do. 23 // The number of milliseconds to idle when we do not have anything to do.
38 // Nothing special about the value, other than we're being more OS-friendly 24 // Nothing special about the value, other than we're being more OS-friendly
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 return false; 70 return false;
85 if (!media_format.GetAsInteger(MediaFormat::kHeight, &height)) 71 if (!media_format.GetAsInteger(MediaFormat::kHeight, &height))
86 return false; 72 return false;
87 if (width_out) *width_out = width; 73 if (width_out) *width_out = width;
88 if (height_out) *height_out = height; 74 if (height_out) *height_out = height;
89 return true; 75 return true;
90 } 76 }
91 77
92 void VideoRendererBase::Play(FilterCallback* callback) { 78 void VideoRendererBase::Play(FilterCallback* callback) {
93 AutoLock auto_lock(lock_); 79 AutoLock auto_lock(lock_);
94 DCHECK(kPaused == state_ || kFlushing == state_); 80 DCHECK_EQ(kPrerolled, state_);
95 scoped_ptr<FilterCallback> c(callback); 81 scoped_ptr<FilterCallback> c(callback);
96 state_ = kPlaying; 82 state_ = kPlaying;
97 callback->Run(); 83 callback->Run();
98 } 84 }
99 85
100 void VideoRendererBase::Pause(FilterCallback* callback) { 86 void VideoRendererBase::Pause(FilterCallback* callback) {
101 AutoLock auto_lock(lock_); 87 AutoLock auto_lock(lock_);
102 DCHECK(state_ == kPlaying || state_ == kEnded); 88 DCHECK(state_ != kUninitialized || state_ == kError);
103 AutoCallbackRunner done_runner(callback); 89 AutoCallbackRunner done_runner(callback);
104 state_ = kPaused; 90 state_ = kPaused;
105 } 91 }
106 92
107 void VideoRendererBase::Flush(FilterCallback* callback) { 93 void VideoRendererBase::Flush(FilterCallback* callback) {
108 DCHECK(state_ == kPaused); 94 DCHECK_EQ(state_, kPaused);
109 95
110 AutoLock auto_lock(lock_); 96 AutoLock auto_lock(lock_);
111 flush_callback_.reset(callback); 97 flush_callback_.reset(callback);
112 state_ = kFlushing; 98 state_ = kFlushing;
113 99
114 // Filter is considered paused when we've finished all pending reads, which 100 if (pending_paint_ == false)
115 // implies all buffers are returned to owner in Decoder/Renderer. Renderer
116 // is considered paused with one more contingency that |pending_paint_| is
117 // false, such that no client of us is holding any reference to VideoFrame.
118 if (pending_reads_ == 0 && pending_paint_ == false) {
119 flush_callback_->Run();
120 flush_callback_.reset();
121 FlushBuffers(); 101 FlushBuffers();
122 }
123 } 102 }
124 103
125 void VideoRendererBase::Stop(FilterCallback* callback) { 104 void VideoRendererBase::Stop(FilterCallback* callback) {
105 DCHECK_EQ(pending_reads_, 0);
106
126 { 107 {
127 AutoLock auto_lock(lock_); 108 AutoLock auto_lock(lock_);
128 state_ = kStopped; 109 state_ = kStopped;
129 110
130 // TODO(jiesun): move this to flush.
131 // TODO(jiesun): we should wait until pending_paint_ is false;
132 FlushBuffers();
133
134 // Clean up our thread if present. 111 // Clean up our thread if present.
135 if (thread_) { 112 if (thread_) {
136 // Signal the thread since it's possible to get stopped with the video 113 // Signal the thread since it's possible to get stopped with the video
137 // thread waiting for a read to complete. 114 // thread waiting for a read to complete.
138 frame_available_.Signal(); 115 frame_available_.Signal();
139 { 116 {
140 AutoUnlock auto_unlock(lock_); 117 AutoUnlock auto_unlock(lock_);
141 PlatformThread::Join(thread_); 118 PlatformThread::Join(thread_);
142 } 119 }
143 thread_ = kNullThreadHandle; 120 thread_ = kNullThreadHandle;
144 } 121 }
145 122
146 } 123 }
147 // Signal the subclass we're stopping. 124 // Signal the subclass we're stopping.
148 OnStop(callback); 125 OnStop(callback);
149 } 126 }
150 127
151 void VideoRendererBase::SetPlaybackRate(float playback_rate) { 128 void VideoRendererBase::SetPlaybackRate(float playback_rate) {
152 AutoLock auto_lock(lock_); 129 AutoLock auto_lock(lock_);
153 playback_rate_ = playback_rate; 130 playback_rate_ = playback_rate;
154 } 131 }
155 132
156 void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { 133 void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) {
157 AutoLock auto_lock(lock_); 134 AutoLock auto_lock(lock_);
158 DCHECK(kPaused == state_ || kFlushing == state_); 135 // There is a race condition between filters to receive SeekTask().
159 DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed"; 136 // It turns out we could receive buffer from decoder before seek()
160 state_ = kSeeking; 137 // is called on us. so we do the following:
161 seek_callback_.reset(callback); 138 // kFlushed => ( Receive first buffer or Seek() ) => kSeeking and
162 seek_timestamp_ = time; 139 // kSeeking => ( Receive enough buffers) => kPrerolled. )
140 DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_);
163 141
164 // Throw away everything and schedule our reads. 142 if (state_ == kPrerolled) {
165 // TODO(jiesun): this should be guaranteed by pause/flush before seek happen. 143 // Already get enough buffers from decoder.
166 frames_queue_ready_.clear(); 144 callback->Run();
167 frames_queue_done_.clear(); 145 delete callback;
168 for (size_t i = 0; i < kMaxFrames; ++i) { 146 } else {
169 // TODO(jiesun): this is dummy read for ffmpeg path until we truely recycle 147 // Otherwise we are either kFlushed or kSeeking, but without enough buffers;
170 // in that path. 148 // we should save the callback function and call it later.
171 scoped_refptr<VideoFrame> null_frame; 149 state_ = kSeeking;
172 frames_queue_done_.push_back(null_frame); 150 seek_callback_.reset(callback);
173 } 151 }
174 152
175 // TODO(jiesun): if EGL image path make sure those video frames are already in 153 seek_timestamp_ = time;
176 // frames_queue_done_, we could remove FillThisBuffer call from derived class.
177 // But currently that is trigger by first paint(), which is bad.
178 ScheduleRead_Locked(); 154 ScheduleRead_Locked();
179 } 155 }
180 156
181 void VideoRendererBase::Initialize(VideoDecoder* decoder, 157 void VideoRendererBase::Initialize(VideoDecoder* decoder,
182 FilterCallback* callback) { 158 FilterCallback* callback) {
183 AutoLock auto_lock(lock_); 159 AutoLock auto_lock(lock_);
184 DCHECK(decoder); 160 DCHECK(decoder);
185 DCHECK(callback); 161 DCHECK(callback);
186 DCHECK_EQ(kUninitialized, state_); 162 DCHECK_EQ(kUninitialized, state_);
187 decoder_ = decoder; 163 decoder_ = decoder;
188 scoped_ptr<FilterCallback> c(callback); 164 AutoCallbackRunner done_runner(callback);
189 165
190 decoder_->set_fill_buffer_done_callback( 166 decoder_->set_fill_buffer_done_callback(
191 NewCallback(this, &VideoRendererBase::OnFillBufferDone)); 167 NewCallback(this, &VideoRendererBase::OnFillBufferDone));
192 // Notify the pipeline of the video dimensions. 168 // Notify the pipeline of the video dimensions.
193 if (!ParseMediaFormat(decoder->media_format(), 169 if (!ParseMediaFormat(decoder->media_format(),
194 &surface_type_, 170 &surface_type_,
195 &surface_format_, 171 &surface_format_,
196 &width_, &height_)) { 172 &width_, &height_)) {
197 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); 173 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED);
198 callback->Run(); 174 state_ = kError;
199 return; 175 return;
200 } 176 }
201 host()->SetVideoSize(width_, height_); 177 host()->SetVideoSize(width_, height_);
202 178
203 // Initialize the subclass. 179 // Initialize the subclass.
204 // TODO(scherkus): do we trust subclasses not to do something silly while 180 // TODO(scherkus): do we trust subclasses not to do something silly while
205 // we're holding the lock? 181 // we're holding the lock?
206 if (!OnInitialize(decoder)) { 182 if (!OnInitialize(decoder)) {
207 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); 183 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED);
208 callback->Run(); 184 state_ = kError;
209 return; 185 return;
210 } 186 }
211 187
212 // We're all good! Consider ourselves paused (ThreadMain() should never 188 // We're all good! Consider ourselves flushed. (ThreadMain() should never
213 // see us in the kUninitialized state). 189 // see us in the kUninitialized state).
214 state_ = kPaused; 190 // Since we had an initial Seek, we consider ourself flushed, because we
191 // have not populated any buffers yet.
192 state_ = kFlushed;
215 193
216 // Create our video thread. 194 // Create our video thread.
217 if (!PlatformThread::Create(0, this, &thread_)) { 195 if (!PlatformThread::Create(0, this, &thread_)) {
218 NOTREACHED() << "Video thread creation failed"; 196 NOTREACHED() << "Video thread creation failed";
219 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); 197 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED);
220 callback->Run(); 198 state_ = kError;
221 return; 199 return;
222 } 200 }
223 201
224 #if defined(OS_WIN) 202 #if defined(OS_WIN)
225 // Bump up our priority so our sleeping is more accurate. 203 // Bump up our priority so our sleeping is more accurate.
226 // TODO(scherkus): find out if this is necessary, but it seems to help. 204 // TODO(scherkus): find out if this is necessary, but it seems to help.
227 ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); 205 ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
228 #endif // defined(OS_WIN) 206 #endif // defined(OS_WIN)
229 207
230 // Finally, execute the start callback.
231 callback->Run();
232 } 208 }
233 209
234 bool VideoRendererBase::HasEnded() { 210 bool VideoRendererBase::HasEnded() {
235 AutoLock auto_lock(lock_); 211 AutoLock auto_lock(lock_);
236 return state_ == kEnded; 212 return state_ == kEnded;
237 } 213 }
238 214
239 // PlatformThread::Delegate implementation. 215 // PlatformThread::Delegate implementation.
240 void VideoRendererBase::ThreadMain() { 216 void VideoRendererBase::ThreadMain() {
241 PlatformThread::SetName("CrVideoRenderer"); 217 PlatformThread::SetName("CrVideoRenderer");
(...skipping 17 matching lines...) Expand all
259 else 235 else
260 remaining_time = kIdleTimeDelta; 236 remaining_time = kIdleTimeDelta;
261 } else { 237 } else {
262 // Calculate how long until we should advance the frame, which is 238 // Calculate how long until we should advance the frame, which is
263 // typically negative but for playback rates < 1.0f may be long enough 239 // typically negative but for playback rates < 1.0f may be long enough
264 // that it makes more sense to idle and check again. 240 // that it makes more sense to idle and check again.
265 scoped_refptr<VideoFrame> next_frame = frames_queue_ready_.front(); 241 scoped_refptr<VideoFrame> next_frame = frames_queue_ready_.front();
266 remaining_time = CalculateSleepDuration(next_frame, playback_rate_); 242 remaining_time = CalculateSleepDuration(next_frame, playback_rate_);
267 } 243 }
268 244
245 // TODO(jiesun): I do not think we should wake up every 10ms.
246 // We should only wait up when following is true:
247 // 1. frame arrival (use event);
248 // 2. state_ change (use event);
249 // 3. playback_rate_ change (use event);
250 // 4. next frame's pts (use timeout);
269 if (remaining_time > kIdleTimeDelta) 251 if (remaining_time > kIdleTimeDelta)
270 remaining_time = kIdleTimeDelta; 252 remaining_time = kIdleTimeDelta;
253
254 // We can not do anything about this until next frame arrival.
255 // We do not want to spin in this case though.
256 if (remaining_time.InMicroseconds() < 0 && frames_queue_ready_.empty())
257 remaining_time = kIdleTimeDelta;
258
271 if (remaining_time.InMicroseconds() > 0) 259 if (remaining_time.InMicroseconds() > 0)
272 frame_available_.TimedWait(remaining_time); 260 frame_available_.TimedWait(remaining_time);
273 261
274 if (state_ != kPlaying || playback_rate_ == 0) 262 if (state_ != kPlaying || playback_rate_ == 0)
275 continue; 263 continue;
276 264
277 // Otherwise we're playing, so advance the frame and keep reading from the 265 // Otherwise we're playing, so advance the frame and keep reading from the
278 // decoder when following condition is satisfied: 266 // decoder when following condition is satisfied:
279 // 1. We had at least one backup frame. 267 // 1. We had at least one backup frame.
280 // 2. We had not reached end of stream. 268 // 2. We had not reached end of stream.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 frames_queue_ready_[1]->GetTimestamp() - host()->GetTime(); 304 frames_queue_ready_[1]->GetTimestamp() - host()->GetTime();
317 if (next_remaining_time.InMicroseconds() <= 0) { 305 if (next_remaining_time.InMicroseconds() <= 0) {
318 // Since the current frame is still hold by painter/compositor, and 306 // Since the current frame is still hold by painter/compositor, and
319 // the next frame is already timed-out, we should skip the next frame 307 // the next frame is already timed-out, we should skip the next frame
320 // which is the first frame in the queue. 308 // which is the first frame in the queue.
321 timeout_frame = frames_queue_ready_.front(); 309 timeout_frame = frames_queue_ready_.front();
322 frames_queue_ready_.pop_front(); 310 frames_queue_ready_.pop_front();
323 } 311 }
324 } 312 }
325 if (timeout_frame.get()) { 313 if (timeout_frame.get()) {
326 // TODO(jiesun): we should really merge the following branch. That way 314 frames_queue_done_.push_back(timeout_frame);
327 // we will remove the last EGLImage hack in this class. but the 315 ScheduleRead_Locked();
328 // |pending_reads_| prevents use to do so (until we had implemented
329 // flush logic and get rid of pending reads.)
330 if (uses_egl_image() &&
331 media::VideoFrame::TYPE_EGL_IMAGE == timeout_frame->type()) {
332 decoder_->FillThisBuffer(timeout_frame);
333 } else {
334 // TODO(jiesun): could this be merged with EGLimage path?
335 frames_queue_done_.push_back(timeout_frame);
336 ScheduleRead_Locked();
337 }
338 } 316 }
339 if (new_frame_available) { 317 if (new_frame_available) {
340 AutoUnlock auto_unlock(lock_); 318 AutoUnlock auto_unlock(lock_);
341 // Notify subclass that |current_frame_| has been updated. 319 // Notify subclass that |current_frame_| has been updated.
342 OnFrameAvailable(); 320 OnFrameAvailable();
343 } 321 }
344 } 322 }
345 } 323 }
346 } 324 }
347 325
348 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { 326 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) {
349 AutoLock auto_lock(lock_); 327 AutoLock auto_lock(lock_);
350 DCHECK(!pending_paint_); 328 DCHECK(!pending_paint_);
351 329
352 if (state_ == kStopped || !current_frame_.get() || 330 if (!current_frame_.get() || current_frame_->IsEndOfStream()) {
353 current_frame_->IsEndOfStream()) {
354 *frame_out = NULL; 331 *frame_out = NULL;
355 return; 332 return;
356 } 333 }
357 334
358 // We should have initialized and have the current frame. 335 // We should have initialized and have the current frame.
359 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || 336 DCHECK(state_ != kUninitialized && state_ != kStopped && state_ != kError);
360 state_ == kFlushing || state_ == kEnded);
361 *frame_out = current_frame_; 337 *frame_out = current_frame_;
362 pending_paint_ = true; 338 pending_paint_ = true;
363 } 339 }
364 340
365 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) { 341 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) {
366 AutoLock auto_lock(lock_); 342 AutoLock auto_lock(lock_);
367 343
368 // Note that we do not claim |pending_paint_| when we return NULL frame, in 344 // Note that we do not claim |pending_paint_| when we return NULL frame, in
369 // that case, |current_frame_| could be changed before PutCurrentFrame. 345 // that case, |current_frame_| could be changed before PutCurrentFrame.
370 DCHECK(pending_paint_ || frame.get() == NULL); 346 DCHECK(pending_paint_ || frame.get() == NULL);
371 DCHECK(current_frame_.get() == frame.get() || frame.get() == NULL); 347 DCHECK(current_frame_.get() == frame.get() || frame.get() == NULL);
372 348
373 pending_paint_ = false; 349 pending_paint_ = false;
374 // We had cleared the |pending_paint_| flag, there are chances that current 350 // We had cleared the |pending_paint_| flag, there are chances that current
375 // frame is timed-out. We will wake up our main thread to advance the current 351 // frame is timed-out. We will wake up our main thread to advance the current
376 // frame when this is true. 352 // frame when this is true.
377 frame_available_.Signal(); 353 frame_available_.Signal();
378 if (state_ == kFlushing && pending_reads_ == 0 && flush_callback_.get()) { 354 if (state_ == kFlushing)
379 // No more pending reads! We're now officially "paused".
380 FlushBuffers(); 355 FlushBuffers();
381 flush_callback_->Run();
382 flush_callback_.reset();
383 }
384 } 356 }
385 357
386 void VideoRendererBase::OnFillBufferDone(scoped_refptr<VideoFrame> frame) { 358 void VideoRendererBase::OnFillBufferDone(scoped_refptr<VideoFrame> frame) {
387 AutoLock auto_lock(lock_); 359 AutoLock auto_lock(lock_);
388 360
389 // TODO(ajwong): Work around cause we don't synchronize on stop. Correct 361 // Decoder could reach seek state before our Seek() get called.
390 // fix is to resolve http://crbug.com/16059. 362 // We will enter kSeeking
391 if (state_ == kStopped) { 363 if (kFlushed == state_)
392 // TODO(jiesun): Remove this when flush before stop landed! 364 state_ = kSeeking;
365
366 // Synchronous flush between filters should prevent this from happening.
367 DCHECK_NE(state_, kStopped);
368 if (frame.get() && !frame->IsEndOfStream())
369 --pending_reads_;
370
371 DCHECK(state_ != kUninitialized && state_ != kStopped && state_ != kError);
372
373 if (state_ == kPaused || state_ == kFlushing) {
374 // Decoder are flushing rubbish video frame, we will not display them.
375 if (frame.get() && !frame->IsEndOfStream())
376 frames_queue_done_.push_back(frame);
377 DCHECK_LE(frames_queue_done_.size(),
378 static_cast<size_t>(Limits::kMaxVideoFrames));
379
380 // Excluding kPause here, because in pause state, we will never
381 // transfer out-bounding buffer. We do not flush buffer when Compositor
382 // hold reference to our video frame either.
383 if (state_ == kFlushing && pending_paint_ == false)
384 FlushBuffers();
385
393 return; 386 return;
394 } 387 }
395 388
396 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying ||
397 state_ == kFlushing || state_ == kEnded);
398 DCHECK_GT(pending_reads_, 0u);
399 --pending_reads_;
400
401 // Discard frames until we reach our desired seek timestamp. 389 // Discard frames until we reach our desired seek timestamp.
402 if (state_ == kSeeking && !frame->IsEndOfStream() && 390 if (state_ == kSeeking && !frame->IsEndOfStream() &&
403 (frame->GetTimestamp() + frame->GetDuration()) < seek_timestamp_) { 391 (frame->GetTimestamp() + frame->GetDuration()) < seek_timestamp_) {
404 frames_queue_done_.push_back(frame); 392 frames_queue_done_.push_back(frame);
405 ScheduleRead_Locked(); 393 ScheduleRead_Locked();
406 } else { 394 } else {
407 frames_queue_ready_.push_back(frame); 395 frames_queue_ready_.push_back(frame);
408 DCHECK_LE(frames_queue_ready_.size(), kMaxFrames); 396 DCHECK_LE(frames_queue_ready_.size(),
397 static_cast<size_t>(Limits::kMaxVideoFrames));
409 frame_available_.Signal(); 398 frame_available_.Signal();
410 } 399 }
411 400
412 // Check for our preroll complete condition. 401 // Check for our preroll complete condition.
413 if (state_ == kSeeking) { 402 if (state_ == kSeeking) {
414 DCHECK(seek_callback_.get()); 403 if (frames_queue_ready_.size() == Limits::kMaxVideoFrames ||
415 if (frames_queue_ready_.size() == kMaxFrames || frame->IsEndOfStream()) { 404 frame->IsEndOfStream()) {
416 // We're paused, so make sure we update |current_frame_| to represent 405 // We're paused, so make sure we update |current_frame_| to represent
417 // our new location. 406 // our new location.
418 state_ = kPaused; 407 state_ = kPrerolled;
419 408
420 // Because we might remain paused (i.e., we were not playing before we 409 // Because we might remain paused (i.e., we were not playing before we
421 // received a seek), we can't rely on ThreadMain() to notify the subclass 410 // received a seek), we can't rely on ThreadMain() to notify the subclass
422 // the frame has been updated. 411 // the frame has been updated.
423 scoped_refptr<VideoFrame> first_frame; 412 scoped_refptr<VideoFrame> first_frame;
424 first_frame = frames_queue_ready_.front(); 413 first_frame = frames_queue_ready_.front();
425 if (!first_frame->IsEndOfStream()) { 414 if (!first_frame->IsEndOfStream()) {
426 frames_queue_ready_.pop_front(); 415 frames_queue_ready_.pop_front();
427 current_frame_ = first_frame; 416 current_frame_ = first_frame;
428 } 417 }
429 OnFrameAvailable(); 418 OnFrameAvailable();
430 419
431 seek_callback_->Run(); 420 // If we reach prerolled state before Seek() is called by pipeline,
432 seek_callback_.reset(); 421 // |seek_callback_| is not set, we will return immediately during
422 // when Seek() is eventually called.
423 if ((seek_callback_.get())) {
424 seek_callback_->Run();
425 seek_callback_.reset();
426 }
433 } 427 }
434 } else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) { 428 } else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) {
435 // No more pending reads! We're now officially "paused". 429 OnFlushDone();
436 if (flush_callback_.get()) {
437 flush_callback_->Run();
438 flush_callback_.reset();
439 }
440 } 430 }
441 } 431 }
442 432
433 void VideoRendererBase::ReadInput(scoped_refptr<VideoFrame> frame) {
434 // We should never return empty frames or EOS frame.
435 DCHECK(frame.get() && !frame->IsEndOfStream());
436
437 decoder_->FillThisBuffer(frame);
438 ++pending_reads_;
439 }
440
443 void VideoRendererBase::ScheduleRead_Locked() { 441 void VideoRendererBase::ScheduleRead_Locked() {
444 lock_.AssertAcquired(); 442 lock_.AssertAcquired();
445 DCHECK_NE(kEnded, state_); 443 DCHECK_NE(kEnded, state_);
446 // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to 444 // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to
447 // provide buffer pools. In the future, we may want to implement real 445 // provide buffer pools. In the future, we may want to implement real
448 // buffer pool to recycle buffers. 446 // buffer pool to recycle buffers.
449 while (!frames_queue_done_.empty()) { 447 while (!frames_queue_done_.empty()) {
450 scoped_refptr<VideoFrame> video_frame = frames_queue_done_.front(); 448 scoped_refptr<VideoFrame> video_frame = frames_queue_done_.front();
451 frames_queue_done_.pop_front(); 449 frames_queue_done_.pop_front();
452 decoder_->FillThisBuffer(video_frame); 450 ReadInput(video_frame);
453 DCHECK_LT(pending_reads_, kMaxFrames);
454 ++pending_reads_;
455 } 451 }
456 } 452 }
457 453
458 void VideoRendererBase::FlushBuffers() { 454 void VideoRendererBase::FlushBuffers() {
459 DCHECK(!pending_paint_); 455 DCHECK(!pending_paint_);
460 456
461 // We should never put EOF frame into "done queue". 457 // We should never put EOF frame into "done queue".
462 while (!frames_queue_ready_.empty()) { 458 while (!frames_queue_ready_.empty()) {
463 scoped_refptr<VideoFrame> video_frame = frames_queue_ready_.front(); 459 scoped_refptr<VideoFrame> video_frame = frames_queue_ready_.front();
464 if (!video_frame->IsEndOfStream()) { 460 if (!video_frame->IsEndOfStream()) {
465 frames_queue_done_.push_back(video_frame); 461 frames_queue_done_.push_back(video_frame);
466 } 462 }
467 frames_queue_ready_.pop_front(); 463 frames_queue_ready_.pop_front();
468 } 464 }
469 if (current_frame_.get() && !current_frame_->IsEndOfStream()) { 465 if (current_frame_.get() && !current_frame_->IsEndOfStream()) {
470 frames_queue_done_.push_back(current_frame_); 466 frames_queue_done_.push_back(current_frame_);
471 } 467 }
472 current_frame_ = NULL; 468 current_frame_ = NULL;
469
470 if (decoder_->ProvidesBuffer()) {
471 // Flush all buffers out to decoder;
472 ScheduleRead_Locked();
473 }
474
475 if (pending_reads_ == 0)
476 OnFlushDone();
477 }
478
479 void VideoRendererBase::OnFlushDone() {
480 // Check all buffers are return to owners.
481 if (decoder_->ProvidesBuffer()) {
482 DCHECK_EQ(frames_queue_done_.size(), 0u);
483 } else {
484 DCHECK_EQ(frames_queue_done_.size(),
485 static_cast<size_t>(Limits::kMaxVideoFrames));
486 }
487 DCHECK(!current_frame_.get());
488 DCHECK(frames_queue_ready_.empty());
489
490 if (flush_callback_.get()) { // This ensures callback is invoked once.
491 flush_callback_->Run();
492 flush_callback_.reset();
493 }
494 state_ = kFlushed;
473 } 495 }
474 496
475 base::TimeDelta VideoRendererBase::CalculateSleepDuration( 497 base::TimeDelta VideoRendererBase::CalculateSleepDuration(
476 VideoFrame* next_frame, float playback_rate) { 498 VideoFrame* next_frame, float playback_rate) {
477 // Determine the current and next presentation timestamps. 499 // Determine the current and next presentation timestamps.
478 base::TimeDelta now = host()->GetTime(); 500 base::TimeDelta now = host()->GetTime();
479 base::TimeDelta this_pts = current_frame_->GetTimestamp(); 501 base::TimeDelta this_pts = current_frame_->GetTimestamp();
480 base::TimeDelta next_pts; 502 base::TimeDelta next_pts;
481 if (next_frame) { 503 if (next_frame) {
482 next_pts = next_frame->GetTimestamp(); 504 next_pts = next_frame->GetTimestamp();
(...skipping 12 matching lines...) Expand all
495 previous_time_ = now; 517 previous_time_ = now;
496 } 518 }
497 519
498 // Scale our sleep based on the playback rate. 520 // Scale our sleep based on the playback rate.
499 // TODO(scherkus): floating point badness and degrade gracefully. 521 // TODO(scherkus): floating point badness and degrade gracefully.
500 return base::TimeDelta::FromMicroseconds( 522 return base::TimeDelta::FromMicroseconds(
501 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); 523 static_cast<int64>(sleep.InMicroseconds() / playback_rate));
502 } 524 }
503 525
504 } // namespace media 526 } // 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