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

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

Issue 1996763002: Make painting a single frame a permanent API on VideoRendererSink. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments. Created 4 years, 7 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/renderers/video_renderer_impl.h ('k') | media/renderers/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/renderers/video_renderer_impl.h" 5 #include "media/renderers/video_renderer_impl.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 state_(kUninitialized), 50 state_(kUninitialized),
51 sequence_token_(0), 51 sequence_token_(0),
52 pending_read_(false), 52 pending_read_(false),
53 drop_frames_(drop_frames), 53 drop_frames_(drop_frames),
54 buffering_state_(BUFFERING_HAVE_NOTHING), 54 buffering_state_(BUFFERING_HAVE_NOTHING),
55 frames_decoded_(0), 55 frames_decoded_(0),
56 frames_dropped_(0), 56 frames_dropped_(0),
57 tick_clock_(new base::DefaultTickClock()), 57 tick_clock_(new base::DefaultTickClock()),
58 was_background_rendering_(false), 58 was_background_rendering_(false),
59 time_progressing_(false), 59 time_progressing_(false),
60 render_first_frame_and_stop_(false),
61 posted_maybe_stop_after_first_paint_(false),
62 last_video_memory_usage_(0), 60 last_video_memory_usage_(0),
63 have_renderered_frames_(false), 61 have_renderered_frames_(false),
64 last_frame_opaque_(false), 62 last_frame_opaque_(false),
65 weak_factory_(this) { 63 weak_factory_(this) {
66 if (gpu_factories && 64 if (gpu_factories &&
67 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames()) { 65 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames()) {
68 gpu_memory_buffer_pool_.reset(new GpuMemoryBufferVideoFramePool( 66 gpu_memory_buffer_pool_.reset(new GpuMemoryBufferVideoFramePool(
69 media_task_runner, worker_task_runner, gpu_factories)); 67 media_task_runner, worker_task_runner, gpu_factories));
70 } 68 }
71 } 69 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 RendererClient* client, 130 RendererClient* client,
133 const TimeSource::WallClockTimeCB& wall_clock_time_cb, 131 const TimeSource::WallClockTimeCB& wall_clock_time_cb,
134 const PipelineStatusCB& init_cb) { 132 const PipelineStatusCB& init_cb) {
135 DCHECK(task_runner_->BelongsToCurrentThread()); 133 DCHECK(task_runner_->BelongsToCurrentThread());
136 base::AutoLock auto_lock(lock_); 134 base::AutoLock auto_lock(lock_);
137 DCHECK(stream); 135 DCHECK(stream);
138 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); 136 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
139 DCHECK(!init_cb.is_null()); 137 DCHECK(!init_cb.is_null());
140 DCHECK(!wall_clock_time_cb.is_null()); 138 DCHECK(!wall_clock_time_cb.is_null());
141 DCHECK_EQ(kUninitialized, state_); 139 DCHECK_EQ(kUninitialized, state_);
142 DCHECK(!render_first_frame_and_stop_);
143 DCHECK(!posted_maybe_stop_after_first_paint_);
144 DCHECK(!was_background_rendering_); 140 DCHECK(!was_background_rendering_);
145 DCHECK(!time_progressing_); 141 DCHECK(!time_progressing_);
146 DCHECK(!have_renderered_frames_); 142 DCHECK(!have_renderered_frames_);
147 143
148 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE); 144 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE);
149 UMA_HISTOGRAM_BOOLEAN("Media.VideoRenderer.LowDelay", low_delay_); 145 UMA_HISTOGRAM_BOOLEAN("Media.VideoRenderer.LowDelay", low_delay_);
150 if (low_delay_) 146 if (low_delay_)
151 MEDIA_LOG(DEBUG, media_log_) << "Video rendering in low delay mode."; 147 MEDIA_LOG(DEBUG, media_log_) << "Video rendering in low delay mode.";
152 148
153 // Always post |init_cb_| because |this| could be destroyed if initialization 149 // Always post |init_cb_| because |this| could be destroyed if initialization
(...skipping 21 matching lines...) Expand all
175 DCHECK_EQ(state_, kPlaying); 171 DCHECK_EQ(state_, kPlaying);
176 172
177 size_t frames_dropped = 0; 173 size_t frames_dropped = 0;
178 scoped_refptr<VideoFrame> result = 174 scoped_refptr<VideoFrame> result =
179 algorithm_->Render(deadline_min, deadline_max, &frames_dropped); 175 algorithm_->Render(deadline_min, deadline_max, &frames_dropped);
180 176
181 // Due to how the |algorithm_| holds frames, this should never be null if 177 // Due to how the |algorithm_| holds frames, this should never be null if
182 // we've had a proper startup sequence. 178 // we've had a proper startup sequence.
183 DCHECK(result); 179 DCHECK(result);
184 180
185 // Notify client of size and opacity changes if this is the first frame
186 // or if those have changed from the last frame.
187 if (!have_renderered_frames_ ||
188 (last_frame_natural_size_ != result->natural_size())) {
189 last_frame_natural_size_ = result->natural_size();
190 task_runner_->PostTask(
191 FROM_HERE,
192 base::Bind(&VideoRendererImpl::OnVideoNaturalSizeChange,
193 weak_factory_.GetWeakPtr(), last_frame_natural_size_));
194 }
195 if (!have_renderered_frames_ ||
196 (last_frame_opaque_ != IsOpaque(result->format()))) {
197 last_frame_opaque_ = IsOpaque(result->format());
198 task_runner_->PostTask(
199 FROM_HERE, base::Bind(&VideoRendererImpl::OnVideoOpacityChange,
200 weak_factory_.GetWeakPtr(), last_frame_opaque_));
201 }
202
203 // Declare HAVE_NOTHING if we reach a state where we can't progress playback 181 // Declare HAVE_NOTHING if we reach a state where we can't progress playback
204 // any further. We don't want to do this if we've already done so, reached 182 // any further. We don't want to do this if we've already done so, reached
205 // end of stream, or have frames available. We also don't want to do this in 183 // end of stream, or have frames available. We also don't want to do this in
206 // background rendering mode unless this isn't the first background render 184 // background rendering mode unless this isn't the first background render
207 // tick and we haven't seen any decoded frames since the last one. 185 // tick and we haven't seen any decoded frames since the last one.
208 // 186 MaybeFireEndedCallback_Locked(true);
209 // We use the inverse of |render_first_frame_and_stop_| as a proxy for the
210 // value of |time_progressing_| here since we can't access it from the
211 // compositor thread. If we're here (in Render()) the sink must have been
212 // started -- but if it was started only to render the first frame and stop,
213 // then |time_progressing_| is likely false. If we're still in Render() when
214 // |render_first_frame_and_stop_| is false, then |time_progressing_| is true.
215 // If |time_progressing_| is actually true when |render_first_frame_and_stop_|
216 // is also true, then the ended callback will be harmlessly delayed until
217 // MaybeStopSinkAfterFirstPaint() runs and the next Render() call comes in.
218 MaybeFireEndedCallback_Locked(!render_first_frame_and_stop_);
219 if (buffering_state_ == BUFFERING_HAVE_ENOUGH && !received_end_of_stream_ && 187 if (buffering_state_ == BUFFERING_HAVE_ENOUGH && !received_end_of_stream_ &&
220 !algorithm_->effective_frames_queued() && 188 !algorithm_->effective_frames_queued() &&
221 (!background_rendering || 189 (!background_rendering ||
222 (!frames_decoded_ && was_background_rendering_))) { 190 (!frames_decoded_ && was_background_rendering_))) {
223 // Do not set |buffering_state_| here as the lock in FrameReady() may be 191 // Do not set |buffering_state_| here as the lock in FrameReady() may be
224 // held already and it fire the state changes in the wrong order. 192 // held already and it fire the state changes in the wrong order.
225 task_runner_->PostTask( 193 task_runner_->PostTask(
226 FROM_HERE, base::Bind(&VideoRendererImpl::TransitionToHaveNothing, 194 FROM_HERE, base::Bind(&VideoRendererImpl::TransitionToHaveNothing,
227 weak_factory_.GetWeakPtr())); 195 weak_factory_.GetWeakPtr()));
228 } 196 }
229 197
230 // We don't count dropped frames in the background to avoid skewing the count 198 // We don't count dropped frames in the background to avoid skewing the count
231 // and impacting JavaScript visible metrics used by web developers. 199 // and impacting JavaScript visible metrics used by web developers.
232 // 200 //
233 // Just after resuming from background rendering, we also don't count the 201 // Just after resuming from background rendering, we also don't count the
234 // dropped frames since they are likely just dropped due to being too old. 202 // dropped frames since they are likely just dropped due to being too old.
235 if (!background_rendering && !was_background_rendering_) 203 if (!background_rendering && !was_background_rendering_)
236 frames_dropped_ += frames_dropped; 204 frames_dropped_ += frames_dropped;
237 UpdateStats_Locked(); 205 UpdateStats_Locked();
238 was_background_rendering_ = background_rendering; 206 was_background_rendering_ = background_rendering;
239 207
240 // After painting the first frame, if playback hasn't started, we post a
241 // delayed task to request that the sink be stopped. The task is delayed to
242 // give videos with autoplay time to start.
243 //
244 // OnTimeStateChanged() will clear this flag if time starts before we get here
245 // and MaybeStopSinkAfterFirstPaint() will ignore this request if time starts
246 // before the call executes.
247 if (render_first_frame_and_stop_ && !posted_maybe_stop_after_first_paint_) {
248 posted_maybe_stop_after_first_paint_ = true;
249 task_runner_->PostDelayedTask(
250 FROM_HERE, base::Bind(&VideoRendererImpl::MaybeStopSinkAfterFirstPaint,
251 weak_factory_.GetWeakPtr()),
252 base::TimeDelta::FromMilliseconds(250));
253 }
254
255 // Always post this task, it will acquire new frames if necessary and since it 208 // Always post this task, it will acquire new frames if necessary and since it
256 // happens on another thread, even if we don't have room in the queue now, by 209 // happens on another thread, even if we don't have room in the queue now, by
257 // the time it runs (may be delayed up to 50ms for complex decodes!) we might. 210 // the time it runs (may be delayed up to 50ms for complex decodes!) we might.
258 task_runner_->PostTask(FROM_HERE, base::Bind(&VideoRendererImpl::AttemptRead, 211 task_runner_->PostTask(
259 weak_factory_.GetWeakPtr())); 212 FROM_HERE,
213 base::Bind(&VideoRendererImpl::AttemptReadAndCheckForMetadataChanges,
214 weak_factory_.GetWeakPtr(), result->format(),
215 result->natural_size()));
260 216
261 have_renderered_frames_ = true;
262 return result; 217 return result;
263 } 218 }
264 219
265 void VideoRendererImpl::OnFrameDropped() { 220 void VideoRendererImpl::OnFrameDropped() {
266 base::AutoLock auto_lock(lock_); 221 base::AutoLock auto_lock(lock_);
267 algorithm_->OnLastFrameDropped(); 222 algorithm_->OnLastFrameDropped();
268 } 223 }
269 224
270 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) { 225 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
271 DCHECK(task_runner_->BelongsToCurrentThread()); 226 DCHECK(task_runner_->BelongsToCurrentThread());
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 void VideoRendererImpl::OnBufferingStateChange(BufferingState state) { 264 void VideoRendererImpl::OnBufferingStateChange(BufferingState state) {
310 DCHECK(task_runner_->BelongsToCurrentThread()); 265 DCHECK(task_runner_->BelongsToCurrentThread());
311 client_->OnBufferingStateChange(state); 266 client_->OnBufferingStateChange(state);
312 } 267 }
313 268
314 void VideoRendererImpl::OnWaitingForDecryptionKey() { 269 void VideoRendererImpl::OnWaitingForDecryptionKey() {
315 DCHECK(task_runner_->BelongsToCurrentThread()); 270 DCHECK(task_runner_->BelongsToCurrentThread());
316 client_->OnWaitingForDecryptionKey(); 271 client_->OnWaitingForDecryptionKey();
317 } 272 }
318 273
319 void VideoRendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
320 DCHECK(task_runner_->BelongsToCurrentThread());
321 client_->OnVideoNaturalSizeChange(size);
322 }
323
324 void VideoRendererImpl::OnVideoOpacityChange(bool opaque) {
325 DCHECK(task_runner_->BelongsToCurrentThread());
326 client_->OnVideoOpacityChange(opaque);
327 }
328
329 void VideoRendererImpl::SetTickClockForTesting( 274 void VideoRendererImpl::SetTickClockForTesting(
330 std::unique_ptr<base::TickClock> tick_clock) { 275 std::unique_ptr<base::TickClock> tick_clock) {
331 tick_clock_.swap(tick_clock); 276 tick_clock_.swap(tick_clock);
332 } 277 }
333 278
334 void VideoRendererImpl::SetGpuMemoryBufferVideoForTesting( 279 void VideoRendererImpl::SetGpuMemoryBufferVideoForTesting(
335 std::unique_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool) { 280 std::unique_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool) {
336 gpu_memory_buffer_pool_.swap(gpu_memory_buffer_pool); 281 gpu_memory_buffer_pool_.swap(gpu_memory_buffer_pool);
337 } 282 }
338 283
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 DCHECK(frame); 328 DCHECK(frame);
384 gpu_memory_buffer_pool_->MaybeCreateHardwareFrame( 329 gpu_memory_buffer_pool_->MaybeCreateHardwareFrame(
385 frame, base::Bind(&VideoRendererImpl::FrameReady, 330 frame, base::Bind(&VideoRendererImpl::FrameReady,
386 weak_factory_.GetWeakPtr(), sequence_token_, status)); 331 weak_factory_.GetWeakPtr(), sequence_token_, status));
387 } 332 }
388 333
389 void VideoRendererImpl::FrameReady(uint32_t sequence_token, 334 void VideoRendererImpl::FrameReady(uint32_t sequence_token,
390 VideoFrameStream::Status status, 335 VideoFrameStream::Status status,
391 const scoped_refptr<VideoFrame>& frame) { 336 const scoped_refptr<VideoFrame>& frame) {
392 DCHECK(task_runner_->BelongsToCurrentThread()); 337 DCHECK(task_runner_->BelongsToCurrentThread());
393 bool start_sink = false; 338 base::AutoLock auto_lock(lock_);
394 {
395 base::AutoLock auto_lock(lock_);
396 // Stream has been reset and this VideoFrame was decoded before the reset
397 // but the async copy finished after.
398 if (sequence_token != sequence_token_)
399 return;
400 339
401 DCHECK_NE(state_, kUninitialized); 340 // Stream has been reset and this VideoFrame was decoded before the reset
402 DCHECK_NE(state_, kFlushed); 341 // but the async copy finished after.
342 if (sequence_token != sequence_token_)
343 return;
403 344
404 CHECK(pending_read_); 345 DCHECK_NE(state_, kUninitialized);
405 pending_read_ = false; 346 DCHECK_NE(state_, kFlushed);
406 347
407 if (status == VideoFrameStream::DECODE_ERROR) { 348 CHECK(pending_read_);
408 DCHECK(!frame); 349 pending_read_ = false;
409 task_runner_->PostTask(
410 FROM_HERE,
411 base::Bind(&VideoRendererImpl::OnPlaybackError,
412 weak_factory_.GetWeakPtr(), PIPELINE_ERROR_DECODE));
413 return;
414 }
415 350
416 // Already-queued VideoFrameStream ReadCB's can fire after various state 351 if (status == VideoFrameStream::DECODE_ERROR) {
417 // transitions have happened; in that case just drop those frames 352 DCHECK(!frame);
418 // immediately. 353 task_runner_->PostTask(
419 if (state_ == kFlushing) 354 FROM_HERE,
420 return; 355 base::Bind(&VideoRendererImpl::OnPlaybackError,
421 356 weak_factory_.GetWeakPtr(), PIPELINE_ERROR_DECODE));
422 DCHECK_EQ(state_, kPlaying); 357 return;
423
424 // Can happen when demuxers are preparing for a new Seek().
425 if (!frame) {
426 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
427 return;
428 }
429
430 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
431 DCHECK(!received_end_of_stream_);
432 received_end_of_stream_ = true;
433
434 // See if we can fire EOS immediately instead of waiting for Render().
435 MaybeFireEndedCallback_Locked(time_progressing_);
436 } else if ((low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) &&
437 IsBeforeStartTime(frame->timestamp())) {
438 // Don't accumulate frames that are earlier than the start time if we
439 // won't have a chance for a better frame, otherwise we could declare
440 // HAVE_ENOUGH_DATA and start playback prematurely.
441 AttemptRead_Locked();
442 return;
443 } else {
444 // If the sink hasn't been started, we still have time to release less
445 // than ideal frames prior to startup. We don't use IsBeforeStartTime()
446 // here since it's based on a duration estimate and we can be exact here.
447 if (!sink_started_ && frame->timestamp() <= start_timestamp_)
448 algorithm_->Reset();
449
450 AddReadyFrame_Locked(frame);
451 }
452
453 // Attempt to purge bad frames in case of underflow or backgrounding.
454 RemoveFramesForUnderflowOrBackgroundRendering();
455
456 // Signal buffering state if we've met our conditions.
457 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) {
458 TransitionToHaveEnough_Locked();
459 if (!sink_started_ && !rendered_end_of_stream_) {
460 start_sink = true;
461 render_first_frame_and_stop_ = true;
462 posted_maybe_stop_after_first_paint_ = false;
463 }
464 }
465
466 // Always request more decoded video if we have capacity. This serves two
467 // purposes:
468 // 1) Prerolling while paused
469 // 2) Keeps decoding going if video rendering thread starts falling behind
470 AttemptRead_Locked();
471 } 358 }
472 359
473 // If time is progressing, the sink has already been started; this may be true 360 // Already-queued VideoFrameStream ReadCB's can fire after various state
474 // if we have previously underflowed, yet weren't stopped because of audio. 361 // transitions have happened; in that case just drop those frames
475 if (start_sink) { 362 // immediately.
476 DCHECK(!sink_started_); 363 if (state_ == kFlushing)
477 StartSink(); 364 return;
365
366 DCHECK_EQ(state_, kPlaying);
367
368 // Can happen when demuxers are preparing for a new Seek().
369 if (!frame) {
370 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
371 return;
478 } 372 }
373
374 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
375 DCHECK(!received_end_of_stream_);
376 received_end_of_stream_ = true;
377
378 // See if we can fire EOS immediately instead of waiting for Render().
379 MaybeFireEndedCallback_Locked(time_progressing_);
380 } else if ((low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) &&
381 IsBeforeStartTime(frame->timestamp())) {
382 // Don't accumulate frames that are earlier than the start time if we
383 // won't have a chance for a better frame, otherwise we could declare
384 // HAVE_ENOUGH_DATA and start playback prematurely.
385 AttemptRead_Locked();
386 return;
387 } else {
388 // If the sink hasn't been started, we still have time to release less
389 // than ideal frames prior to startup. We don't use IsBeforeStartTime()
390 // here since it's based on a duration estimate and we can be exact here.
391 if (!sink_started_ && frame->timestamp() <= start_timestamp_)
392 algorithm_->Reset();
393
394 AddReadyFrame_Locked(frame);
395 }
396
397 // Attempt to purge bad frames in case of underflow or backgrounding.
398 RemoveFramesForUnderflowOrBackgroundRendering();
399
400 // Signal buffering state if we've met our conditions.
401 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) {
402 TransitionToHaveEnough_Locked();
403
404 // Paint the first frame if necessary.
405 if (!rendered_end_of_stream_ && !sink_started_) {
406 DCHECK(algorithm_->frames_queued());
407 scoped_refptr<VideoFrame> frame = algorithm_->first_frame();
408 CheckForMetadataChanges(frame->format(), frame->natural_size());
409 sink_->PaintSingleFrame(frame);
410 }
411 }
412
413 // Always request more decoded video if we have capacity. This serves two
414 // purposes:
415 // 1) Prerolling while paused
416 // 2) Keeps decoding going if video rendering thread starts falling behind
417 AttemptRead_Locked();
479 } 418 }
480 419
481 bool VideoRendererImpl::HaveEnoughData_Locked() { 420 bool VideoRendererImpl::HaveEnoughData_Locked() {
482 DCHECK_EQ(state_, kPlaying); 421 DCHECK_EQ(state_, kPlaying);
483 lock_.AssertAcquired(); 422 lock_.AssertAcquired();
484 423
485 if (received_end_of_stream_) 424 if (received_end_of_stream_)
486 return true; 425 return true;
487 426
488 if (HaveReachedBufferingCap()) 427 if (HaveReachedBufferingCap())
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 const scoped_refptr<VideoFrame>& frame) { 464 const scoped_refptr<VideoFrame>& frame) {
526 DCHECK(task_runner_->BelongsToCurrentThread()); 465 DCHECK(task_runner_->BelongsToCurrentThread());
527 lock_.AssertAcquired(); 466 lock_.AssertAcquired();
528 DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)); 467 DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
529 468
530 frames_decoded_++; 469 frames_decoded_++;
531 470
532 algorithm_->EnqueueFrame(frame); 471 algorithm_->EnqueueFrame(frame);
533 } 472 }
534 473
535 void VideoRendererImpl::AttemptRead() {
536 base::AutoLock auto_lock(lock_);
537 AttemptRead_Locked();
538 }
539
540 void VideoRendererImpl::AttemptRead_Locked() { 474 void VideoRendererImpl::AttemptRead_Locked() {
541 DCHECK(task_runner_->BelongsToCurrentThread()); 475 DCHECK(task_runner_->BelongsToCurrentThread());
542 lock_.AssertAcquired(); 476 lock_.AssertAcquired();
543 477
544 if (pending_read_ || received_end_of_stream_) 478 if (pending_read_ || received_end_of_stream_)
545 return; 479 return;
546 480
547 if (HaveReachedBufferingCap()) 481 if (HaveReachedBufferingCap())
548 return; 482 return;
549 483
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 531
598 task_runner_->PostTask(FROM_HERE, 532 task_runner_->PostTask(FROM_HERE,
599 base::Bind(&VideoRendererImpl::OnStatisticsUpdate, 533 base::Bind(&VideoRendererImpl::OnStatisticsUpdate,
600 weak_factory_.GetWeakPtr(), statistics)); 534 weak_factory_.GetWeakPtr(), statistics));
601 frames_decoded_ = 0; 535 frames_decoded_ = 0;
602 frames_dropped_ = 0; 536 frames_dropped_ = 0;
603 last_video_memory_usage_ = memory_usage; 537 last_video_memory_usage_ = memory_usage;
604 } 538 }
605 } 539 }
606 540
607 void VideoRendererImpl::MaybeStopSinkAfterFirstPaint() {
608 DCHECK(task_runner_->BelongsToCurrentThread());
609
610 if (!time_progressing_ && sink_started_)
611 StopSink();
612
613 base::AutoLock auto_lock(lock_);
614 render_first_frame_and_stop_ = false;
615 }
616
617 bool VideoRendererImpl::HaveReachedBufferingCap() { 541 bool VideoRendererImpl::HaveReachedBufferingCap() {
618 DCHECK(task_runner_->BelongsToCurrentThread()); 542 DCHECK(task_runner_->BelongsToCurrentThread());
619 const size_t kMaxVideoFrames = limits::kMaxVideoFrames; 543 const size_t kMaxVideoFrames = limits::kMaxVideoFrames;
620 544
621 // When the display rate is less than the frame rate, the effective frames 545 // When the display rate is less than the frame rate, the effective frames
622 // queued may be much smaller than the actual number of frames queued. Here 546 // queued may be much smaller than the actual number of frames queued. Here
623 // we ensure that frames_queued() doesn't get excessive. 547 // we ensure that frames_queued() doesn't get excessive.
624 return algorithm_->effective_frames_queued() >= kMaxVideoFrames || 548 return algorithm_->effective_frames_queued() >= kMaxVideoFrames ||
625 algorithm_->frames_queued() >= 3 * kMaxVideoFrames; 549 algorithm_->frames_queued() >= 3 * kMaxVideoFrames;
626 } 550 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
724 // If we've paused for underflow, and still have no effective frames, clear 648 // If we've paused for underflow, and still have no effective frames, clear
725 // the entire queue. Note: this may cause slight inaccuracies in the number 649 // the entire queue. Note: this may cause slight inaccuracies in the number
726 // of dropped frames since the frame may have been rendered before. 650 // of dropped frames since the frame may have been rendered before.
727 if (!sink_started_ && !algorithm_->effective_frames_queued()) { 651 if (!sink_started_ && !algorithm_->effective_frames_queued()) {
728 frames_dropped_ += algorithm_->frames_queued(); 652 frames_dropped_ += algorithm_->frames_queued();
729 algorithm_->Reset( 653 algorithm_->Reset(
730 VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates); 654 VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates);
731 } 655 }
732 } 656 }
733 657
658 void VideoRendererImpl::CheckForMetadataChanges(VideoPixelFormat pixel_format,
659 const gfx::Size& natural_size) {
660 DCHECK(task_runner_->BelongsToCurrentThread());
661
662 // Notify client of size and opacity changes if this is the first frame
663 // or if those have changed from the last frame.
664 if (!have_renderered_frames_ || last_frame_natural_size_ != natural_size) {
665 last_frame_natural_size_ = natural_size;
666 client_->OnVideoNaturalSizeChange(last_frame_natural_size_);
667 }
668
669 const bool is_opaque = IsOpaque(pixel_format);
670 if (!have_renderered_frames_ || last_frame_opaque_ != is_opaque) {
671 last_frame_opaque_ = is_opaque;
672 client_->OnVideoOpacityChange(last_frame_opaque_);
673 }
674
675 have_renderered_frames_ = true;
676 }
677
678 void VideoRendererImpl::AttemptReadAndCheckForMetadataChanges(
679 VideoPixelFormat pixel_format,
680 const gfx::Size& natural_size) {
681 base::AutoLock auto_lock(lock_);
682 CheckForMetadataChanges(pixel_format, natural_size);
683 AttemptRead_Locked();
684 }
685
734 } // namespace media 686 } // namespace media
OLDNEW
« no previous file with comments | « media/renderers/video_renderer_impl.h ('k') | media/renderers/video_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698