| OLD | NEW |
| 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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 // | 194 // |
| 195 // We use the inverse of |render_first_frame_and_stop_| as a proxy for the | 195 // We use the inverse of |render_first_frame_and_stop_| as a proxy for the |
| 196 // value of |time_progressing_| here since we can't access it from the | 196 // value of |time_progressing_| here since we can't access it from the |
| 197 // compositor thread. If we're here (in Render()) the sink must have been | 197 // compositor thread. If we're here (in Render()) the sink must have been |
| 198 // started -- but if it was started only to render the first frame and stop, | 198 // started -- but if it was started only to render the first frame and stop, |
| 199 // then |time_progressing_| is likely false. If we're still in Render() when | 199 // then |time_progressing_| is likely false. If we're still in Render() when |
| 200 // |render_first_frame_and_stop_| is false, then |time_progressing_| is true. | 200 // |render_first_frame_and_stop_| is false, then |time_progressing_| is true. |
| 201 // If |time_progressing_| is actually true when |render_first_frame_and_stop_| | 201 // If |time_progressing_| is actually true when |render_first_frame_and_stop_| |
| 202 // is also true, then the ended callback will be harmlessly delayed until | 202 // is also true, then the ended callback will be harmlessly delayed until |
| 203 // MaybeStopSinkAfterFirstPaint() runs and the next Render() call comes in. | 203 // MaybeStopSinkAfterFirstPaint() runs and the next Render() call comes in. |
| 204 const size_t effective_frames = | 204 MaybeFireEndedCallback_Locked(!render_first_frame_and_stop_); |
| 205 MaybeFireEndedCallback_Locked(!render_first_frame_and_stop_); | |
| 206 if (buffering_state_ == BUFFERING_HAVE_ENOUGH && !received_end_of_stream_ && | 205 if (buffering_state_ == BUFFERING_HAVE_ENOUGH && !received_end_of_stream_ && |
| 207 !effective_frames && (!background_rendering || | 206 !algorithm_->effective_frames_queued() && |
| 208 (!frames_decoded_ && was_background_rendering_))) { | 207 (!background_rendering || |
| 208 (!frames_decoded_ && was_background_rendering_))) { |
| 209 // Do not set |buffering_state_| here as the lock in FrameReady() may be | 209 // Do not set |buffering_state_| here as the lock in FrameReady() may be |
| 210 // held already and it fire the state changes in the wrong order. | 210 // held already and it fire the state changes in the wrong order. |
| 211 task_runner_->PostTask( | 211 task_runner_->PostTask( |
| 212 FROM_HERE, base::Bind(&VideoRendererImpl::TransitionToHaveNothing, | 212 FROM_HERE, base::Bind(&VideoRendererImpl::TransitionToHaveNothing, |
| 213 weak_factory_.GetWeakPtr())); | 213 weak_factory_.GetWeakPtr())); |
| 214 } | 214 } |
| 215 | 215 |
| 216 // We don't count dropped frames in the background to avoid skewing the count | 216 // We don't count dropped frames in the background to avoid skewing the count |
| 217 // and impacting JavaScript visible metrics used by web developers. | 217 // and impacting JavaScript visible metrics used by web developers. |
| 218 // | 218 // |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 if (sequence_token != sequence_token_) | 332 if (sequence_token != sequence_token_) |
| 333 return; | 333 return; |
| 334 | 334 |
| 335 DCHECK_NE(state_, kUninitialized); | 335 DCHECK_NE(state_, kUninitialized); |
| 336 DCHECK_NE(state_, kFlushed); | 336 DCHECK_NE(state_, kFlushed); |
| 337 | 337 |
| 338 CHECK(pending_read_); | 338 CHECK(pending_read_); |
| 339 pending_read_ = false; | 339 pending_read_ = false; |
| 340 | 340 |
| 341 if (status == VideoFrameStream::DECODE_ERROR) { | 341 if (status == VideoFrameStream::DECODE_ERROR) { |
| 342 DCHECK(!frame.get()); | 342 DCHECK(!frame); |
| 343 PipelineStatus error = PIPELINE_ERROR_DECODE; | 343 PipelineStatus error = PIPELINE_ERROR_DECODE; |
| 344 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error)); | 344 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error)); |
| 345 return; | 345 return; |
| 346 } | 346 } |
| 347 | 347 |
| 348 // Already-queued VideoFrameStream ReadCB's can fire after various state | 348 // Already-queued VideoFrameStream ReadCB's can fire after various state |
| 349 // transitions have happened; in that case just drop those frames | 349 // transitions have happened; in that case just drop those frames |
| 350 // immediately. | 350 // immediately. |
| 351 if (state_ == kFlushing) | 351 if (state_ == kFlushing) |
| 352 return; | 352 return; |
| 353 | 353 |
| 354 DCHECK_EQ(state_, kPlaying); | 354 DCHECK_EQ(state_, kPlaying); |
| 355 | 355 |
| 356 // Can happen when demuxers are preparing for a new Seek(). | 356 // Can happen when demuxers are preparing for a new Seek(). |
| 357 if (!frame.get()) { | 357 if (!frame) { |
| 358 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED); | 358 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED); |
| 359 return; | 359 return; |
| 360 } | 360 } |
| 361 | 361 |
| 362 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) { | 362 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) { |
| 363 DCHECK(!received_end_of_stream_); | 363 DCHECK(!received_end_of_stream_); |
| 364 received_end_of_stream_ = true; | 364 received_end_of_stream_ = true; |
| 365 | 365 |
| 366 // See if we can fire EOS immediately instead of waiting for Render(). | 366 // See if we can fire EOS immediately instead of waiting for Render(). |
| 367 MaybeFireEndedCallback_Locked(time_progressing_); | 367 MaybeFireEndedCallback_Locked(time_progressing_); |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 render_first_frame_and_stop_ = false; | 568 render_first_frame_and_stop_ = false; |
| 569 } | 569 } |
| 570 | 570 |
| 571 bool VideoRendererImpl::HaveReachedBufferingCap() { | 571 bool VideoRendererImpl::HaveReachedBufferingCap() { |
| 572 DCHECK(task_runner_->BelongsToCurrentThread()); | 572 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 573 const size_t kMaxVideoFrames = limits::kMaxVideoFrames; | 573 const size_t kMaxVideoFrames = limits::kMaxVideoFrames; |
| 574 | 574 |
| 575 // When the display rate is less than the frame rate, the effective frames | 575 // When the display rate is less than the frame rate, the effective frames |
| 576 // queued may be much smaller than the actual number of frames queued. Here | 576 // queued may be much smaller than the actual number of frames queued. Here |
| 577 // we ensure that frames_queued() doesn't get excessive. | 577 // we ensure that frames_queued() doesn't get excessive. |
| 578 return algorithm_->EffectiveFramesQueued() >= kMaxVideoFrames || | 578 return algorithm_->effective_frames_queued() >= kMaxVideoFrames || |
| 579 algorithm_->frames_queued() >= 3 * kMaxVideoFrames; | 579 algorithm_->frames_queued() >= 3 * kMaxVideoFrames; |
| 580 } | 580 } |
| 581 | 581 |
| 582 void VideoRendererImpl::StartSink() { | 582 void VideoRendererImpl::StartSink() { |
| 583 DCHECK(task_runner_->BelongsToCurrentThread()); | 583 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 584 DCHECK_GT(algorithm_->frames_queued(), 0u); | 584 DCHECK_GT(algorithm_->frames_queued(), 0u); |
| 585 sink_started_ = true; | 585 sink_started_ = true; |
| 586 was_background_rendering_ = false; | 586 was_background_rendering_ = false; |
| 587 sink_->Start(this); | 587 sink_->Start(this); |
| 588 } | 588 } |
| 589 | 589 |
| 590 void VideoRendererImpl::StopSink() { | 590 void VideoRendererImpl::StopSink() { |
| 591 DCHECK(task_runner_->BelongsToCurrentThread()); | 591 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 592 sink_->Stop(); | 592 sink_->Stop(); |
| 593 algorithm_->set_time_stopped(); | 593 algorithm_->set_time_stopped(); |
| 594 sink_started_ = false; | 594 sink_started_ = false; |
| 595 was_background_rendering_ = false; | 595 was_background_rendering_ = false; |
| 596 } | 596 } |
| 597 | 597 |
| 598 size_t VideoRendererImpl::MaybeFireEndedCallback_Locked(bool time_progressing) { | 598 void VideoRendererImpl::MaybeFireEndedCallback_Locked(bool time_progressing) { |
| 599 lock_.AssertAcquired(); | 599 lock_.AssertAcquired(); |
| 600 | 600 |
| 601 // If there's only one frame in the video or Render() was never called, the | 601 // If there's only one frame in the video or Render() was never called, the |
| 602 // algorithm will have one frame linger indefinitely. So in cases where the | 602 // algorithm will have one frame linger indefinitely. So in cases where the |
| 603 // frame duration is unknown and we've received EOS, fire it once we get down | 603 // frame duration is unknown and we've received EOS, fire it once we get down |
| 604 // to a single frame. | 604 // to a single frame. |
| 605 const size_t effective_frames = algorithm_->EffectiveFramesQueued(); | |
| 606 | 605 |
| 607 // Don't fire ended if we haven't received EOS or have already done so. | 606 // Don't fire ended if we haven't received EOS or have already done so. |
| 608 if (!received_end_of_stream_ || rendered_end_of_stream_) | 607 if (!received_end_of_stream_ || rendered_end_of_stream_) |
| 609 return effective_frames; | 608 return; |
| 610 | 609 |
| 611 // Don't fire ended if time isn't moving and we have frames. | 610 // Don't fire ended if time isn't moving and we have frames. |
| 612 if (!time_progressing && algorithm_->frames_queued()) | 611 if (!time_progressing && algorithm_->frames_queued()) |
| 613 return effective_frames; | 612 return; |
| 614 | 613 |
| 615 // Fire ended if we have no more effective frames or only ever had one frame. | 614 // Fire ended if we have no more effective frames or only ever had one frame. |
| 616 if (!effective_frames || | 615 if (!algorithm_->effective_frames_queued() || |
| 617 (algorithm_->frames_queued() == 1u && | 616 (algorithm_->frames_queued() == 1u && |
| 618 algorithm_->average_frame_duration() == base::TimeDelta())) { | 617 algorithm_->average_frame_duration().is_zero())) { |
| 619 rendered_end_of_stream_ = true; | 618 rendered_end_of_stream_ = true; |
| 620 task_runner_->PostTask(FROM_HERE, ended_cb_); | 619 task_runner_->PostTask(FROM_HERE, ended_cb_); |
| 621 } | 620 } |
| 622 | |
| 623 return effective_frames; | |
| 624 } | 621 } |
| 625 | 622 |
| 626 base::TimeTicks VideoRendererImpl::ConvertMediaTimestamp( | 623 base::TimeTicks VideoRendererImpl::ConvertMediaTimestamp( |
| 627 base::TimeDelta media_time) { | 624 base::TimeDelta media_time) { |
| 628 std::vector<base::TimeDelta> media_times(1, media_time); | 625 std::vector<base::TimeDelta> media_times(1, media_time); |
| 629 std::vector<base::TimeTicks> wall_clock_times; | 626 std::vector<base::TimeTicks> wall_clock_times; |
| 630 if (!wall_clock_time_cb_.Run(media_times, &wall_clock_times)) | 627 if (!wall_clock_time_cb_.Run(media_times, &wall_clock_times)) |
| 631 return base::TimeTicks(); | 628 return base::TimeTicks(); |
| 632 return wall_clock_times[0]; | 629 return wall_clock_times[0]; |
| 633 } | 630 } |
| 634 | 631 |
| 635 base::TimeTicks VideoRendererImpl::GetCurrentMediaTimeAsWallClockTime() { | 632 base::TimeTicks VideoRendererImpl::GetCurrentMediaTimeAsWallClockTime() { |
| 636 std::vector<base::TimeTicks> current_time; | 633 std::vector<base::TimeTicks> current_time; |
| 637 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), ¤t_time); | 634 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), ¤t_time); |
| 638 return current_time[0]; | 635 return current_time[0]; |
| 639 } | 636 } |
| 640 | 637 |
| 641 bool VideoRendererImpl::IsBeforeStartTime(base::TimeDelta timestamp) { | 638 bool VideoRendererImpl::IsBeforeStartTime(base::TimeDelta timestamp) { |
| 642 return timestamp + video_frame_stream_->AverageDuration() < start_timestamp_; | 639 return timestamp + video_frame_stream_->AverageDuration() < start_timestamp_; |
| 643 } | 640 } |
| 644 | 641 |
| 645 } // namespace media | 642 } // namespace media |
| OLD | NEW |