OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/base/pipeline.h" | 5 #include "media/base/pipeline.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 : task_runner_(task_runner), | 38 : task_runner_(task_runner), |
39 media_log_(media_log), | 39 media_log_(media_log), |
40 running_(false), | 40 running_(false), |
41 did_loading_progress_(false), | 41 did_loading_progress_(false), |
42 total_bytes_(0), | 42 total_bytes_(0), |
43 volume_(1.0f), | 43 volume_(1.0f), |
44 playback_rate_(0.0f), | 44 playback_rate_(0.0f), |
45 clock_(new Clock(&default_tick_clock_)), | 45 clock_(new Clock(&default_tick_clock_)), |
46 waiting_for_clock_update_(false), | 46 waiting_for_clock_update_(false), |
47 status_(PIPELINE_OK), | 47 status_(PIPELINE_OK), |
| 48 has_audio_(false), |
| 49 has_video_(false), |
48 state_(kCreated), | 50 state_(kCreated), |
49 audio_ended_(false), | 51 audio_ended_(false), |
50 video_ended_(false), | 52 video_ended_(false), |
51 text_ended_(false), | 53 text_ended_(false), |
52 audio_disabled_(false), | 54 audio_disabled_(false), |
53 demuxer_(NULL), | 55 demuxer_(NULL), |
54 creation_time_(default_tick_clock_.NowTicks()) { | 56 creation_time_(default_tick_clock_.NowTicks()) { |
55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 57 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
56 media_log_->AddEvent( | 58 media_log_->AddEvent( |
57 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); | 59 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); |
58 } | 60 } |
59 | 61 |
60 Pipeline::~Pipeline() { | 62 Pipeline::~Pipeline() { |
61 DCHECK(thread_checker_.CalledOnValidThread()) | 63 DCHECK(thread_checker_.CalledOnValidThread()) |
62 << "Pipeline must be destroyed on same thread that created it"; | 64 << "Pipeline must be destroyed on same thread that created it"; |
63 DCHECK(!running_) << "Stop() must complete before destroying object"; | 65 DCHECK(!running_) << "Stop() must complete before destroying object"; |
64 DCHECK(stop_cb_.is_null()); | 66 DCHECK(stop_cb_.is_null()); |
65 DCHECK(seek_cb_.is_null()); | 67 DCHECK(seek_cb_.is_null()); |
66 | 68 |
67 media_log_->AddEvent( | 69 media_log_->AddEvent( |
68 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); | 70 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); |
69 } | 71 } |
70 | 72 |
71 void Pipeline::Start(scoped_ptr<FilterCollection> collection, | 73 void Pipeline::Start(scoped_ptr<FilterCollection> collection, |
72 const base::Closure& ended_cb, | 74 const base::Closure& ended_cb, |
73 const PipelineStatusCB& error_cb, | 75 const PipelineStatusCB& error_cb, |
74 const PipelineStatusCB& seek_cb, | 76 const PipelineStatusCB& seek_cb, |
75 const PipelineMetadataCB& metadata_cb, | 77 const BufferingStateCB& buffering_state_cb, |
76 const base::Closure& preroll_completed_cb, | |
77 const base::Closure& duration_change_cb) { | 78 const base::Closure& duration_change_cb) { |
78 DCHECK(!ended_cb.is_null()); | |
79 DCHECK(!error_cb.is_null()); | |
80 DCHECK(!seek_cb.is_null()); | |
81 DCHECK(!metadata_cb.is_null()); | |
82 DCHECK(!preroll_completed_cb.is_null()); | |
83 | |
84 base::AutoLock auto_lock(lock_); | 79 base::AutoLock auto_lock(lock_); |
85 CHECK(!running_) << "Media pipeline is already running"; | 80 CHECK(!running_) << "Media pipeline is already running"; |
| 81 DCHECK(!buffering_state_cb.is_null()); |
| 82 |
86 running_ = true; | 83 running_ = true; |
87 | 84 task_runner_->PostTask(FROM_HERE, base::Bind( |
88 filter_collection_ = collection.Pass(); | 85 &Pipeline::StartTask, base::Unretained(this), base::Passed(&collection), |
89 ended_cb_ = ended_cb; | 86 ended_cb, error_cb, seek_cb, buffering_state_cb, duration_change_cb)); |
90 error_cb_ = error_cb; | |
91 seek_cb_ = seek_cb; | |
92 metadata_cb_ = metadata_cb; | |
93 preroll_completed_cb_ = preroll_completed_cb; | |
94 duration_change_cb_ = duration_change_cb; | |
95 | |
96 task_runner_->PostTask( | |
97 FROM_HERE, base::Bind(&Pipeline::StartTask, base::Unretained(this))); | |
98 } | 87 } |
99 | 88 |
100 void Pipeline::Stop(const base::Closure& stop_cb) { | 89 void Pipeline::Stop(const base::Closure& stop_cb) { |
101 base::AutoLock auto_lock(lock_); | 90 base::AutoLock auto_lock(lock_); |
102 task_runner_->PostTask(FROM_HERE, base::Bind( | 91 task_runner_->PostTask(FROM_HERE, base::Bind( |
103 &Pipeline::StopTask, base::Unretained(this), stop_cb)); | 92 &Pipeline::StopTask, base::Unretained(this), stop_cb)); |
104 } | 93 } |
105 | 94 |
106 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { | 95 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { |
107 base::AutoLock auto_lock(lock_); | 96 base::AutoLock auto_lock(lock_); |
108 if (!running_) { | 97 if (!running_) { |
109 NOTREACHED() << "Media pipeline isn't running"; | 98 NOTREACHED() << "Media pipeline isn't running"; |
110 return; | 99 return; |
111 } | 100 } |
112 | 101 |
113 task_runner_->PostTask(FROM_HERE, base::Bind( | 102 task_runner_->PostTask(FROM_HERE, base::Bind( |
114 &Pipeline::SeekTask, base::Unretained(this), time, seek_cb)); | 103 &Pipeline::SeekTask, base::Unretained(this), time, seek_cb)); |
115 } | 104 } |
116 | 105 |
117 bool Pipeline::IsRunning() const { | 106 bool Pipeline::IsRunning() const { |
118 base::AutoLock auto_lock(lock_); | 107 base::AutoLock auto_lock(lock_); |
119 return running_; | 108 return running_; |
120 } | 109 } |
121 | 110 |
| 111 bool Pipeline::HasAudio() const { |
| 112 base::AutoLock auto_lock(lock_); |
| 113 return has_audio_; |
| 114 } |
| 115 |
| 116 bool Pipeline::HasVideo() const { |
| 117 base::AutoLock auto_lock(lock_); |
| 118 return has_video_; |
| 119 } |
| 120 |
122 float Pipeline::GetPlaybackRate() const { | 121 float Pipeline::GetPlaybackRate() const { |
123 base::AutoLock auto_lock(lock_); | 122 base::AutoLock auto_lock(lock_); |
124 return playback_rate_; | 123 return playback_rate_; |
125 } | 124 } |
126 | 125 |
127 void Pipeline::SetPlaybackRate(float playback_rate) { | 126 void Pipeline::SetPlaybackRate(float playback_rate) { |
128 if (playback_rate < 0.0f) | 127 if (playback_rate < 0.0f) |
129 return; | 128 return; |
130 | 129 |
131 base::AutoLock auto_lock(lock_); | 130 base::AutoLock auto_lock(lock_); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 TimeDelta Pipeline::GetMediaDuration() const { | 181 TimeDelta Pipeline::GetMediaDuration() const { |
183 base::AutoLock auto_lock(lock_); | 182 base::AutoLock auto_lock(lock_); |
184 return clock_->Duration(); | 183 return clock_->Duration(); |
185 } | 184 } |
186 | 185 |
187 int64 Pipeline::GetTotalBytes() const { | 186 int64 Pipeline::GetTotalBytes() const { |
188 base::AutoLock auto_lock(lock_); | 187 base::AutoLock auto_lock(lock_); |
189 return total_bytes_; | 188 return total_bytes_; |
190 } | 189 } |
191 | 190 |
| 191 gfx::Size Pipeline::GetInitialNaturalSize() const { |
| 192 base::AutoLock auto_lock(lock_); |
| 193 return initial_natural_size_; |
| 194 } |
| 195 |
192 bool Pipeline::DidLoadingProgress() const { | 196 bool Pipeline::DidLoadingProgress() const { |
193 base::AutoLock auto_lock(lock_); | 197 base::AutoLock auto_lock(lock_); |
194 bool ret = did_loading_progress_; | 198 bool ret = did_loading_progress_; |
195 did_loading_progress_ = false; | 199 did_loading_progress_ = false; |
196 return ret; | 200 return ret; |
197 } | 201 } |
198 | 202 |
199 PipelineStatistics Pipeline::GetStatistics() const { | 203 PipelineStatistics Pipeline::GetStatistics() const { |
200 base::AutoLock auto_lock(lock_); | 204 base::AutoLock auto_lock(lock_); |
201 return statistics_; | 205 return statistics_; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 &Pipeline::AudioDisabledTask, base::Unretained(this))); | 326 &Pipeline::AudioDisabledTask, base::Unretained(this))); |
323 media_log_->AddEvent( | 327 media_log_->AddEvent( |
324 media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); | 328 media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); |
325 } | 329 } |
326 | 330 |
327 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { | 331 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
328 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); | 332 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); |
329 DCHECK(IsRunning()); | 333 DCHECK(IsRunning()); |
330 base::AutoLock auto_lock(lock_); | 334 base::AutoLock auto_lock(lock_); |
331 | 335 |
332 if (audio_disabled_) | 336 if (!has_audio_) |
333 return; | 337 return; |
334 | |
335 if (waiting_for_clock_update_ && time < clock_->Elapsed()) | 338 if (waiting_for_clock_update_ && time < clock_->Elapsed()) |
336 return; | 339 return; |
337 | 340 |
338 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see | 341 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see |
339 // http://crbug.com/137973 | 342 // http://crbug.com/137973 |
340 if (state_ == kSeeking) | 343 if (state_ == kSeeking) |
341 return; | 344 return; |
342 | 345 |
343 clock_->SetTime(time, max_time); | 346 clock_->SetTime(time, max_time); |
344 StartClockIfWaitingForTimeUpdate_Locked(); | 347 StartClockIfWaitingForTimeUpdate_Locked(); |
345 } | 348 } |
346 | 349 |
347 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { | 350 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { |
348 DCHECK(IsRunning()); | 351 DCHECK(IsRunning()); |
349 base::AutoLock auto_lock(lock_); | 352 base::AutoLock auto_lock(lock_); |
350 | 353 |
351 if (audio_renderer_ && !audio_disabled_) | 354 if (has_audio_) |
352 return; | 355 return; |
353 | 356 |
354 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see | 357 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see |
355 // http://crbug.com/137973 | 358 // http://crbug.com/137973 |
356 if (state_ == kSeeking) | 359 if (state_ == kSeeking) |
357 return; | 360 return; |
358 | 361 |
359 DCHECK(!waiting_for_clock_update_); | 362 DCHECK(!waiting_for_clock_update_); |
360 clock_->SetMaxTime(max_time); | 363 clock_->SetMaxTime(max_time); |
361 } | 364 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 case kInitVideoRenderer: | 455 case kInitVideoRenderer: |
453 return InitializeVideoRenderer(done_cb); | 456 return InitializeVideoRenderer(done_cb); |
454 | 457 |
455 case kInitPrerolling: | 458 case kInitPrerolling: |
456 filter_collection_.reset(); | 459 filter_collection_.reset(); |
457 { | 460 { |
458 base::AutoLock l(lock_); | 461 base::AutoLock l(lock_); |
459 // We do not want to start the clock running. We only want to set the | 462 // We do not want to start the clock running. We only want to set the |
460 // base media time so our timestamp calculations will be correct. | 463 // base media time so our timestamp calculations will be correct. |
461 clock_->SetTime(demuxer_->GetStartTime(), demuxer_->GetStartTime()); | 464 clock_->SetTime(demuxer_->GetStartTime(), demuxer_->GetStartTime()); |
| 465 |
| 466 // TODO(scherkus): |has_audio_| should be true no matter what -- |
| 467 // otherwise people with muted/disabled sound cards will make our |
| 468 // default controls look as if every video doesn't contain an audio |
| 469 // track. |
| 470 has_audio_ = audio_renderer_ != NULL && !audio_disabled_; |
| 471 has_video_ = video_renderer_ != NULL; |
462 } | 472 } |
463 if (!audio_renderer_ && !video_renderer_) { | 473 if (!audio_renderer_ && !video_renderer_) { |
464 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); | 474 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); |
465 return; | 475 return; |
466 } | 476 } |
467 | 477 |
468 { | 478 buffering_state_cb_.Run(kHaveMetadata); |
469 PipelineMetadata metadata; | |
470 metadata.has_audio = audio_renderer_; | |
471 metadata.has_video = video_renderer_; | |
472 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | |
473 if (stream) | |
474 metadata.natural_size = stream->video_decoder_config().natural_size(); | |
475 metadata_cb_.Run(metadata); | |
476 } | |
477 | 479 |
478 return DoInitialPreroll(done_cb); | 480 return DoInitialPreroll(done_cb); |
479 | 481 |
480 case kStarting: | 482 case kStarting: |
481 return DoPlay(done_cb); | 483 return DoPlay(done_cb); |
482 | 484 |
483 case kStarted: | 485 case kStarted: |
484 { | 486 { |
485 base::AutoLock l(lock_); | 487 base::AutoLock l(lock_); |
486 // We use audio stream to update the clock. So if there is such a | 488 // We use audio stream to update the clock. So if there is such a |
487 // stream, we pause the clock until we receive a valid timestamp. | 489 // stream, we pause the clock until we receive a valid timestamp. |
488 waiting_for_clock_update_ = true; | 490 waiting_for_clock_update_ = true; |
489 if (!audio_renderer_ || audio_disabled_) { | 491 if (!has_audio_) { |
490 clock_->SetMaxTime(clock_->Duration()); | 492 clock_->SetMaxTime(clock_->Duration()); |
491 StartClockIfWaitingForTimeUpdate_Locked(); | 493 StartClockIfWaitingForTimeUpdate_Locked(); |
492 } | 494 } |
493 } | 495 } |
494 | 496 |
495 DCHECK(!seek_cb_.is_null()); | 497 DCHECK(!seek_cb_.is_null()); |
496 DCHECK_EQ(status_, PIPELINE_OK); | 498 DCHECK_EQ(status_, PIPELINE_OK); |
497 | 499 |
498 // Fire canplaythrough immediately after playback begins because of | 500 // Fire canplaythrough immediately after playback begins because of |
499 // crbug.com/106480. | 501 // crbug.com/106480. |
500 // TODO(vrk): set ready state to HaveFutureData when bug above is fixed. | 502 // TODO(vrk): set ready state to HaveFutureData when bug above is fixed. |
501 preroll_completed_cb_.Run(); | 503 buffering_state_cb_.Run(kPrerollCompleted); |
502 return base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | 504 return base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
503 | 505 |
504 case kStopping: | 506 case kStopping: |
505 case kStopped: | 507 case kStopped: |
506 case kCreated: | 508 case kCreated: |
507 case kSeeking: | 509 case kSeeking: |
508 NOTREACHED() << "State has no transition: " << state_; | 510 NOTREACHED() << "State has no transition: " << state_; |
509 return; | 511 return; |
510 } | 512 } |
511 } | 513 } |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 | 724 |
723 // Called from any thread. | 725 // Called from any thread. |
724 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { | 726 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { |
725 base::AutoLock auto_lock(lock_); | 727 base::AutoLock auto_lock(lock_); |
726 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; | 728 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; |
727 statistics_.video_bytes_decoded += stats.video_bytes_decoded; | 729 statistics_.video_bytes_decoded += stats.video_bytes_decoded; |
728 statistics_.video_frames_decoded += stats.video_frames_decoded; | 730 statistics_.video_frames_decoded += stats.video_frames_decoded; |
729 statistics_.video_frames_dropped += stats.video_frames_dropped; | 731 statistics_.video_frames_dropped += stats.video_frames_dropped; |
730 } | 732 } |
731 | 733 |
732 void Pipeline::StartTask() { | 734 void Pipeline::StartTask(scoped_ptr<FilterCollection> filter_collection, |
| 735 const base::Closure& ended_cb, |
| 736 const PipelineStatusCB& error_cb, |
| 737 const PipelineStatusCB& seek_cb, |
| 738 const BufferingStateCB& buffering_state_cb, |
| 739 const base::Closure& duration_change_cb) { |
733 DCHECK(task_runner_->BelongsToCurrentThread()); | 740 DCHECK(task_runner_->BelongsToCurrentThread()); |
734 CHECK_EQ(kCreated, state_) | 741 CHECK_EQ(kCreated, state_) |
735 << "Media pipeline cannot be started more than once"; | 742 << "Media pipeline cannot be started more than once"; |
736 | 743 |
| 744 filter_collection_ = filter_collection.Pass(); |
| 745 ended_cb_ = ended_cb; |
| 746 error_cb_ = error_cb; |
| 747 seek_cb_ = seek_cb; |
| 748 buffering_state_cb_ = buffering_state_cb; |
| 749 duration_change_cb_ = duration_change_cb; |
| 750 |
737 text_renderer_ = filter_collection_->GetTextRenderer(); | 751 text_renderer_ = filter_collection_->GetTextRenderer(); |
738 | 752 |
739 if (text_renderer_) { | 753 if (text_renderer_) { |
740 text_renderer_->Initialize( | 754 text_renderer_->Initialize( |
741 base::Bind(&Pipeline::OnTextRendererEnded, base::Unretained(this))); | 755 base::Bind(&Pipeline::OnTextRendererEnded, base::Unretained(this))); |
742 } | 756 } |
743 | 757 |
744 StateTransitionTask(PIPELINE_OK); | 758 StateTransitionTask(PIPELINE_OK); |
745 } | 759 } |
746 | 760 |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
904 } | 918 } |
905 | 919 |
906 DCHECK_EQ(status_, PIPELINE_OK); | 920 DCHECK_EQ(status_, PIPELINE_OK); |
907 ended_cb_.Run(); | 921 ended_cb_.Run(); |
908 } | 922 } |
909 | 923 |
910 void Pipeline::AudioDisabledTask() { | 924 void Pipeline::AudioDisabledTask() { |
911 DCHECK(task_runner_->BelongsToCurrentThread()); | 925 DCHECK(task_runner_->BelongsToCurrentThread()); |
912 | 926 |
913 base::AutoLock auto_lock(lock_); | 927 base::AutoLock auto_lock(lock_); |
| 928 has_audio_ = false; |
914 audio_disabled_ = true; | 929 audio_disabled_ = true; |
915 | 930 |
916 // Notify our demuxer that we're no longer rendering audio. | 931 // Notify our demuxer that we're no longer rendering audio. |
917 demuxer_->OnAudioRendererDisabled(); | 932 demuxer_->OnAudioRendererDisabled(); |
918 | 933 |
919 // Start clock since there is no more audio to trigger clock updates. | 934 // Start clock since there is no more audio to trigger clock updates. |
920 clock_->SetMaxTime(clock_->Duration()); | 935 clock_->SetMaxTime(clock_->Duration()); |
921 StartClockIfWaitingForTimeUpdate_Locked(); | 936 StartClockIfWaitingForTimeUpdate_Locked(); |
922 } | 937 } |
923 | 938 |
(...skipping 28 matching lines...) Expand all Loading... |
952 base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)), | 967 base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)), |
953 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), | 968 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), |
954 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), | 969 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), |
955 base::Bind(&Pipeline::OnAudioDisabled, base::Unretained(this)), | 970 base::Bind(&Pipeline::OnAudioDisabled, base::Unretained(this)), |
956 base::Bind(&Pipeline::SetError, base::Unretained(this))); | 971 base::Bind(&Pipeline::SetError, base::Unretained(this))); |
957 } | 972 } |
958 | 973 |
959 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { | 974 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { |
960 DCHECK(task_runner_->BelongsToCurrentThread()); | 975 DCHECK(task_runner_->BelongsToCurrentThread()); |
961 | 976 |
| 977 // Get an initial natural size so we have something when we signal |
| 978 // the kHaveMetadata buffering state. |
| 979 // |
| 980 // TODO(acolwell): We have to query demuxer outside of the lock to prevent a |
| 981 // deadlock between ChunkDemuxer and Pipeline. See http://crbug.com/334325 for |
| 982 // ideas on removing locking from ChunkDemuxer. |
| 983 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
| 984 gfx::Size initial_natural_size = |
| 985 stream->video_decoder_config().natural_size(); |
| 986 { |
| 987 base::AutoLock l(lock_); |
| 988 initial_natural_size_ = initial_natural_size; |
| 989 } |
| 990 |
962 video_renderer_ = filter_collection_->GetVideoRenderer(); | 991 video_renderer_ = filter_collection_->GetVideoRenderer(); |
963 video_renderer_->Initialize( | 992 video_renderer_->Initialize( |
964 demuxer_->GetStream(DemuxerStream::VIDEO), | 993 stream, |
965 done_cb, | 994 done_cb, |
966 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), | 995 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
967 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), | 996 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), |
968 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), | 997 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), |
969 base::Bind(&Pipeline::SetError, base::Unretained(this)), | 998 base::Bind(&Pipeline::SetError, base::Unretained(this)), |
970 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), | 999 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), |
971 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); | 1000 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); |
972 } | 1001 } |
973 | 1002 |
974 void Pipeline::OnAudioUnderflow() { | 1003 void Pipeline::OnAudioUnderflow() { |
(...skipping 13 matching lines...) Expand all Loading... |
988 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1017 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
989 lock_.AssertAcquired(); | 1018 lock_.AssertAcquired(); |
990 if (!waiting_for_clock_update_) | 1019 if (!waiting_for_clock_update_) |
991 return; | 1020 return; |
992 | 1021 |
993 waiting_for_clock_update_ = false; | 1022 waiting_for_clock_update_ = false; |
994 clock_->Play(); | 1023 clock_->Play(); |
995 } | 1024 } |
996 | 1025 |
997 } // namespace media | 1026 } // namespace media |
OLD | NEW |