OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chromecast/media/cma/pipeline/media_pipeline_impl.h" | 5 #include "chromecast/media/cma/pipeline/media_pipeline_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
13 #include "base/thread_task_runner_handle.h" | 13 #include "base/thread_task_runner_handle.h" |
14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
15 #include "chromecast/media/cdm/browser_cdm_cast.h" | 15 #include "chromecast/media/cdm/browser_cdm_cast.h" |
16 #include "chromecast/media/cma/base/buffering_controller.h" | 16 #include "chromecast/media/cma/base/buffering_controller.h" |
17 #include "chromecast/media/cma/base/buffering_state.h" | 17 #include "chromecast/media/cma/base/buffering_state.h" |
18 #include "chromecast/media/cma/base/cma_logging.h" | 18 #include "chromecast/media/cma/base/cma_logging.h" |
19 #include "chromecast/media/cma/base/coded_frame_provider.h" | 19 #include "chromecast/media/cma/base/coded_frame_provider.h" |
20 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h" | 20 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h" |
21 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h" | 21 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h" |
22 #include "chromecast/public/media/media_clock_device.h" | |
23 #include "chromecast/public/media/media_pipeline_backend.h" | 22 #include "chromecast/public/media/media_pipeline_backend.h" |
24 #include "media/base/timestamp_constants.h" | 23 #include "media/base/timestamp_constants.h" |
25 | 24 |
26 namespace chromecast { | 25 namespace chromecast { |
27 namespace media { | 26 namespace media { |
28 | 27 |
29 namespace { | 28 namespace { |
30 | 29 |
31 // Buffering parameters when load_type is kLoadTypeUrl. | 30 // Buffering parameters when load_type is kLoadTypeUrl. |
32 const base::TimeDelta kLowBufferThresholdURL( | 31 const base::TimeDelta kLowBufferThresholdURL( |
(...skipping 11 matching lines...) Expand all Loading... |
44 const base::TimeDelta kTimeUpdateInterval( | 43 const base::TimeDelta kTimeUpdateInterval( |
45 base::TimeDelta::FromMilliseconds(250)); | 44 base::TimeDelta::FromMilliseconds(250)); |
46 | 45 |
47 // Interval between two updates of the statistics is equal to: | 46 // Interval between two updates of the statistics is equal to: |
48 // kTimeUpdateInterval * kStatisticsUpdatePeriod. | 47 // kTimeUpdateInterval * kStatisticsUpdatePeriod. |
49 const int kStatisticsUpdatePeriod = 4; | 48 const int kStatisticsUpdatePeriod = 4; |
50 | 49 |
51 } // namespace | 50 } // namespace |
52 | 51 |
53 MediaPipelineImpl::MediaPipelineImpl() | 52 MediaPipelineImpl::MediaPipelineImpl() |
54 : has_audio_(false), | 53 : audio_decoder_(nullptr), |
| 54 video_decoder_(nullptr), |
| 55 backend_initialized_(false), |
| 56 has_audio_(false), |
55 has_video_(false), | 57 has_video_(false), |
56 target_playback_rate_(0.0), | 58 paused_(false), |
| 59 target_playback_rate_(1.0f), |
57 enable_time_update_(false), | 60 enable_time_update_(false), |
58 pending_time_update_task_(false), | 61 pending_time_update_task_(false), |
59 statistics_rolling_counter_(0), | 62 statistics_rolling_counter_(0), |
60 weak_factory_(this) { | 63 weak_factory_(this) { |
61 CMALOG(kLogControl) << __FUNCTION__; | 64 CMALOG(kLogControl) << __FUNCTION__; |
62 weak_this_ = weak_factory_.GetWeakPtr(); | 65 weak_this_ = weak_factory_.GetWeakPtr(); |
63 thread_checker_.DetachFromThread(); | 66 thread_checker_.DetachFromThread(); |
64 } | 67 } |
65 | 68 |
66 MediaPipelineImpl::~MediaPipelineImpl() { | 69 MediaPipelineImpl::~MediaPipelineImpl() { |
(...skipping 10 matching lines...) Expand all Loading... |
77 if (!client_.pipeline_backend_destroyed_cb.is_null()) | 80 if (!client_.pipeline_backend_destroyed_cb.is_null()) |
78 client_.pipeline_backend_destroyed_cb.Run(); | 81 client_.pipeline_backend_destroyed_cb.Run(); |
79 } | 82 } |
80 | 83 |
81 void MediaPipelineImpl::Initialize( | 84 void MediaPipelineImpl::Initialize( |
82 LoadType load_type, | 85 LoadType load_type, |
83 scoped_ptr<MediaPipelineBackend> media_pipeline_backend) { | 86 scoped_ptr<MediaPipelineBackend> media_pipeline_backend) { |
84 CMALOG(kLogControl) << __FUNCTION__; | 87 CMALOG(kLogControl) << __FUNCTION__; |
85 DCHECK(thread_checker_.CalledOnValidThread()); | 88 DCHECK(thread_checker_.CalledOnValidThread()); |
86 media_pipeline_backend_.reset(media_pipeline_backend.release()); | 89 media_pipeline_backend_.reset(media_pipeline_backend.release()); |
87 clock_device_ = media_pipeline_backend_->GetClock(); | |
88 if (!client_.pipeline_backend_created_cb.is_null()) | 90 if (!client_.pipeline_backend_created_cb.is_null()) |
89 client_.pipeline_backend_created_cb.Run(); | 91 client_.pipeline_backend_created_cb.Run(); |
90 | 92 |
91 if (load_type == kLoadTypeURL || load_type == kLoadTypeMediaSource) { | 93 if (load_type == kLoadTypeURL || load_type == kLoadTypeMediaSource) { |
92 base::TimeDelta low_threshold(kLowBufferThresholdURL); | 94 base::TimeDelta low_threshold(kLowBufferThresholdURL); |
93 base::TimeDelta high_threshold(kHighBufferThresholdURL); | 95 base::TimeDelta high_threshold(kHighBufferThresholdURL); |
94 if (load_type == kLoadTypeMediaSource) { | 96 if (load_type == kLoadTypeMediaSource) { |
95 low_threshold = kLowBufferThresholdMediaSource; | 97 low_threshold = kLowBufferThresholdMediaSource; |
96 high_threshold = kHighBufferThresholdMediaSource; | 98 high_threshold = kHighBufferThresholdMediaSource; |
97 } | 99 } |
98 scoped_refptr<BufferingConfig> buffering_config( | 100 scoped_refptr<BufferingConfig> buffering_config( |
99 new BufferingConfig(low_threshold, high_threshold)); | 101 new BufferingConfig(low_threshold, high_threshold)); |
100 buffering_controller_.reset(new BufferingController( | 102 buffering_controller_.reset(new BufferingController( |
101 buffering_config, | 103 buffering_config, |
102 base::Bind(&MediaPipelineImpl::OnBufferingNotification, weak_this_))); | 104 base::Bind(&MediaPipelineImpl::OnBufferingNotification, weak_this_))); |
103 } | 105 } |
104 | |
105 audio_pipeline_.reset( | |
106 new AudioPipelineImpl(media_pipeline_backend_->GetAudio())); | |
107 | |
108 video_pipeline_.reset( | |
109 new VideoPipelineImpl(media_pipeline_backend_->GetVideo())); | |
110 } | 106 } |
111 | 107 |
112 void MediaPipelineImpl::SetClient(const MediaPipelineClient& client) { | 108 void MediaPipelineImpl::SetClient(const MediaPipelineClient& client) { |
113 DCHECK(thread_checker_.CalledOnValidThread()); | 109 DCHECK(thread_checker_.CalledOnValidThread()); |
114 DCHECK(!client.error_cb.is_null()); | 110 DCHECK(!client.error_cb.is_null()); |
115 DCHECK(!client.time_update_cb.is_null()); | 111 DCHECK(!client.time_update_cb.is_null()); |
116 DCHECK(!client.buffering_state_cb.is_null()); | 112 DCHECK(!client.buffering_state_cb.is_null()); |
117 DCHECK(!client.pipeline_backend_created_cb.is_null()); | 113 DCHECK(!client.pipeline_backend_created_cb.is_null()); |
118 DCHECK(!client.pipeline_backend_destroyed_cb.is_null()); | 114 DCHECK(!client.pipeline_backend_destroyed_cb.is_null()); |
119 client_ = client; | 115 client_ = client; |
120 } | 116 } |
121 | 117 |
122 void MediaPipelineImpl::SetCdm(int cdm_id) { | 118 void MediaPipelineImpl::SetCdm(int cdm_id) { |
123 CMALOG(kLogControl) << __FUNCTION__ << " cdm_id=" << cdm_id; | 119 CMALOG(kLogControl) << __FUNCTION__ << " cdm_id=" << cdm_id; |
124 DCHECK(thread_checker_.CalledOnValidThread()); | 120 DCHECK(thread_checker_.CalledOnValidThread()); |
125 NOTIMPLEMENTED(); | 121 NOTIMPLEMENTED(); |
126 // TODO(gunsch): SetCdm(int) is not implemented. | 122 // TODO(gunsch): SetCdm(int) is not implemented. |
127 // One possibility would be a GetCdmByIdCB that's passed in. | 123 // One possibility would be a GetCdmByIdCB that's passed in. |
128 } | 124 } |
129 | 125 |
| 126 void MediaPipelineImpl::OnVideoResolutionChanged( |
| 127 MediaPipelineBackend::VideoDecoder* decoder, |
| 128 const Size& size) { |
| 129 DCHECK(decoder == video_decoder_); |
| 130 video_pipeline_->OnNaturalSizeChanged(size); |
| 131 } |
| 132 |
| 133 void MediaPipelineImpl::OnPushBufferComplete( |
| 134 MediaPipelineBackend::Decoder* decoder, |
| 135 MediaPipelineBackend::BufferStatus status) { |
| 136 if (decoder == audio_decoder_) |
| 137 audio_pipeline_->OnBufferPushed(status); |
| 138 else if (decoder == video_decoder_) |
| 139 video_pipeline_->OnBufferPushed(status); |
| 140 } |
| 141 |
| 142 void MediaPipelineImpl::OnEndOfStream(MediaPipelineBackend::Decoder* decoder) { |
| 143 if (decoder == audio_decoder_) |
| 144 audio_pipeline_->OnEndOfStream(); |
| 145 else if (decoder == video_decoder_) |
| 146 video_pipeline_->OnEndOfStream(); |
| 147 } |
| 148 |
| 149 void MediaPipelineImpl::OnDecoderError(MediaPipelineBackend::Decoder* decoder) { |
| 150 if (decoder == audio_decoder_) |
| 151 audio_pipeline_->OnError(); |
| 152 else if (decoder == video_decoder_) |
| 153 video_pipeline_->OnError(); |
| 154 } |
| 155 |
130 void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) { | 156 void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) { |
131 CMALOG(kLogControl) << __FUNCTION__; | 157 CMALOG(kLogControl) << __FUNCTION__; |
132 DCHECK(thread_checker_.CalledOnValidThread()); | 158 DCHECK(thread_checker_.CalledOnValidThread()); |
133 audio_pipeline_->SetCdm(cdm); | 159 audio_pipeline_->SetCdm(cdm); |
134 video_pipeline_->SetCdm(cdm); | 160 video_pipeline_->SetCdm(cdm); |
135 } | 161 } |
136 | 162 |
137 AudioPipeline* MediaPipelineImpl::GetAudioPipeline() const { | |
138 return audio_pipeline_.get(); | |
139 } | |
140 | |
141 VideoPipeline* MediaPipelineImpl::GetVideoPipeline() const { | |
142 return video_pipeline_.get(); | |
143 } | |
144 | |
145 void MediaPipelineImpl::InitializeAudio( | 163 void MediaPipelineImpl::InitializeAudio( |
146 const ::media::AudioDecoderConfig& config, | 164 const ::media::AudioDecoderConfig& config, |
| 165 const AvPipelineClient& client, |
147 scoped_ptr<CodedFrameProvider> frame_provider, | 166 scoped_ptr<CodedFrameProvider> frame_provider, |
148 const ::media::PipelineStatusCB& status_cb) { | 167 const ::media::PipelineStatusCB& status_cb) { |
149 DCHECK(thread_checker_.CalledOnValidThread()); | 168 DCHECK(thread_checker_.CalledOnValidThread()); |
150 DCHECK(!has_audio_); | 169 DCHECK(!has_audio_); |
151 if (clock_device_->GetState() == MediaClockDevice::kStateUninitialized && | 170 |
152 !clock_device_->SetState(MediaClockDevice::kStateIdle)) { | 171 has_audio_ = true; |
153 status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED); | 172 |
| 173 audio_decoder_ = media_pipeline_backend_->CreateAudioDecoder(); |
| 174 if (!audio_decoder_) { |
| 175 status_cb.Run(::media::PIPELINE_ERROR_ABORT); |
154 return; | 176 return; |
155 } | 177 } |
156 has_audio_ = true; | 178 audio_pipeline_.reset(new AudioPipelineImpl(audio_decoder_, client)); |
157 audio_pipeline_->Initialize(config, frame_provider.Pass(), status_cb); | 179 audio_pipeline_->Initialize(config, frame_provider.Pass(), status_cb); |
158 } | 180 } |
159 | 181 |
160 void MediaPipelineImpl::InitializeVideo( | 182 void MediaPipelineImpl::InitializeVideo( |
161 const std::vector<::media::VideoDecoderConfig>& configs, | 183 const std::vector< ::media::VideoDecoderConfig>& configs, |
| 184 const VideoPipelineClient& client, |
162 scoped_ptr<CodedFrameProvider> frame_provider, | 185 scoped_ptr<CodedFrameProvider> frame_provider, |
163 const ::media::PipelineStatusCB& status_cb) { | 186 const ::media::PipelineStatusCB& status_cb) { |
164 DCHECK(thread_checker_.CalledOnValidThread()); | 187 DCHECK(thread_checker_.CalledOnValidThread()); |
165 DCHECK(!has_video_); | 188 DCHECK(!has_video_); |
166 if (clock_device_->GetState() == MediaClockDevice::kStateUninitialized && | 189 |
167 !clock_device_->SetState(MediaClockDevice::kStateIdle)) { | 190 has_video_ = true; |
168 status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED); | 191 video_decoder_ = media_pipeline_backend_->CreateVideoDecoder(); |
| 192 if (!video_decoder_) { |
| 193 status_cb.Run(::media::PIPELINE_ERROR_ABORT); |
169 return; | 194 return; |
170 } | 195 } |
171 has_video_ = true; | 196 video_pipeline_.reset(new VideoPipelineImpl(video_decoder_, client)); |
| 197 |
172 video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb); | 198 video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb); |
173 } | 199 } |
174 | 200 |
175 void MediaPipelineImpl::StartPlayingFrom(base::TimeDelta time) { | 201 void MediaPipelineImpl::StartPlayingFrom(base::TimeDelta time) { |
176 CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds(); | 202 CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds(); |
177 DCHECK(thread_checker_.CalledOnValidThread()); | 203 DCHECK(thread_checker_.CalledOnValidThread()); |
178 DCHECK(has_audio_ || has_video_); | 204 DCHECK(has_audio_ || has_video_); |
179 DCHECK(!pending_flush_callbacks_); | 205 DCHECK(!pending_flush_callbacks_); |
| 206 // When starting, we always enter the "playing" state (not paused). |
| 207 paused_ = false; |
180 | 208 |
181 // Reset the start of the timeline. | 209 // Lazy initialise |
182 DCHECK_EQ(clock_device_->GetState(), MediaClockDevice::kStateIdle); | 210 if (!backend_initialized_) { |
183 clock_device_->ResetTimeline(time.InMicroseconds()); | 211 backend_initialized_ = media_pipeline_backend_->Initialize(this); |
| 212 if (!backend_initialized_) { |
| 213 OnError(::media::PIPELINE_ERROR_ABORT); |
| 214 return; |
| 215 } |
| 216 } |
184 | 217 |
185 // Start the clock. If the playback rate is 0, then the clock is started | 218 // Start the backend. |
186 // but does not increase. | 219 if (!media_pipeline_backend_->Start(time.InMicroseconds())) { |
187 if (!clock_device_->SetState(MediaClockDevice::kStateRunning)) { | |
188 OnError(::media::PIPELINE_ERROR_ABORT); | 220 OnError(::media::PIPELINE_ERROR_ABORT); |
189 return; | 221 return; |
190 } | 222 } |
191 | 223 |
192 // Enable time updates. | 224 // Enable time updates. |
193 enable_time_update_ = true; | 225 enable_time_update_ = true; |
194 statistics_rolling_counter_ = 0; | 226 statistics_rolling_counter_ = 0; |
195 if (!pending_time_update_task_) { | 227 if (!pending_time_update_task_) { |
196 pending_time_update_task_ = true; | 228 pending_time_update_task_ = true; |
197 base::ThreadTaskRunnerHandle::Get()->PostTask( | 229 base::ThreadTaskRunnerHandle::Get()->PostTask( |
(...skipping 19 matching lines...) Expand all Loading... |
217 return; | 249 return; |
218 } | 250 } |
219 } | 251 } |
220 } | 252 } |
221 | 253 |
222 void MediaPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) { | 254 void MediaPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) { |
223 CMALOG(kLogControl) << __FUNCTION__; | 255 CMALOG(kLogControl) << __FUNCTION__; |
224 DCHECK(thread_checker_.CalledOnValidThread()); | 256 DCHECK(thread_checker_.CalledOnValidThread()); |
225 DCHECK(has_audio_ || has_video_); | 257 DCHECK(has_audio_ || has_video_); |
226 DCHECK(!pending_flush_callbacks_); | 258 DCHECK(!pending_flush_callbacks_); |
227 DCHECK(clock_device_->GetState() == MediaClockDevice::kStateUninitialized || | |
228 clock_device_->GetState() == MediaClockDevice::kStateRunning); | |
229 | 259 |
230 // No need to update media time anymore. | 260 // No need to update media time anymore. |
231 enable_time_update_ = false; | 261 enable_time_update_ = false; |
232 | 262 |
233 buffering_controller_->Reset(); | 263 buffering_controller_->Reset(); |
234 | 264 |
235 // The clock should return to idle. | 265 // Stop the backend |
236 if (!clock_device_->SetState(MediaClockDevice::kStateIdle)) { | 266 if (!media_pipeline_backend_->Stop()) { |
237 status_cb.Run(::media::PIPELINE_ERROR_ABORT); | 267 status_cb.Run(::media::PIPELINE_ERROR_ABORT); |
238 return; | 268 return; |
239 } | 269 } |
240 | 270 |
241 // Flush both the audio and video pipeline. | 271 // Flush both the audio and video pipeline. |
242 ::media::SerialRunner::Queue bound_fns; | 272 ::media::SerialRunner::Queue bound_fns; |
243 if (has_audio_) { | 273 if (has_audio_) { |
244 bound_fns.Push(base::Bind( | 274 bound_fns.Push(base::Bind( |
245 &AudioPipelineImpl::Flush, | 275 &AudioPipelineImpl::Flush, |
246 base::Unretained(audio_pipeline_.get()))); | 276 base::Unretained(audio_pipeline_.get()))); |
(...skipping 15 matching lines...) Expand all Loading... |
262 DCHECK(has_audio_ || has_video_); | 292 DCHECK(has_audio_ || has_video_); |
263 | 293 |
264 // Cancel pending flush callbacks since we are about to stop/shutdown | 294 // Cancel pending flush callbacks since we are about to stop/shutdown |
265 // audio/video pipelines. This will ensure A/V Flush won't happen in | 295 // audio/video pipelines. This will ensure A/V Flush won't happen in |
266 // stopped state. | 296 // stopped state. |
267 pending_flush_callbacks_.reset(); | 297 pending_flush_callbacks_.reset(); |
268 | 298 |
269 // No need to update media time anymore. | 299 // No need to update media time anymore. |
270 enable_time_update_ = false; | 300 enable_time_update_ = false; |
271 | 301 |
272 // Release hardware resources on Stop. | |
273 // Note: Stop can be called from any state. | |
274 if (clock_device_->GetState() == MediaClockDevice::kStateRunning) | |
275 clock_device_->SetState(MediaClockDevice::kStateIdle); | |
276 if (clock_device_->GetState() == MediaClockDevice::kStateIdle) | |
277 clock_device_->SetState(MediaClockDevice::kStateUninitialized); | |
278 | |
279 // Stop both the audio and video pipeline. | 302 // Stop both the audio and video pipeline. |
280 if (has_audio_) | 303 if (has_audio_) |
281 audio_pipeline_->Stop(); | 304 audio_pipeline_->Stop(); |
282 if (has_video_) | 305 if (has_video_) |
283 video_pipeline_->Stop(); | 306 video_pipeline_->Stop(); |
| 307 |
| 308 // Release hardware resources on Stop. |
| 309 audio_pipeline_ = nullptr; |
| 310 video_pipeline_ = nullptr; |
| 311 media_pipeline_backend_.reset(); |
284 } | 312 } |
285 | 313 |
286 void MediaPipelineImpl::SetPlaybackRate(double rate) { | 314 void MediaPipelineImpl::SetPlaybackRate(double rate) { |
287 CMALOG(kLogControl) << __FUNCTION__ << " rate=" << rate; | 315 CMALOG(kLogControl) << __FUNCTION__ << " rate=" << rate; |
288 DCHECK(thread_checker_.CalledOnValidThread()); | 316 DCHECK(thread_checker_.CalledOnValidThread()); |
| 317 if (!buffering_controller_ || !buffering_controller_->IsBuffering()) { |
| 318 if (paused_ && rate != 0.0f) { |
| 319 if (rate != target_playback_rate_) |
| 320 media_pipeline_backend_->SetPlaybackRate(rate); |
| 321 paused_ = false; |
| 322 media_pipeline_backend_->Resume(); |
| 323 } else if (!paused_ && rate == 0.0f) { |
| 324 paused_ = true; |
| 325 media_pipeline_backend_->Pause(); |
| 326 } else { |
| 327 media_pipeline_backend_->SetPlaybackRate(rate); |
| 328 } |
| 329 } |
289 target_playback_rate_ = rate; | 330 target_playback_rate_ = rate; |
290 if (!buffering_controller_ || !buffering_controller_->IsBuffering()) | |
291 media_pipeline_backend_->GetClock()->SetRate(rate); | |
292 } | 331 } |
293 | 332 |
294 AudioPipelineImpl* MediaPipelineImpl::GetAudioPipelineImpl() const { | 333 void MediaPipelineImpl::SetVolume(float volume) { |
295 return audio_pipeline_.get(); | 334 CMALOG(kLogControl) << __FUNCTION__ << " vol=" << volume; |
296 } | 335 DCHECK(thread_checker_.CalledOnValidThread()); |
297 | 336 DCHECK(audio_pipeline_); |
298 VideoPipelineImpl* MediaPipelineImpl::GetVideoPipelineImpl() const { | 337 audio_pipeline_->SetVolume(volume); |
299 return video_pipeline_.get(); | |
300 } | 338 } |
301 | 339 |
302 void MediaPipelineImpl::StateTransition( | 340 void MediaPipelineImpl::StateTransition( |
303 const ::media::PipelineStatusCB& status_cb, | 341 const ::media::PipelineStatusCB& status_cb, |
304 ::media::PipelineStatus status) { | 342 ::media::PipelineStatus status) { |
305 pending_flush_callbacks_.reset(); | 343 pending_flush_callbacks_.reset(); |
306 status_cb.Run(status); | 344 status_cb.Run(status); |
307 } | 345 } |
308 | 346 |
309 void MediaPipelineImpl::OnBufferingNotification(bool is_buffering) { | 347 void MediaPipelineImpl::OnBufferingNotification(bool is_buffering) { |
310 CMALOG(kLogControl) << __FUNCTION__ << " is_buffering=" << is_buffering; | 348 CMALOG(kLogControl) << __FUNCTION__ << " is_buffering=" << is_buffering; |
311 DCHECK(thread_checker_.CalledOnValidThread()); | 349 DCHECK(thread_checker_.CalledOnValidThread()); |
312 DCHECK(buffering_controller_); | 350 DCHECK(buffering_controller_); |
313 | 351 |
314 if (!client_.buffering_state_cb.is_null()) { | 352 if (!client_.buffering_state_cb.is_null()) { |
315 ::media::BufferingState buffering_state = is_buffering ? | 353 ::media::BufferingState buffering_state = is_buffering ? |
316 ::media::BUFFERING_HAVE_NOTHING : ::media::BUFFERING_HAVE_ENOUGH; | 354 ::media::BUFFERING_HAVE_NOTHING : ::media::BUFFERING_HAVE_ENOUGH; |
317 client_.buffering_state_cb.Run(buffering_state); | 355 client_.buffering_state_cb.Run(buffering_state); |
318 } | 356 } |
319 | 357 |
320 if (media_pipeline_backend_->GetClock()->GetState() == | |
321 MediaClockDevice::kStateUninitialized) { | |
322 return; | |
323 } | |
324 | |
325 if (is_buffering) { | 358 if (is_buffering) { |
326 // Do not consume data in a rebuffering phase. | 359 // Do not consume data in a rebuffering phase. |
327 media_pipeline_backend_->GetClock()->SetRate(0.0); | 360 if (!paused_) { |
328 } else { | 361 paused_ = true; |
329 media_pipeline_backend_->GetClock()->SetRate(target_playback_rate_); | 362 media_pipeline_backend_->Pause(); |
| 363 } |
| 364 } else if (paused_) { |
| 365 paused_ = false; |
| 366 media_pipeline_backend_->Resume(); |
330 } | 367 } |
331 } | 368 } |
332 | 369 |
333 void MediaPipelineImpl::UpdateMediaTime() { | 370 void MediaPipelineImpl::UpdateMediaTime() { |
334 pending_time_update_task_ = false; | 371 pending_time_update_task_ = false; |
335 if (!enable_time_update_) | 372 if (!enable_time_update_) |
336 return; | 373 return; |
337 | 374 |
338 if (statistics_rolling_counter_ == 0) { | 375 if (statistics_rolling_counter_ == 0) { |
339 audio_pipeline_->UpdateStatistics(); | 376 if (audio_pipeline_) |
340 video_pipeline_->UpdateStatistics(); | 377 audio_pipeline_->UpdateStatistics(); |
| 378 if (video_pipeline_) |
| 379 video_pipeline_->UpdateStatistics(); |
341 } | 380 } |
342 statistics_rolling_counter_ = | 381 statistics_rolling_counter_ = |
343 (statistics_rolling_counter_ + 1) % kStatisticsUpdatePeriod; | 382 (statistics_rolling_counter_ + 1) % kStatisticsUpdatePeriod; |
344 | 383 |
345 base::TimeDelta media_time = | 384 base::TimeDelta media_time = base::TimeDelta::FromMicroseconds( |
346 base::TimeDelta::FromMicroseconds(clock_device_->GetTimeMicroseconds()); | 385 media_pipeline_backend_->GetCurrentPts()); |
347 if (media_time == ::media::kNoTimestamp()) { | 386 if (media_time == ::media::kNoTimestamp()) { |
348 pending_time_update_task_ = true; | 387 pending_time_update_task_ = true; |
349 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 388 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
350 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_), | 389 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_), |
351 kTimeUpdateInterval); | 390 kTimeUpdateInterval); |
352 return; | 391 return; |
353 } | 392 } |
354 base::TimeTicks stc = base::TimeTicks::Now(); | 393 base::TimeTicks stc = base::TimeTicks::Now(); |
355 | 394 |
356 base::TimeDelta max_rendering_time = media_time; | 395 base::TimeDelta max_rendering_time = media_time; |
(...skipping 25 matching lines...) Expand all Loading... |
382 | 421 |
383 void MediaPipelineImpl::OnError(::media::PipelineStatus error) { | 422 void MediaPipelineImpl::OnError(::media::PipelineStatus error) { |
384 DCHECK(thread_checker_.CalledOnValidThread()); | 423 DCHECK(thread_checker_.CalledOnValidThread()); |
385 DCHECK_NE(error, ::media::PIPELINE_OK) << "PIPELINE_OK is not an error!"; | 424 DCHECK_NE(error, ::media::PIPELINE_OK) << "PIPELINE_OK is not an error!"; |
386 if (!client_.error_cb.is_null()) | 425 if (!client_.error_cb.is_null()) |
387 client_.error_cb.Run(error); | 426 client_.error_cb.Run(error); |
388 } | 427 } |
389 | 428 |
390 } // namespace media | 429 } // namespace media |
391 } // namespace chromecast | 430 } // namespace chromecast |
OLD | NEW |