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

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

Issue 2366373003: Not for submission. fastSeek prototype. (Closed)
Patch Set: Created 4 years, 2 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') | no next file » | 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"
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/renderer_client.h"
24 #include "media/base/stream_position.h"
24 #include "media/base/video_frame.h" 25 #include "media/base/video_frame.h"
25 #include "media/renderers/gpu_video_accelerator_factories.h" 26 #include "media/renderers/gpu_video_accelerator_factories.h"
26 #include "media/video/gpu_memory_buffer_video_frame_pool.h" 27 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
27 28
28 namespace media { 29 namespace media {
29 30
30 VideoRendererImpl::VideoRendererImpl( 31 VideoRendererImpl::VideoRendererImpl(
31 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 32 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
32 const scoped_refptr<base::TaskRunner>& worker_task_runner, 33 const scoped_refptr<base::TaskRunner>& worker_task_runner,
33 VideoRendererSink* sink, 34 VideoRendererSink* sink,
(...skipping 10 matching lines...) Expand all
44 media_log)), 45 media_log)),
45 gpu_memory_buffer_pool_(nullptr), 46 gpu_memory_buffer_pool_(nullptr),
46 media_log_(media_log), 47 media_log_(media_log),
47 low_delay_(false), 48 low_delay_(false),
48 received_end_of_stream_(false), 49 received_end_of_stream_(false),
49 rendered_end_of_stream_(false), 50 rendered_end_of_stream_(false),
50 state_(kUninitialized), 51 state_(kUninitialized),
51 pending_read_(false), 52 pending_read_(false),
52 drop_frames_(drop_frames), 53 drop_frames_(drop_frames),
53 buffering_state_(BUFFERING_HAVE_NOTHING), 54 buffering_state_(BUFFERING_HAVE_NOTHING),
55 start_rendering_from_first_frame_(false),
54 frames_decoded_(0), 56 frames_decoded_(0),
55 frames_dropped_(0), 57 frames_dropped_(0),
56 tick_clock_(new base::DefaultTickClock()), 58 tick_clock_(new base::DefaultTickClock()),
57 was_background_rendering_(false), 59 was_background_rendering_(false),
58 time_progressing_(false), 60 time_progressing_(false),
59 last_video_memory_usage_(0), 61 last_video_memory_usage_(0),
60 have_renderered_frames_(false), 62 have_renderered_frames_(false),
61 last_frame_opaque_(false), 63 last_frame_opaque_(false),
62 weak_factory_(this), 64 weak_factory_(this),
63 frame_callback_weak_factory_(this) { 65 frame_callback_weak_factory_(this) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone, 111 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone,
110 weak_factory_.GetWeakPtr())); 112 weak_factory_.GetWeakPtr()));
111 113
112 // To avoid unnecessary work by VDAs, only delete queued frames after 114 // To avoid unnecessary work by VDAs, only delete queued frames after
113 // resetting |video_frame_stream_|. If this is done in the opposite order VDAs 115 // resetting |video_frame_stream_|. If this is done in the opposite order VDAs
114 // will get a bunch of ReusePictureBuffer() calls before the Reset(), which 116 // will get a bunch of ReusePictureBuffer() calls before the Reset(), which
115 // they may use to output more frames that won't be used. 117 // they may use to output more frames that won't be used.
116 algorithm_->Reset(); 118 algorithm_->Reset();
117 } 119 }
118 120
119 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { 121 void VideoRendererImpl::StartPlayingFrom(StreamPosition position) {
120 DVLOG(1) << __func__ << "(" << timestamp.InMicroseconds() << ")"; 122 DVLOG(1) << __func__ << "(" << ToString(position) << ")";
121 DCHECK(task_runner_->BelongsToCurrentThread()); 123 DCHECK(task_runner_->BelongsToCurrentThread());
122 base::AutoLock auto_lock(lock_); 124 base::AutoLock auto_lock(lock_);
123 DCHECK_EQ(state_, kFlushed); 125 DCHECK_EQ(state_, kFlushed);
124 DCHECK(!pending_read_); 126 DCHECK(!pending_read_);
125 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 127 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING);
126 128
127 state_ = kPlaying; 129 state_ = kPlaying;
128 start_timestamp_ = timestamp; 130 start_timestamp_ = position.time;
131 start_rendering_from_first_frame_ =
132 position.kind == StreamPosition::Kind::KEY_FRAME_PRECEDING_TIME;
129 AttemptRead_Locked(); 133 AttemptRead_Locked();
130 } 134 }
131 135
132 void VideoRendererImpl::Initialize( 136 void VideoRendererImpl::Initialize(
133 DemuxerStream* stream, 137 DemuxerStream* stream,
134 CdmContext* cdm_context, 138 CdmContext* cdm_context,
135 RendererClient* client, 139 RendererClient* client,
136 const TimeSource::WallClockTimeCB& wall_clock_time_cb, 140 const TimeSource::WallClockTimeCB& wall_clock_time_cb,
137 const PipelineStatusCB& init_cb) { 141 const PipelineStatusCB& init_cb) {
138 DCHECK(task_runner_->BelongsToCurrentThread()); 142 DCHECK(task_runner_->BelongsToCurrentThread());
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 DCHECK(task_runner_->BelongsToCurrentThread()); 234 DCHECK(task_runner_->BelongsToCurrentThread());
231 base::AutoLock auto_lock(lock_); 235 base::AutoLock auto_lock(lock_);
232 DCHECK_EQ(state_, kInitializing); 236 DCHECK_EQ(state_, kInitializing);
233 237
234 if (!success) { 238 if (!success) {
235 state_ = kUninitialized; 239 state_ = kUninitialized;
236 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); 240 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
237 return; 241 return;
238 } 242 }
239 243
240 // We're all good! Consider ourselves flushed. (ThreadMain() should never 244 // We're all good! Consider ourselves flushed because we have not populated
241 // see us in the kUninitialized state). 245 // any buffers yet.
242 // Since we had an initial Preroll(), we consider ourself flushed, because we
243 // have not populated any buffers yet.
244 state_ = kFlushed; 246 state_ = kFlushed;
245 247
246 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_)); 248 algorithm_.reset(new VideoRendererAlgorithm(wall_clock_time_cb_));
247 if (!drop_frames_) 249 if (!drop_frames_)
248 algorithm_->disable_frame_dropping(); 250 algorithm_->disable_frame_dropping();
249 251
250 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 252 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
251 } 253 }
252 254
253 void VideoRendererImpl::OnPlaybackError(PipelineStatus error) { 255 void VideoRendererImpl::OnPlaybackError(PipelineStatus error) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 359
358 // Can happen when demuxers are preparing for a new Seek(). 360 // Can happen when demuxers are preparing for a new Seek().
359 if (!frame) { 361 if (!frame) {
360 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED); 362 DCHECK_EQ(status, VideoFrameStream::DEMUXER_READ_ABORTED);
361 return; 363 return;
362 } 364 }
363 365
364 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) { 366 if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
365 DCHECK(!received_end_of_stream_); 367 DCHECK(!received_end_of_stream_);
366 received_end_of_stream_ = true; 368 received_end_of_stream_ = true;
369 } else if (start_rendering_from_first_frame_) {
370 start_timestamp_ = frame->timestamp();
371 start_rendering_from_first_frame_ = false;
372 client_->OnFirstVideoFrameTimestampKnown(frame->timestamp());
373 AddReadyFrame_Locked(frame);
367 } else if ((low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) && 374 } else if ((low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) &&
368 IsBeforeStartTime(frame->timestamp())) { 375 IsBeforeStartTime(frame->timestamp())) {
369 // Don't accumulate frames that are earlier than the start time if we 376 // Don't accumulate frames that are earlier than the start time if we
370 // won't have a chance for a better frame, otherwise we could declare 377 // won't have a chance for a better frame, otherwise we could declare
371 // HAVE_ENOUGH_DATA and start playback prematurely. 378 // HAVE_ENOUGH_DATA and start playback prematurely.
372 AttemptRead_Locked(); 379 AttemptRead_Locked();
373 return; 380 return;
374 } else { 381 } else {
375 // If the sink hasn't been started, we still have time to release less 382 // If the sink hasn't been started, we still have time to release less
376 // than ideal frames prior to startup. We don't use IsBeforeStartTime() 383 // than ideal frames prior to startup. We don't use IsBeforeStartTime()
377 // here since it's based on a duration estimate and we can be exact here. 384 // here since it's based on a duration estimate and we can be exact here.
378 if (!sink_started_ && frame->timestamp() <= start_timestamp_) 385 if (!sink_started_ && frame->timestamp() <= start_timestamp_) {
379 algorithm_->Reset(); 386 algorithm_->Reset();
387 }
380 388
381 AddReadyFrame_Locked(frame); 389 AddReadyFrame_Locked(frame);
382 } 390 }
383 391
384 // Attempt to purge bad frames in case of underflow or backgrounding. 392 // Attempt to purge bad frames in case of underflow or backgrounding.
385 RemoveFramesForUnderflowOrBackgroundRendering(); 393 RemoveFramesForUnderflowOrBackgroundRendering();
386 394
387 // We may have removed all frames above and have reached end of stream. 395 // We may have removed all frames above and have reached end of stream.
388 MaybeFireEndedCallback_Locked(time_progressing_); 396 MaybeFireEndedCallback_Locked(time_progressing_);
389 397
390 // Update statistics here instead of during Render() when the sink is stopped. 398 // Update statistics here instead of during Render() when the sink is stopped.
391 if (!sink_started_) 399 if (!sink_started_)
392 UpdateStats_Locked(); 400 UpdateStats_Locked();
393 401
394 // Paint the first frame if possible and necessary. PaintSingleFrame() will 402 // Paint the first frame if possible and necessary. PaintSingleFrame() will
395 // ignore repeated calls for the same frame. Paint ahead of HAVE_ENOUGH_DATA 403 // ignore repeated calls for the same frame. Paint ahead of HAVE_ENOUGH_DATA
396 // to ensure the user sees the frame as early as possible. 404 // to ensure the user sees the frame as early as possible.
397 if (!sink_started_ && algorithm_->frames_queued()) { 405 if (!sink_started_ && algorithm_->frames_queued()) {
398 // We want to paint the first frame under two conditions: Either (1) we have 406 // We want to paint the first frame under two conditions: Either (1) we have
399 // enough frames to know it's definitely the first frame or (2) there may be 407 // enough frames to know it's definitely the first frame or (2) there may be
400 // no more frames coming (sometimes unless we paint one of them). 408 // no more frames coming (sometimes unless we paint one of them).
401 // 409 //
402 // For the first condition, we need at least two frames or the first frame
403 // must have a timestamp >= |start_timestamp_|, since otherwise we may be
404 // prerolling frames before the actual start time that will be dropped.
405 if (algorithm_->frames_queued() > 1 || received_end_of_stream_ || 410 if (algorithm_->frames_queued() > 1 || received_end_of_stream_ ||
406 algorithm_->first_frame()->timestamp() >= start_timestamp_ || 411 algorithm_->first_frame()->timestamp() >= start_timestamp_ ||
407 low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) { 412 low_delay_ || !video_frame_stream_->CanReadWithoutStalling()) {
408 scoped_refptr<VideoFrame> frame = algorithm_->first_frame(); 413 scoped_refptr<VideoFrame> frame = algorithm_->first_frame();
409 CheckForMetadataChanges(frame->format(), frame->natural_size()); 414 CheckForMetadataChanges(frame->format(), frame->natural_size());
410 sink_->PaintSingleFrame(frame); 415 sink_->PaintSingleFrame(frame);
411 } 416 }
412 } 417 }
413 418
414 // Signal buffering state if we've met our conditions. 419 // Signal buffering state if we've met our conditions.
415 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) 420 if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked())
416 TransitionToHaveEnough_Locked(); 421 TransitionToHaveEnough_Locked();
417 422
418 // Always request more decoded video if we have capacity. This serves two 423 // Always request more decoded video if we have capacity.
419 // purposes:
420 // 1) Prerolling while paused
421 // 2) Keeps decoding going if video rendering thread starts falling behind
422 AttemptRead_Locked(); 424 AttemptRead_Locked();
423 } 425 }
424 426
425 bool VideoRendererImpl::HaveEnoughData_Locked() { 427 bool VideoRendererImpl::HaveEnoughData_Locked() {
426 DCHECK_EQ(state_, kPlaying); 428 DCHECK_EQ(state_, kPlaying);
427 lock_.AssertAcquired(); 429 lock_.AssertAcquired();
428 430
429 if (received_end_of_stream_) 431 if (received_end_of_stream_)
430 return true; 432 return true;
431 433
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 return wall_clock_times[0]; 618 return wall_clock_times[0];
617 } 619 }
618 620
619 base::TimeTicks VideoRendererImpl::GetCurrentMediaTimeAsWallClockTime() { 621 base::TimeTicks VideoRendererImpl::GetCurrentMediaTimeAsWallClockTime() {
620 std::vector<base::TimeTicks> current_time; 622 std::vector<base::TimeTicks> current_time;
621 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), &current_time); 623 wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), &current_time);
622 return current_time[0]; 624 return current_time[0];
623 } 625 }
624 626
625 bool VideoRendererImpl::IsBeforeStartTime(base::TimeDelta timestamp) { 627 bool VideoRendererImpl::IsBeforeStartTime(base::TimeDelta timestamp) {
628 if (start_rendering_from_first_frame_)
629 return false;
626 return timestamp + video_frame_stream_->AverageDuration() < start_timestamp_; 630 return timestamp + video_frame_stream_->AverageDuration() < start_timestamp_;
627 } 631 }
628 632
629 void VideoRendererImpl::RemoveFramesForUnderflowOrBackgroundRendering() { 633 void VideoRendererImpl::RemoveFramesForUnderflowOrBackgroundRendering() {
630 // Nothing to do if we're not underflowing, background rendering, or frame 634 // Nothing to do if we're not underflowing, background rendering, or frame
631 // dropping is disabled (test only). 635 // dropping is disabled (test only).
632 const bool have_nothing = buffering_state_ == BUFFERING_HAVE_NOTHING; 636 const bool have_nothing = buffering_state_ == BUFFERING_HAVE_NOTHING;
633 if (!was_background_rendering_ && !have_nothing && !drop_frames_) 637 if (!was_background_rendering_ && !have_nothing && !drop_frames_)
634 return; 638 return;
635 639
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
698 702
699 void VideoRendererImpl::AttemptReadAndCheckForMetadataChanges( 703 void VideoRendererImpl::AttemptReadAndCheckForMetadataChanges(
700 VideoPixelFormat pixel_format, 704 VideoPixelFormat pixel_format,
701 const gfx::Size& natural_size) { 705 const gfx::Size& natural_size) {
702 base::AutoLock auto_lock(lock_); 706 base::AutoLock auto_lock(lock_);
703 CheckForMetadataChanges(pixel_format, natural_size); 707 CheckForMetadataChanges(pixel_format, natural_size);
704 AttemptRead_Locked(); 708 AttemptRead_Locked();
705 } 709 }
706 710
707 } // namespace media 711 } // namespace media
OLDNEW
« no previous file with comments | « media/renderers/video_renderer_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698