Chromium Code Reviews| 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" |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
| 15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 16 #include "base/time/default_tick_clock.h" | 16 #include "base/time/default_tick_clock.h" |
| 17 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" |
| 18 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
| 19 #include "media/base/limits.h" | 19 #include "media/base/limits.h" |
| 20 #include "media/base/media_log.h" | 20 #include "media/base/media_log.h" |
| 21 #include "media/base/media_switches.h" | 21 #include "media/base/media_switches.h" |
| 22 #include "media/base/pipeline_status.h" | 22 #include "media/base/pipeline_status.h" |
| 23 #include "media/base/renderer_client.h" | |
| 23 #include "media/base/video_frame.h" | 24 #include "media/base/video_frame.h" |
| 24 #include "media/renderers/gpu_video_accelerator_factories.h" | 25 #include "media/renderers/gpu_video_accelerator_factories.h" |
| 25 #include "media/video/gpu_memory_buffer_video_frame_pool.h" | 26 #include "media/video/gpu_memory_buffer_video_frame_pool.h" |
| 26 | 27 |
| 27 namespace media { | 28 namespace media { |
| 28 | 29 |
| 29 VideoRendererImpl::VideoRendererImpl( | 30 VideoRendererImpl::VideoRendererImpl( |
| 30 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 31 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| 31 const scoped_refptr<base::TaskRunner>& worker_task_runner, | 32 const scoped_refptr<base::TaskRunner>& worker_task_runner, |
| 32 VideoRendererSink* sink, | 33 VideoRendererSink* sink, |
| 33 ScopedVector<VideoDecoder> decoders, | 34 ScopedVector<VideoDecoder> decoders, |
| 34 bool drop_frames, | 35 bool drop_frames, |
| 35 GpuVideoAcceleratorFactories* gpu_factories, | 36 GpuVideoAcceleratorFactories* gpu_factories, |
| 36 const scoped_refptr<MediaLog>& media_log) | 37 const scoped_refptr<MediaLog>& media_log) |
| 37 : task_runner_(media_task_runner), | 38 : task_runner_(media_task_runner), |
| 38 sink_(sink), | 39 sink_(sink), |
| 39 sink_started_(false), | 40 sink_started_(false), |
| 41 client_(nullptr), | |
| 40 video_frame_stream_(new VideoFrameStream(media_task_runner, | 42 video_frame_stream_(new VideoFrameStream(media_task_runner, |
| 41 std::move(decoders), | 43 std::move(decoders), |
| 42 media_log)), | 44 media_log)), |
| 43 gpu_memory_buffer_pool_(nullptr), | 45 gpu_memory_buffer_pool_(nullptr), |
| 44 media_log_(media_log), | 46 media_log_(media_log), |
| 45 low_delay_(false), | 47 low_delay_(false), |
| 46 received_end_of_stream_(false), | 48 received_end_of_stream_(false), |
| 47 rendered_end_of_stream_(false), | 49 rendered_end_of_stream_(false), |
| 48 state_(kUninitialized), | 50 state_(kUninitialized), |
| 49 sequence_token_(0), | 51 sequence_token_(0), |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 | 90 |
| 89 base::AutoLock auto_lock(lock_); | 91 base::AutoLock auto_lock(lock_); |
| 90 DCHECK_EQ(state_, kPlaying); | 92 DCHECK_EQ(state_, kPlaying); |
| 91 flush_cb_ = callback; | 93 flush_cb_ = callback; |
| 92 state_ = kFlushing; | 94 state_ = kFlushing; |
| 93 | 95 |
| 94 // This is necessary if the |video_frame_stream_| has already seen an end of | 96 // This is necessary if the |video_frame_stream_| has already seen an end of |
| 95 // stream and needs to drain it before flushing it. | 97 // stream and needs to drain it before flushing it. |
| 96 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { | 98 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { |
| 97 buffering_state_ = BUFFERING_HAVE_NOTHING; | 99 buffering_state_ = BUFFERING_HAVE_NOTHING; |
| 98 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING); | 100 client_->OnBufferingStateChange(buffering_state_); |
| 99 } | 101 } |
| 100 received_end_of_stream_ = false; | 102 received_end_of_stream_ = false; |
| 101 rendered_end_of_stream_ = false; | 103 rendered_end_of_stream_ = false; |
| 102 | 104 |
| 103 algorithm_->Reset(); | 105 algorithm_->Reset(); |
| 104 | 106 |
| 105 video_frame_stream_->Reset( | 107 video_frame_stream_->Reset( |
| 106 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone, | 108 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone, |
| 107 weak_factory_.GetWeakPtr())); | 109 weak_factory_.GetWeakPtr())); |
| 108 } | 110 } |
| 109 | 111 |
| 110 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { | 112 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { |
| 111 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; | 113 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; |
| 112 DCHECK(task_runner_->BelongsToCurrentThread()); | 114 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 113 base::AutoLock auto_lock(lock_); | 115 base::AutoLock auto_lock(lock_); |
| 114 DCHECK_EQ(state_, kFlushed); | 116 DCHECK_EQ(state_, kFlushed); |
| 115 DCHECK(!pending_read_); | 117 DCHECK(!pending_read_); |
| 116 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 118 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
| 117 | 119 |
| 118 state_ = kPlaying; | 120 state_ = kPlaying; |
| 119 start_timestamp_ = timestamp; | 121 start_timestamp_ = timestamp; |
| 120 AttemptRead_Locked(); | 122 AttemptRead_Locked(); |
| 121 } | 123 } |
| 122 | 124 |
| 123 void VideoRendererImpl::Initialize( | 125 void VideoRendererImpl::Initialize( |
| 126 RendererClient* client, | |
| 124 DemuxerStream* stream, | 127 DemuxerStream* stream, |
| 125 const PipelineStatusCB& init_cb, | |
| 126 CdmContext* cdm_context, | 128 CdmContext* cdm_context, |
| 127 const StatisticsCB& statistics_cb, | |
| 128 const BufferingStateCB& buffering_state_cb, | |
| 129 const base::Closure& ended_cb, | |
| 130 const PipelineStatusCB& error_cb, | |
| 131 const TimeSource::WallClockTimeCB& wall_clock_time_cb, | 129 const TimeSource::WallClockTimeCB& wall_clock_time_cb, |
| 132 const base::Closure& waiting_for_decryption_key_cb) { | 130 const PipelineStatusCB& init_cb) { |
| 133 DCHECK(task_runner_->BelongsToCurrentThread()); | 131 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 134 base::AutoLock auto_lock(lock_); | 132 base::AutoLock auto_lock(lock_); |
| 135 DCHECK(stream); | 133 DCHECK(stream); |
| 136 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); | 134 DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); |
| 137 DCHECK(!init_cb.is_null()); | 135 DCHECK(!init_cb.is_null()); |
| 138 DCHECK(!statistics_cb.is_null()); | |
| 139 DCHECK(!buffering_state_cb.is_null()); | |
| 140 DCHECK(!ended_cb.is_null()); | |
| 141 DCHECK(!wall_clock_time_cb.is_null()); | 136 DCHECK(!wall_clock_time_cb.is_null()); |
| 142 DCHECK_EQ(kUninitialized, state_); | 137 DCHECK_EQ(kUninitialized, state_); |
| 143 DCHECK(!render_first_frame_and_stop_); | 138 DCHECK(!render_first_frame_and_stop_); |
| 144 DCHECK(!posted_maybe_stop_after_first_paint_); | 139 DCHECK(!posted_maybe_stop_after_first_paint_); |
| 145 DCHECK(!was_background_rendering_); | 140 DCHECK(!was_background_rendering_); |
| 146 DCHECK(!time_progressing_); | 141 DCHECK(!time_progressing_); |
| 147 | 142 |
| 148 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE); | 143 low_delay_ = (stream->liveness() == DemuxerStream::LIVENESS_LIVE); |
| 149 UMA_HISTOGRAM_BOOLEAN("Media.VideoRenderer.LowDelay", low_delay_); | 144 UMA_HISTOGRAM_BOOLEAN("Media.VideoRenderer.LowDelay", low_delay_); |
| 150 if (low_delay_) | 145 if (low_delay_) |
| 151 MEDIA_LOG(DEBUG, media_log_) << "Video rendering in low delay mode."; | 146 MEDIA_LOG(DEBUG, media_log_) << "Video rendering in low delay mode."; |
| 152 | 147 |
| 153 // Always post |init_cb_| because |this| could be destroyed if initialization | 148 // Always post |init_cb_| because |this| could be destroyed if initialization |
| 154 // failed. | 149 // failed. |
| 155 init_cb_ = BindToCurrentLoop(init_cb); | 150 init_cb_ = BindToCurrentLoop(init_cb); |
| 156 | 151 |
| 157 // Always post |buffering_state_cb_| because it may otherwise invoke reentrant | 152 client_ = client; |
| 158 // calls to OnTimeStateChanged() under lock, which can deadlock the compositor | |
| 159 // and media threads. | |
| 160 buffering_state_cb_ = BindToCurrentLoop(buffering_state_cb); | |
| 161 | |
| 162 statistics_cb_ = statistics_cb; | |
| 163 ended_cb_ = ended_cb; | |
| 164 error_cb_ = error_cb; | |
| 165 wall_clock_time_cb_ = wall_clock_time_cb; | 153 wall_clock_time_cb_ = wall_clock_time_cb; |
| 166 state_ = kInitializing; | 154 state_ = kInitializing; |
| 167 | 155 |
| 168 video_frame_stream_->Initialize( | 156 video_frame_stream_->Initialize( |
| 169 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized, | 157 stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized, |
| 170 weak_factory_.GetWeakPtr()), | 158 weak_factory_.GetWeakPtr()), |
| 171 cdm_context, statistics_cb, waiting_for_decryption_key_cb); | 159 cdm_context, base::Bind(&VideoRendererImpl::OnStatisticsUpdate, |
| 160 weak_factory_.GetWeakPtr()), | |
| 161 base::Bind(&VideoRendererImpl::OnWaitingForDecryptionKey, | |
| 162 weak_factory_.GetWeakPtr())); | |
| 172 } | 163 } |
| 173 | 164 |
| 174 scoped_refptr<VideoFrame> VideoRendererImpl::Render( | 165 scoped_refptr<VideoFrame> VideoRendererImpl::Render( |
| 175 base::TimeTicks deadline_min, | 166 base::TimeTicks deadline_min, |
| 176 base::TimeTicks deadline_max, | 167 base::TimeTicks deadline_max, |
| 177 bool background_rendering) { | 168 bool background_rendering) { |
| 178 base::AutoLock auto_lock(lock_); | 169 base::AutoLock auto_lock(lock_); |
| 179 DCHECK_EQ(state_, kPlaying); | 170 DCHECK_EQ(state_, kPlaying); |
| 180 | 171 |
| 181 size_t frames_dropped = 0; | 172 size_t frames_dropped = 0; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 269 // have not populated any buffers yet. | 260 // have not populated any buffers yet. |
| 270 state_ = kFlushed; | 261 state_ = kFlushed; |
| 271 | 262 |
| 272 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_)); | 263 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_)); |
| 273 if (!drop_frames_) | 264 if (!drop_frames_) |
| 274 algorithm_->disable_frame_dropping(); | 265 algorithm_->disable_frame_dropping(); |
| 275 | 266 |
| 276 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 267 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 277 } | 268 } |
| 278 | 269 |
| 270 void VideoRendererImpl::OnPlaybackEnded() { | |
| 271 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 272 client_->OnEnded(); | |
| 273 } | |
| 274 | |
| 275 void VideoRendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { | |
| 276 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 277 client_->OnStatisticsUpdate(stats); | |
| 278 } | |
| 279 | |
| 280 void VideoRendererImpl::OnWaitingForDecryptionKey() { | |
| 281 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 282 client_->OnWaitingForDecryptionKey(); | |
| 283 } | |
| 284 | |
| 279 void VideoRendererImpl::SetTickClockForTesting( | 285 void VideoRendererImpl::SetTickClockForTesting( |
| 280 std::unique_ptr<base::TickClock> tick_clock) { | 286 std::unique_ptr<base::TickClock> tick_clock) { |
| 281 tick_clock_.swap(tick_clock); | 287 tick_clock_.swap(tick_clock); |
| 282 } | 288 } |
| 283 | 289 |
| 284 void VideoRendererImpl::SetGpuMemoryBufferVideoForTesting( | 290 void VideoRendererImpl::SetGpuMemoryBufferVideoForTesting( |
| 285 std::unique_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool) { | 291 std::unique_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool) { |
| 286 gpu_memory_buffer_pool_.swap(gpu_memory_buffer_pool); | 292 gpu_memory_buffer_pool_.swap(gpu_memory_buffer_pool); |
| 287 } | 293 } |
| 288 | 294 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 return; | 355 return; |
| 350 | 356 |
| 351 DCHECK_NE(state_, kUninitialized); | 357 DCHECK_NE(state_, kUninitialized); |
| 352 DCHECK_NE(state_, kFlushed); | 358 DCHECK_NE(state_, kFlushed); |
| 353 | 359 |
| 354 CHECK(pending_read_); | 360 CHECK(pending_read_); |
| 355 pending_read_ = false; | 361 pending_read_ = false; |
| 356 | 362 |
| 357 if (status == VideoFrameStream::DECODE_ERROR) { | 363 if (status == VideoFrameStream::DECODE_ERROR) { |
| 358 DCHECK(!frame); | 364 DCHECK(!frame); |
| 359 PipelineStatus error = PIPELINE_ERROR_DECODE; | 365 client_->OnError(PIPELINE_ERROR_DECODE); |
|
xhwang
2016/05/09 18:13:23
The old code posts the callback (probably because
alokp
2016/05/09 21:31:44
Done.
| |
| 360 task_runner_->PostTask(FROM_HERE, base::Bind(error_cb_, error)); | |
| 361 return; | 366 return; |
| 362 } | 367 } |
| 363 | 368 |
| 364 // Already-queued VideoFrameStream ReadCB's can fire after various state | 369 // Already-queued VideoFrameStream ReadCB's can fire after various state |
| 365 // transitions have happened; in that case just drop those frames | 370 // transitions have happened; in that case just drop those frames |
| 366 // immediately. | 371 // immediately. |
| 367 if (state_ == kFlushing) | 372 if (state_ == kFlushing) |
| 368 return; | 373 return; |
| 369 | 374 |
| 370 DCHECK_EQ(state_, kPlaying); | 375 DCHECK_EQ(state_, kPlaying); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 444 | 449 |
| 445 return algorithm_->effective_frames_queued() > 0; | 450 return algorithm_->effective_frames_queued() > 0; |
| 446 } | 451 } |
| 447 | 452 |
| 448 void VideoRendererImpl::TransitionToHaveEnough_Locked() { | 453 void VideoRendererImpl::TransitionToHaveEnough_Locked() { |
| 449 DCHECK(task_runner_->BelongsToCurrentThread()); | 454 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 450 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 455 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
| 451 lock_.AssertAcquired(); | 456 lock_.AssertAcquired(); |
| 452 | 457 |
| 453 buffering_state_ = BUFFERING_HAVE_ENOUGH; | 458 buffering_state_ = BUFFERING_HAVE_ENOUGH; |
| 454 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); | 459 client_->OnBufferingStateChange(buffering_state_); |
|
xhwang
2016/05/09 18:13:23
The old |buffering_state_cb_| involves a post (Bin
alokp
2016/05/09 21:31:44
Done.
| |
| 455 } | 460 } |
| 456 | 461 |
| 457 void VideoRendererImpl::TransitionToHaveNothing() { | 462 void VideoRendererImpl::TransitionToHaveNothing() { |
| 458 DCHECK(task_runner_->BelongsToCurrentThread()); | 463 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 459 | 464 |
| 460 base::AutoLock auto_lock(lock_); | 465 base::AutoLock auto_lock(lock_); |
| 461 if (buffering_state_ != BUFFERING_HAVE_ENOUGH || HaveEnoughData_Locked()) | 466 if (buffering_state_ != BUFFERING_HAVE_ENOUGH || HaveEnoughData_Locked()) |
| 462 return; | 467 return; |
| 463 | 468 |
| 464 buffering_state_ = BUFFERING_HAVE_NOTHING; | 469 buffering_state_ = BUFFERING_HAVE_NOTHING; |
| 465 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING); | 470 client_->OnBufferingStateChange(buffering_state_); |
|
xhwang
2016/05/09 18:13:23
ditto about post
alokp
2016/05/09 21:31:44
Done.
| |
| 466 } | 471 } |
| 467 | 472 |
| 468 void VideoRendererImpl::AddReadyFrame_Locked( | 473 void VideoRendererImpl::AddReadyFrame_Locked( |
| 469 const scoped_refptr<VideoFrame>& frame) { | 474 const scoped_refptr<VideoFrame>& frame) { |
| 470 DCHECK(task_runner_->BelongsToCurrentThread()); | 475 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 471 lock_.AssertAcquired(); | 476 lock_.AssertAcquired(); |
| 472 DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)); | 477 DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)); |
| 473 | 478 |
| 474 frames_decoded_++; | 479 frames_decoded_++; |
| 475 | 480 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 532 DCHECK_GE(frames_dropped_, 0); | 537 DCHECK_GE(frames_dropped_, 0); |
| 533 | 538 |
| 534 if (frames_decoded_ || frames_dropped_) { | 539 if (frames_decoded_ || frames_dropped_) { |
| 535 PipelineStatistics statistics; | 540 PipelineStatistics statistics; |
| 536 statistics.video_frames_decoded = frames_decoded_; | 541 statistics.video_frames_decoded = frames_decoded_; |
| 537 statistics.video_frames_dropped = frames_dropped_; | 542 statistics.video_frames_dropped = frames_dropped_; |
| 538 | 543 |
| 539 const size_t memory_usage = algorithm_->GetMemoryUsage(); | 544 const size_t memory_usage = algorithm_->GetMemoryUsage(); |
| 540 statistics.video_memory_usage = memory_usage - last_video_memory_usage_; | 545 statistics.video_memory_usage = memory_usage - last_video_memory_usage_; |
| 541 | 546 |
| 542 task_runner_->PostTask(FROM_HERE, base::Bind(statistics_cb_, statistics)); | 547 task_runner_->PostTask(FROM_HERE, |
| 548 base::Bind(&VideoRendererImpl::OnStatisticsUpdate, | |
| 549 weak_factory_.GetWeakPtr(), statistics)); | |
| 543 frames_decoded_ = 0; | 550 frames_decoded_ = 0; |
| 544 frames_dropped_ = 0; | 551 frames_dropped_ = 0; |
| 545 last_video_memory_usage_ = memory_usage; | 552 last_video_memory_usage_ = memory_usage; |
| 546 } | 553 } |
| 547 } | 554 } |
| 548 | 555 |
| 549 void VideoRendererImpl::MaybeStopSinkAfterFirstPaint() { | 556 void VideoRendererImpl::MaybeStopSinkAfterFirstPaint() { |
| 550 DCHECK(task_runner_->BelongsToCurrentThread()); | 557 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 551 | 558 |
| 552 if (!time_progressing_ && sink_started_) | 559 if (!time_progressing_ && sink_started_) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 597 | 604 |
| 598 // Don't fire ended if time isn't moving and we have frames. | 605 // Don't fire ended if time isn't moving and we have frames. |
| 599 if (!time_progressing && algorithm_->frames_queued()) | 606 if (!time_progressing && algorithm_->frames_queued()) |
| 600 return; | 607 return; |
| 601 | 608 |
| 602 // Fire ended if we have no more effective frames or only ever had one frame. | 609 // Fire ended if we have no more effective frames or only ever had one frame. |
| 603 if (!algorithm_->effective_frames_queued() || | 610 if (!algorithm_->effective_frames_queued() || |
| 604 (algorithm_->frames_queued() == 1u && | 611 (algorithm_->frames_queued() == 1u && |
| 605 algorithm_->average_frame_duration().is_zero())) { | 612 algorithm_->average_frame_duration().is_zero())) { |
| 606 rendered_end_of_stream_ = true; | 613 rendered_end_of_stream_ = true; |
| 607 task_runner_->PostTask(FROM_HERE, ended_cb_); | 614 task_runner_->PostTask(FROM_HERE, |
| 615 base::Bind(&VideoRendererImpl::OnPlaybackEnded, | |
| 616 weak_factory_.GetWeakPtr())); | |
| 608 } | 617 } |
| 609 } | 618 } |
| 610 | 619 |
| 611 base::TimeTicks VideoRendererImpl::ConvertMediaTimestamp( | 620 base::TimeTicks VideoRendererImpl::ConvertMediaTimestamp( |
| 612 base::TimeDelta media_time) { | 621 base::TimeDelta media_time) { |
| 613 std::vector<base::TimeDelta> media_times(1, media_time); | 622 std::vector<base::TimeDelta> media_times(1, media_time); |
| 614 std::vector<base::TimeTicks> wall_clock_times; | 623 std::vector<base::TimeTicks> wall_clock_times; |
| 615 if (!wall_clock_time_cb_.Run(media_times, &wall_clock_times)) | 624 if (!wall_clock_time_cb_.Run(media_times, &wall_clock_times)) |
| 616 return base::TimeTicks(); | 625 return base::TimeTicks(); |
| 617 return wall_clock_times[0]; | 626 return wall_clock_times[0]; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 665 // the entire queue. Note: this may cause slight inaccuracies in the number | 674 // the entire queue. Note: this may cause slight inaccuracies in the number |
| 666 // of dropped frames since the frame may have been rendered before. | 675 // of dropped frames since the frame may have been rendered before. |
| 667 if (!sink_started_ && !algorithm_->effective_frames_queued()) { | 676 if (!sink_started_ && !algorithm_->effective_frames_queued()) { |
| 668 frames_dropped_ += algorithm_->frames_queued(); | 677 frames_dropped_ += algorithm_->frames_queued(); |
| 669 algorithm_->Reset( | 678 algorithm_->Reset( |
| 670 VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates); | 679 VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates); |
| 671 } | 680 } |
| 672 } | 681 } |
| 673 | 682 |
| 674 } // namespace media | 683 } // namespace media |
| OLD | NEW |