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

Side by Side Diff: media/base/pipeline.cc

Issue 418143005: media: Introduce Renderer interface and RendererImpl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: minor cleanup Created 6 years, 4 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 | Annotate | Revision Log
OLDNEW
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"
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/single_thread_task_runner.h" 15 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
19 #include "base/synchronization/condition_variable.h" 19 #include "base/synchronization/condition_variable.h"
20 #include "media/base/audio_decoder.h"
21 #include "media/base/audio_renderer.h"
22 #include "media/base/filter_collection.h" 20 #include "media/base/filter_collection.h"
23 #include "media/base/media_log.h" 21 #include "media/base/media_log.h"
22 #include "media/base/renderer.h"
24 #include "media/base/text_renderer.h" 23 #include "media/base/text_renderer.h"
25 #include "media/base/text_track_config.h" 24 #include "media/base/text_track_config.h"
26 #include "media/base/time_delta_interpolator.h"
27 #include "media/base/time_source.h"
28 #include "media/base/video_decoder.h"
29 #include "media/base/video_decoder_config.h" 25 #include "media/base/video_decoder_config.h"
30 #include "media/base/video_renderer.h"
31 26
32 using base::TimeDelta; 27 using base::TimeDelta;
33 28
34 namespace media { 29 namespace media {
35 30
36 Pipeline::Pipeline( 31 Pipeline::Pipeline(
37 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 32 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
38 MediaLog* media_log) 33 MediaLog* media_log)
39 : task_runner_(task_runner), 34 : task_runner_(task_runner),
40 media_log_(media_log), 35 media_log_(media_log),
41 running_(false), 36 running_(false),
42 did_loading_progress_(false), 37 did_loading_progress_(false),
43 volume_(1.0f), 38 volume_(1.0f),
44 playback_rate_(0.0f), 39 playback_rate_(0.0f),
45 interpolator_(new TimeDeltaInterpolator(&default_tick_clock_)),
46 interpolation_state_(INTERPOLATION_STOPPED),
47 status_(PIPELINE_OK), 40 status_(PIPELINE_OK),
41 is_initialized_(false),
48 state_(kCreated), 42 state_(kCreated),
49 audio_ended_(false), 43 renderer_ended_(false),
50 video_ended_(false), 44 text_renderer_ended_(false),
51 text_ended_(false),
52 audio_buffering_state_(BUFFERING_HAVE_NOTHING),
53 video_buffering_state_(BUFFERING_HAVE_NOTHING),
54 demuxer_(NULL), 45 demuxer_(NULL),
55 time_source_(NULL),
56 underflow_disabled_for_testing_(false),
57 weak_factory_(this) { 46 weak_factory_(this) {
58 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 47 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
59 media_log_->AddEvent( 48 media_log_->AddEvent(
60 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); 49 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED));
61 interpolator_->SetBounds(base::TimeDelta(), base::TimeDelta());
62 } 50 }
63 51
64 Pipeline::~Pipeline() { 52 Pipeline::~Pipeline() {
65 DCHECK(thread_checker_.CalledOnValidThread()) 53 DCHECK(thread_checker_.CalledOnValidThread())
66 << "Pipeline must be destroyed on same thread that created it"; 54 << "Pipeline must be destroyed on same thread that created it";
67 DCHECK(!running_) << "Stop() must complete before destroying object"; 55 DCHECK(!running_) << "Stop() must complete before destroying object";
68 DCHECK(stop_cb_.is_null()); 56 DCHECK(stop_cb_.is_null());
69 DCHECK(seek_cb_.is_null()); 57 DCHECK(seek_cb_.is_null());
70 58
71 media_log_->AddEvent( 59 media_log_->AddEvent(
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 if (running_) { 147 if (running_) {
160 task_runner_->PostTask( 148 task_runner_->PostTask(
161 FROM_HERE, 149 FROM_HERE,
162 base::Bind( 150 base::Bind(
163 &Pipeline::VolumeChangedTask, weak_factory_.GetWeakPtr(), volume)); 151 &Pipeline::VolumeChangedTask, weak_factory_.GetWeakPtr(), volume));
164 } 152 }
165 } 153 }
166 154
167 TimeDelta Pipeline::GetMediaTime() const { 155 TimeDelta Pipeline::GetMediaTime() const {
168 base::AutoLock auto_lock(lock_); 156 base::AutoLock auto_lock(lock_);
169 return std::min(interpolator_->GetInterpolatedTime(), duration_); 157 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_)
158 : TimeDelta();
170 } 159 }
171 160
172 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { 161 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const {
173 base::AutoLock auto_lock(lock_); 162 base::AutoLock auto_lock(lock_);
174 return buffered_time_ranges_; 163 return buffered_time_ranges_;
175 } 164 }
176 165
177 TimeDelta Pipeline::GetMediaDuration() const { 166 TimeDelta Pipeline::GetMediaDuration() const {
178 base::AutoLock auto_lock(lock_); 167 base::AutoLock auto_lock(lock_);
179 return duration_; 168 return duration_;
180 } 169 }
181 170
182 bool Pipeline::DidLoadingProgress() { 171 bool Pipeline::DidLoadingProgress() {
183 base::AutoLock auto_lock(lock_); 172 base::AutoLock auto_lock(lock_);
184 bool ret = did_loading_progress_; 173 bool ret = did_loading_progress_;
185 did_loading_progress_ = false; 174 did_loading_progress_ = false;
186 return ret; 175 return ret;
187 } 176 }
188 177
189 PipelineStatistics Pipeline::GetStatistics() const { 178 PipelineStatistics Pipeline::GetStatistics() const {
190 base::AutoLock auto_lock(lock_); 179 base::AutoLock auto_lock(lock_);
191 return statistics_; 180 return statistics_;
192 } 181 }
193 182
194 void Pipeline::SetTimeDeltaInterpolatorForTesting(
195 TimeDeltaInterpolator* interpolator) {
196 interpolator_.reset(interpolator);
197 }
198
199 void Pipeline::SetErrorForTesting(PipelineStatus status) { 183 void Pipeline::SetErrorForTesting(PipelineStatus status) {
200 OnError(status); 184 OnError(status);
201 } 185 }
202 186
203 bool Pipeline::HasWeakPtrsForTesting() const { 187 bool Pipeline::HasWeakPtrsForTesting() const {
204 DCHECK(task_runner_->BelongsToCurrentThread()); 188 DCHECK(task_runner_->BelongsToCurrentThread());
205 return weak_factory_.HasWeakPtrs(); 189 return weak_factory_.HasWeakPtrs();
206 } 190 }
207 191
208 void Pipeline::SetState(State next_state) { 192 void Pipeline::SetState(State next_state) {
209 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); 193 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state);
210 194
211 state_ = next_state; 195 state_ = next_state;
212 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); 196 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state));
213 } 197 }
214 198
215 #define RETURN_STRING(state) case state: return #state; 199 #define RETURN_STRING(state) case state: return #state;
216 200
217 const char* Pipeline::GetStateString(State state) { 201 const char* Pipeline::GetStateString(State state) {
218 switch (state) { 202 switch (state) {
219 RETURN_STRING(kCreated); 203 RETURN_STRING(kCreated);
220 RETURN_STRING(kInitDemuxer); 204 RETURN_STRING(kInitDemuxer);
221 RETURN_STRING(kInitAudioRenderer); 205 RETURN_STRING(kInitRenderer);
222 RETURN_STRING(kInitVideoRenderer);
223 RETURN_STRING(kSeeking); 206 RETURN_STRING(kSeeking);
224 RETURN_STRING(kPlaying); 207 RETURN_STRING(kPlaying);
225 RETURN_STRING(kStopping); 208 RETURN_STRING(kStopping);
226 RETURN_STRING(kStopped); 209 RETURN_STRING(kStopped);
227 } 210 }
228 NOTREACHED(); 211 NOTREACHED();
229 return "INVALID"; 212 return "INVALID";
230 } 213 }
231 214
232 #undef RETURN_STRING 215 #undef RETURN_STRING
233 216
234 Pipeline::State Pipeline::GetNextState() const { 217 Pipeline::State Pipeline::GetNextState() const {
235 DCHECK(task_runner_->BelongsToCurrentThread()); 218 DCHECK(task_runner_->BelongsToCurrentThread());
236 DCHECK(stop_cb_.is_null()) 219 DCHECK(stop_cb_.is_null())
237 << "State transitions don't happen when stopping"; 220 << "State transitions don't happen when stopping";
238 DCHECK_EQ(status_, PIPELINE_OK) 221 DCHECK_EQ(status_, PIPELINE_OK)
239 << "State transitions don't happen when there's an error: " << status_; 222 << "State transitions don't happen when there's an error: " << status_;
240 223
241 switch (state_) { 224 switch (state_) {
242 case kCreated: 225 case kCreated:
243 return kInitDemuxer; 226 return kInitDemuxer;
244 227
245 case kInitDemuxer: 228 case kInitDemuxer:
246 if (demuxer_->GetStream(DemuxerStream::AUDIO)) 229 if (demuxer_->GetStream(DemuxerStream::AUDIO) ||
247 return kInitAudioRenderer; 230 demuxer_->GetStream(DemuxerStream::VIDEO)) {
248 if (demuxer_->GetStream(DemuxerStream::VIDEO)) 231 return kInitRenderer;
249 return kInitVideoRenderer; 232 }
250 return kPlaying; 233 return kPlaying;
251 234
252 case kInitAudioRenderer: 235 case kInitRenderer:
253 if (demuxer_->GetStream(DemuxerStream::VIDEO))
254 return kInitVideoRenderer;
255 return kPlaying;
256
257 case kInitVideoRenderer:
258 return kPlaying;
259
260 case kSeeking: 236 case kSeeking:
261 return kPlaying; 237 return kPlaying;
262 238
263 case kPlaying: 239 case kPlaying:
264 case kStopping: 240 case kStopping:
265 case kStopped: 241 case kStopped:
266 break; 242 break;
267 } 243 }
268 NOTREACHED() << "State has no transition: " << state_; 244 NOTREACHED() << "State has no transition: " << state_;
269 return state_; 245 return state_;
(...skipping 25 matching lines...) Expand all
295 void Pipeline::OnError(PipelineStatus error) { 271 void Pipeline::OnError(PipelineStatus error) {
296 DCHECK(task_runner_->BelongsToCurrentThread()); 272 DCHECK(task_runner_->BelongsToCurrentThread());
297 DCHECK(IsRunning()); 273 DCHECK(IsRunning());
298 DCHECK_NE(PIPELINE_OK, error); 274 DCHECK_NE(PIPELINE_OK, error);
299 VLOG(1) << "Media pipeline error: " << error; 275 VLOG(1) << "Media pipeline error: " << error;
300 276
301 task_runner_->PostTask(FROM_HERE, base::Bind( 277 task_runner_->PostTask(FROM_HERE, base::Bind(
302 &Pipeline::ErrorChangedTask, weak_factory_.GetWeakPtr(), error)); 278 &Pipeline::ErrorChangedTask, weak_factory_.GetWeakPtr(), error));
303 } 279 }
304 280
305 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) {
306 DCHECK(task_runner_->BelongsToCurrentThread());
307 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds());
308 base::AutoLock auto_lock(lock_);
309
310 if (interpolation_state_ == INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE &&
311 time < interpolator_->GetInterpolatedTime()) {
312 return;
313 }
314
315 if (state_ == kSeeking)
316 return;
317
318 interpolator_->SetBounds(time, max_time);
319 StartClockIfWaitingForTimeUpdate_Locked();
320 }
321
322 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) {
323 DCHECK(task_runner_->BelongsToCurrentThread());
324
325 if (audio_renderer_)
326 return;
327
328 if (state_ == kSeeking)
329 return;
330
331 base::AutoLock auto_lock(lock_);
332 DCHECK_NE(interpolation_state_, INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE);
333 interpolator_->SetUpperBound(max_time);
334 }
335
336 void Pipeline::SetDuration(TimeDelta duration) { 281 void Pipeline::SetDuration(TimeDelta duration) {
337 DCHECK(IsRunning()); 282 DCHECK(IsRunning());
338 media_log_->AddEvent( 283 media_log_->AddEvent(
339 media_log_->CreateTimeEvent( 284 media_log_->CreateTimeEvent(
340 MediaLogEvent::DURATION_SET, "duration", duration)); 285 MediaLogEvent::DURATION_SET, "duration", duration));
341 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); 286 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration);
342 287
343 base::AutoLock auto_lock(lock_); 288 base::AutoLock auto_lock(lock_);
344 duration_ = duration; 289 duration_ = duration;
345 if (!duration_change_cb_.is_null()) 290 if (!duration_change_cb_.is_null())
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 324
380 PipelineStatusCB done_cb = 325 PipelineStatusCB done_cb =
381 base::Bind(&Pipeline::OnStateTransition, weak_factory_.GetWeakPtr()); 326 base::Bind(&Pipeline::OnStateTransition, weak_factory_.GetWeakPtr());
382 327
383 // Switch states, performing any entrance actions for the new state as well. 328 // Switch states, performing any entrance actions for the new state as well.
384 SetState(GetNextState()); 329 SetState(GetNextState());
385 switch (state_) { 330 switch (state_) {
386 case kInitDemuxer: 331 case kInitDemuxer:
387 return InitializeDemuxer(done_cb); 332 return InitializeDemuxer(done_cb);
388 333
389 case kInitAudioRenderer: 334 case kInitRenderer:
390 return InitializeAudioRenderer(done_cb); 335 return InitializeRenderer(done_cb);
391
392 case kInitVideoRenderer:
393 return InitializeVideoRenderer(done_cb);
394 336
395 case kPlaying: 337 case kPlaying:
396 // Finish initial start sequence the first time we enter the playing 338 // Finish initial start sequence the first time we enter the playing
397 // state. 339 // state.
398 if (filter_collection_) { 340 if (!is_initialized_) {
399 filter_collection_.reset(); 341 if (!renderer_) {
400 if (!audio_renderer_ && !video_renderer_) {
401 ErrorChangedTask(PIPELINE_ERROR_COULD_NOT_RENDER); 342 ErrorChangedTask(PIPELINE_ERROR_COULD_NOT_RENDER);
402 return; 343 return;
403 } 344 }
404 345
405 if (audio_renderer_) 346 is_initialized_ = true;
406 time_source_ = audio_renderer_->GetTimeSource();
407 347
408 { 348 {
409 PipelineMetadata metadata; 349 PipelineMetadata metadata;
410 metadata.has_audio = audio_renderer_; 350 metadata.has_audio = renderer_->HasAudio();
411 metadata.has_video = video_renderer_; 351 metadata.has_video = renderer_->HasVideo();
412 metadata.timeline_offset = demuxer_->GetTimelineOffset(); 352 metadata.timeline_offset = demuxer_->GetTimelineOffset();
413 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 353 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
414 if (stream) { 354 if (stream) {
415 metadata.natural_size = 355 metadata.natural_size =
416 stream->video_decoder_config().natural_size(); 356 stream->video_decoder_config().natural_size();
417 metadata.video_rotation = stream->video_rotation(); 357 metadata.video_rotation = stream->video_rotation();
418 } 358 }
419 metadata_cb_.Run(metadata); 359 metadata_cb_.Run(metadata);
420 } 360 }
421 } 361 }
422 362
423 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 363 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
424 364
425 { 365 renderer_->StartPlayingFrom(start_timestamp_);
426 base::AutoLock auto_lock(lock_);
427 interpolator_->SetBounds(start_timestamp_, start_timestamp_);
428 }
429 366
430 if (time_source_)
431 time_source_->SetMediaTime(start_timestamp_);
432 if (audio_renderer_)
433 audio_renderer_->StartPlaying();
434 if (video_renderer_)
435 video_renderer_->StartPlaying();
436 if (text_renderer_) 367 if (text_renderer_)
437 text_renderer_->StartPlaying(); 368 text_renderer_->StartPlaying();
438 369
439 PlaybackRateChangedTask(GetPlaybackRate()); 370 PlaybackRateChangedTask(GetPlaybackRate());
440 VolumeChangedTask(GetVolume()); 371 VolumeChangedTask(GetVolume());
441 return; 372 return;
442 373
443 case kStopping: 374 case kStopping:
444 case kStopped: 375 case kStopped:
445 case kCreated: 376 case kCreated:
446 case kSeeking: 377 case kSeeking:
447 NOTREACHED() << "State has no transition: " << state_; 378 NOTREACHED() << "State has no transition: " << state_;
448 return; 379 return;
449 } 380 }
450 } 381 }
451 382
452 // Note that the usage of base::Unretained() with the audio/video renderers 383 // Note that the usage of base::Unretained() with the renderers is considered
453 // in the following DoXXX() functions is considered safe as they are owned by 384 // safe as they are owned by |pending_callbacks_| and share the same lifetime.
454 // |pending_callbacks_| and share the same lifetime.
455 // 385 //
456 // That being said, deleting the renderers while keeping |pending_callbacks_| 386 // That being said, deleting the renderers while keeping |pending_callbacks_|
457 // running on the media thread would result in crashes. 387 // running on the media thread would result in crashes.
458 388 void Pipeline::DoSeek(TimeDelta seek_timestamp,
459 #if DCHECK_IS_ON 389 const PipelineStatusCB& done_cb) {
460 static void VerifyBufferingStates(BufferingState* audio_buffering_state,
461 BufferingState* video_buffering_state) {
462 DCHECK_EQ(*audio_buffering_state, BUFFERING_HAVE_NOTHING);
463 DCHECK_EQ(*video_buffering_state, BUFFERING_HAVE_NOTHING);
464 }
465 #endif
466
467 void Pipeline::DoSeek(
468 base::TimeDelta seek_timestamp,
469 const PipelineStatusCB& done_cb) {
470 DCHECK(task_runner_->BelongsToCurrentThread()); 390 DCHECK(task_runner_->BelongsToCurrentThread());
471 DCHECK(!pending_callbacks_.get()); 391 DCHECK(!pending_callbacks_.get());
392 DCHECK_EQ(state_, kSeeking);
472 SerialRunner::Queue bound_fns; 393 SerialRunner::Queue bound_fns;
473 {
474 base::AutoLock auto_lock(lock_);
475 PauseClockAndStopTicking_Locked();
476 }
477 394
478 // Pause. 395 // Pause.
479 if (text_renderer_) { 396 if (text_renderer_) {
480 bound_fns.Push(base::Bind( 397 bound_fns.Push(base::Bind(
481 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); 398 &TextRenderer::Pause, base::Unretained(text_renderer_.get())));
482 } 399 }
483 400
484 // Flush. 401 // Flush.
485 if (audio_renderer_) { 402 DCHECK(renderer_);
486 bound_fns.Push(base::Bind( 403 bound_fns.Push(
487 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get()))); 404 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get())));
488 }
489
490 if (video_renderer_) {
491 bound_fns.Push(base::Bind(
492 &VideoRenderer::Flush, base::Unretained(video_renderer_.get())));
493 }
494
495 #if DCHECK_IS_ON
496 // Verify renderers reset their buffering states.
497 bound_fns.Push(base::Bind(&VerifyBufferingStates,
498 &audio_buffering_state_,
499 &video_buffering_state_));
500 #endif
501 405
502 if (text_renderer_) { 406 if (text_renderer_) {
503 bound_fns.Push(base::Bind( 407 bound_fns.Push(base::Bind(
504 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); 408 &TextRenderer::Flush, base::Unretained(text_renderer_.get())));
505 } 409 }
506 410
507 // Seek demuxer. 411 // Seek demuxer.
508 bound_fns.Push(base::Bind( 412 bound_fns.Push(base::Bind(
509 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); 413 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
510 414
511 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 415 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
512 } 416 }
513 417
514 void Pipeline::DoStop(const PipelineStatusCB& done_cb) { 418 void Pipeline::DoStop(const PipelineStatusCB& done_cb) {
515 DVLOG(2) << __FUNCTION__; 419 DVLOG(2) << __FUNCTION__;
516 DCHECK(task_runner_->BelongsToCurrentThread()); 420 DCHECK(task_runner_->BelongsToCurrentThread());
517 DCHECK(!pending_callbacks_.get()); 421 DCHECK(!pending_callbacks_.get());
518 422
519 audio_renderer_.reset(); 423 renderer_.reset();
520 video_renderer_.reset();
521 text_renderer_.reset(); 424 text_renderer_.reset();
522 425
523 if (demuxer_) { 426 if (demuxer_) {
524 demuxer_->Stop(base::Bind(done_cb, PIPELINE_OK)); 427 demuxer_->Stop(base::Bind(done_cb, PIPELINE_OK));
525 return; 428 return;
526 } 429 }
527 430
528 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); 431 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
529 } 432 }
530 433
531 void Pipeline::OnStopCompleted(PipelineStatus status) { 434 void Pipeline::OnStopCompleted(PipelineStatus status) {
532 DVLOG(2) << __FUNCTION__; 435 DVLOG(2) << __FUNCTION__;
533 DCHECK(task_runner_->BelongsToCurrentThread()); 436 DCHECK(task_runner_->BelongsToCurrentThread());
534 DCHECK_EQ(state_, kStopping); 437 DCHECK_EQ(state_, kStopping);
535 DCHECK(!audio_renderer_); 438 DCHECK(!renderer_);
536 DCHECK(!video_renderer_);
537 DCHECK(!text_renderer_); 439 DCHECK(!text_renderer_);
440
538 { 441 {
539 base::AutoLock l(lock_); 442 base::AutoLock l(lock_);
540 running_ = false; 443 running_ = false;
541 } 444 }
542 445
543 SetState(kStopped); 446 SetState(kStopped);
544 filter_collection_.reset(); 447 filter_collection_.reset();
545 demuxer_ = NULL; 448 demuxer_ = NULL;
546 449
547 // If we stop during initialization/seeking we want to run |seek_cb_| 450 // If we stop during initialization/seeking we want to run |seek_cb_|
(...skipping 14 matching lines...) Expand all
562 // NOTE: pipeline may be deleted at this point in time as a result of 465 // NOTE: pipeline may be deleted at this point in time as a result of
563 // executing |stop_cb_|. 466 // executing |stop_cb_|.
564 return; 467 return;
565 } 468 }
566 if (!error_cb_.is_null()) { 469 if (!error_cb_.is_null()) {
567 DCHECK_NE(status_, PIPELINE_OK); 470 DCHECK_NE(status_, PIPELINE_OK);
568 base::ResetAndReturn(&error_cb_).Run(status_); 471 base::ResetAndReturn(&error_cb_).Run(status_);
569 } 472 }
570 } 473 }
571 474
572 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, 475 void Pipeline::AddBufferedTimeRange(TimeDelta start, TimeDelta end) {
573 base::TimeDelta end) {
574 DCHECK(IsRunning()); 476 DCHECK(IsRunning());
575 base::AutoLock auto_lock(lock_); 477 base::AutoLock auto_lock(lock_);
576 buffered_time_ranges_.Add(start, end); 478 buffered_time_ranges_.Add(start, end);
577 did_loading_progress_ = true; 479 did_loading_progress_ = true;
578 } 480 }
579 481
580 // Called from any thread. 482 // Called from any thread.
581 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { 483 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) {
582 base::AutoLock auto_lock(lock_); 484 base::AutoLock auto_lock(lock_);
583 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; 485 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr())); 547 DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr()));
646 } 548 }
647 549
648 void Pipeline::PlaybackRateChangedTask(float playback_rate) { 550 void Pipeline::PlaybackRateChangedTask(float playback_rate) {
649 DCHECK(task_runner_->BelongsToCurrentThread()); 551 DCHECK(task_runner_->BelongsToCurrentThread());
650 552
651 // Playback rate changes are only carried out while playing. 553 // Playback rate changes are only carried out while playing.
652 if (state_ != kPlaying) 554 if (state_ != kPlaying)
653 return; 555 return;
654 556
655 { 557 renderer_->SetPlaybackRate(playback_rate_);
656 base::AutoLock auto_lock(lock_);
657 interpolator_->SetPlaybackRate(playback_rate);
658 }
659
660 if (time_source_)
661 time_source_->SetPlaybackRate(playback_rate_);
662 } 558 }
663 559
664 void Pipeline::VolumeChangedTask(float volume) { 560 void Pipeline::VolumeChangedTask(float volume) {
665 DCHECK(task_runner_->BelongsToCurrentThread()); 561 DCHECK(task_runner_->BelongsToCurrentThread());
666 562
667 // Volume changes are only carried out while playing. 563 // Volume changes are only carried out while playing.
668 if (state_ != kPlaying) 564 if (state_ != kPlaying)
669 return; 565 return;
670 566
671 if (audio_renderer_) 567 renderer_->SetVolume(volume);
672 audio_renderer_->SetVolume(volume);
673 } 568 }
674 569
675 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { 570 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) {
676 DCHECK(task_runner_->BelongsToCurrentThread()); 571 DCHECK(task_runner_->BelongsToCurrentThread());
677 DCHECK(stop_cb_.is_null()); 572 DCHECK(stop_cb_.is_null());
678 573
679 // Suppress seeking if we're not fully started. 574 // Suppress seeking if we're not fully started.
680 if (state_ != kPlaying) { 575 if (state_ != kPlaying) {
681 DCHECK(state_ == kStopping || state_ == kStopped) 576 DCHECK(state_ == kStopping || state_ == kStopped)
682 << "Receive extra seek in unexpected state: " << state_; 577 << "Receive extra seek in unexpected state: " << state_;
683 578
684 // TODO(scherkus): should we run the callback? I'm tempted to say the API 579 // TODO(scherkus): should we run the callback? I'm tempted to say the API
685 // will only execute the first Seek() request. 580 // will only execute the first Seek() request.
686 DVLOG(1) << "Media pipeline has not started, ignoring seek to " 581 DVLOG(1) << "Media pipeline has not started, ignoring seek to "
687 << time.InMicroseconds() << " (current state: " << state_ << ")"; 582 << time.InMicroseconds() << " (current state: " << state_ << ")";
688 return; 583 return;
689 } 584 }
690 585
691 DCHECK(seek_cb_.is_null()); 586 DCHECK(seek_cb_.is_null());
692 587
693 SetState(kSeeking); 588 SetState(kSeeking);
694 seek_cb_ = seek_cb; 589 seek_cb_ = seek_cb;
695 audio_ended_ = false; 590 renderer_ended_ = false;
696 video_ended_ = false; 591 text_renderer_ended_ = false;
697 text_ended_ = false;
698 start_timestamp_ = time; 592 start_timestamp_ = time;
699 593
700 DoSeek(time, 594 DoSeek(time,
701 base::Bind(&Pipeline::OnStateTransition, weak_factory_.GetWeakPtr())); 595 base::Bind(&Pipeline::OnStateTransition, weak_factory_.GetWeakPtr()));
702 } 596 }
703 597
704 void Pipeline::OnAudioRendererEnded() { 598 void Pipeline::OnRendererEnded() {
705 DCHECK(task_runner_->BelongsToCurrentThread()); 599 DCHECK(task_runner_->BelongsToCurrentThread());
706 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::AUDIO_ENDED)); 600 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED));
707 601
708 if (state_ != kPlaying) 602 if (state_ != kPlaying)
709 return; 603 return;
710 604
711 DCHECK(!audio_ended_); 605 DCHECK(!renderer_ended_);
712 audio_ended_ = true; 606 renderer_ended_ = true;
713
714 // Start clock since there is no more audio to trigger clock updates.
715 {
716 base::AutoLock auto_lock(lock_);
717 interpolator_->SetUpperBound(duration_);
718 StartClockIfWaitingForTimeUpdate_Locked();
719 }
720 607
721 RunEndedCallbackIfNeeded(); 608 RunEndedCallbackIfNeeded();
722 } 609 }
723
724 void Pipeline::OnVideoRendererEnded() {
725 DCHECK(task_runner_->BelongsToCurrentThread());
726 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::VIDEO_ENDED));
727
728 if (state_ != kPlaying)
729 return;
730
731 DCHECK(!video_ended_);
732 video_ended_ = true;
733
734 RunEndedCallbackIfNeeded();
735 }
736 610
737 void Pipeline::OnTextRendererEnded() { 611 void Pipeline::OnTextRendererEnded() {
738 DCHECK(task_runner_->BelongsToCurrentThread()); 612 DCHECK(task_runner_->BelongsToCurrentThread());
739 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); 613 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
740 614
741 if (state_ != kPlaying) 615 if (state_ != kPlaying)
742 return; 616 return;
743 617
744 DCHECK(!text_ended_); 618 DCHECK(!text_renderer_ended_);
745 text_ended_ = true; 619 text_renderer_ended_ = true;
746 620
747 RunEndedCallbackIfNeeded(); 621 RunEndedCallbackIfNeeded();
748 } 622 }
749 623
750 void Pipeline::RunEndedCallbackIfNeeded() { 624 void Pipeline::RunEndedCallbackIfNeeded() {
751 DCHECK(task_runner_->BelongsToCurrentThread()); 625 DCHECK(task_runner_->BelongsToCurrentThread());
752 626
753 if (audio_renderer_ && !audio_ended_) 627 if (renderer_ && !renderer_ended_)
754 return; 628 return;
755 629
756 if (video_renderer_ && !video_ended_) 630 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_)
757 return; 631 return;
758 632
759 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_)
760 return;
761
762 {
763 base::AutoLock auto_lock(lock_);
764 PauseClockAndStopTicking_Locked();
765 interpolator_->SetBounds(duration_, duration_);
766 }
767
768 DCHECK_EQ(status_, PIPELINE_OK); 633 DCHECK_EQ(status_, PIPELINE_OK);
769 ended_cb_.Run(); 634 ended_cb_.Run();
770 } 635 }
771 636
772 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, 637 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream,
773 const TextTrackConfig& config) { 638 const TextTrackConfig& config) {
774 DCHECK(task_runner_->BelongsToCurrentThread()); 639 DCHECK(task_runner_->BelongsToCurrentThread());
775 // TODO(matthewjheaney): fix up text_ended_ when text stream 640 // TODO(matthewjheaney): fix up text_ended_ when text stream
776 // is added (http://crbug.com/321446). 641 // is added (http://crbug.com/321446).
777 text_renderer_->AddTextStream(text_stream, config); 642 text_renderer_->AddTextStream(text_stream, config);
778 } 643 }
779 644
780 void Pipeline::RemoveTextStreamTask(DemuxerStream* text_stream) { 645 void Pipeline::RemoveTextStreamTask(DemuxerStream* text_stream) {
781 DCHECK(task_runner_->BelongsToCurrentThread()); 646 DCHECK(task_runner_->BelongsToCurrentThread());
782 text_renderer_->RemoveTextStream(text_stream); 647 text_renderer_->RemoveTextStream(text_stream);
783 } 648 }
784 649
785 void Pipeline::InitializeDemuxer(const PipelineStatusCB& done_cb) { 650 void Pipeline::InitializeDemuxer(const PipelineStatusCB& done_cb) {
786 DCHECK(task_runner_->BelongsToCurrentThread()); 651 DCHECK(task_runner_->BelongsToCurrentThread());
787 652
788 demuxer_ = filter_collection_->GetDemuxer(); 653 demuxer_ = filter_collection_->GetDemuxer();
789 demuxer_->Initialize(this, done_cb, text_renderer_); 654 demuxer_->Initialize(this, done_cb, text_renderer_);
790 } 655 }
791 656
792 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { 657 void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) {
793 DCHECK(task_runner_->BelongsToCurrentThread()); 658 DCHECK(task_runner_->BelongsToCurrentThread());
794 659
795 audio_renderer_ = filter_collection_->GetAudioRenderer(); 660 renderer_ = filter_collection_->GetRenderer();
661
796 base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr(); 662 base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr();
797 audio_renderer_->Initialize( 663 renderer_->Initialize(
798 demuxer_->GetStream(DemuxerStream::AUDIO),
799 done_cb, 664 done_cb,
800 base::Bind(&Pipeline::OnUpdateStatistics, weak_this), 665 base::Bind(&Pipeline::OnUpdateStatistics, weak_this),
801 base::Bind(&Pipeline::OnAudioTimeUpdate, weak_this), 666 base::Bind(&Pipeline::OnRendererEnded, weak_this),
802 base::Bind(&Pipeline::BufferingStateChanged, weak_this,
803 &audio_buffering_state_),
804 base::Bind(&Pipeline::OnAudioRendererEnded, weak_this),
805 base::Bind(&Pipeline::OnError, weak_this));
806 }
807
808 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) {
809 DCHECK(task_runner_->BelongsToCurrentThread());
810
811 video_renderer_ = filter_collection_->GetVideoRenderer();
812 base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr();
813 video_renderer_->Initialize(
814 demuxer_->GetStream(DemuxerStream::VIDEO),
815 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE,
816 done_cb,
817 base::Bind(&Pipeline::OnUpdateStatistics, weak_this),
818 base::Bind(&Pipeline::OnVideoTimeUpdate, weak_this),
819 base::Bind(&Pipeline::BufferingStateChanged, weak_this,
820 &video_buffering_state_),
821 base::Bind(&Pipeline::OnVideoRendererEnded, weak_this),
822 base::Bind(&Pipeline::OnError, weak_this), 667 base::Bind(&Pipeline::OnError, weak_this),
823 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), 668 base::Bind(&Pipeline::BufferingStateChanged, weak_this),
824 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); 669 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this)));
825 } 670 }
826 671
827 void Pipeline::BufferingStateChanged(BufferingState* buffering_state, 672 void Pipeline::BufferingStateChanged(BufferingState new_buffering_state) {
828 BufferingState new_buffering_state) { 673 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") ";
829 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
830 << " " << new_buffering_state << ") "
831 << (buffering_state == &audio_buffering_state_ ? "audio" : "video");
832 DCHECK(task_runner_->BelongsToCurrentThread()); 674 DCHECK(task_runner_->BelongsToCurrentThread());
833 bool was_waiting_for_enough_data = WaitingForEnoughData(); 675 buffering_state_cb_.Run(new_buffering_state);
834
835 *buffering_state = new_buffering_state;
836
837 // Disable underflow by ignoring updates that renderers have ran out of data
838 // after we have started the clock.
839 if (state_ == kPlaying && underflow_disabled_for_testing_ &&
840 interpolation_state_ != INTERPOLATION_STOPPED) {
841 return;
842 }
843
844 // Renderer underflowed.
845 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
846 PausePlayback();
847
848 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
849 // underflow state http://crbug.com/144683
850 return;
851 }
852
853 // Renderer prerolled.
854 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
855 StartPlayback();
856 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
857 return;
858 }
859 }
860
861 bool Pipeline::WaitingForEnoughData() const {
862 DCHECK(task_runner_->BelongsToCurrentThread());
863 if (state_ != kPlaying)
864 return false;
865 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
866 return true;
867 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
868 return true;
869 return false;
870 }
871
872 void Pipeline::PausePlayback() {
873 DVLOG(1) << __FUNCTION__;
874 DCHECK_EQ(state_, kPlaying);
875 DCHECK(WaitingForEnoughData());
876 DCHECK(task_runner_->BelongsToCurrentThread());
877
878 base::AutoLock auto_lock(lock_);
879 PauseClockAndStopTicking_Locked();
880 }
881
882 void Pipeline::StartPlayback() {
883 DVLOG(1) << __FUNCTION__;
884 DCHECK_EQ(state_, kPlaying);
885 DCHECK_EQ(interpolation_state_, INTERPOLATION_STOPPED);
886 DCHECK(!WaitingForEnoughData());
887 DCHECK(task_runner_->BelongsToCurrentThread());
888
889 if (time_source_) {
890 // We use audio stream to update the clock. So if there is such a
891 // stream, we pause the clock until we receive a valid timestamp.
892 base::AutoLock auto_lock(lock_);
893 interpolation_state_ = INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE;
894 time_source_->StartTicking();
895 } else {
896 base::AutoLock auto_lock(lock_);
897 interpolation_state_ = INTERPOLATION_STARTED;
898 interpolator_->SetUpperBound(duration_);
899 interpolator_->StartInterpolating();
900 }
901 }
902
903 void Pipeline::PauseClockAndStopTicking_Locked() {
904 lock_.AssertAcquired();
905 switch (interpolation_state_) {
906 case INTERPOLATION_STOPPED:
907 return;
908
909 case INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE:
910 time_source_->StopTicking();
911 break;
912
913 case INTERPOLATION_STARTED:
914 if (time_source_)
915 time_source_->StopTicking();
916 interpolator_->StopInterpolating();
917 break;
918 }
919
920 interpolation_state_ = INTERPOLATION_STOPPED;
921 }
922
923 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() {
924 lock_.AssertAcquired();
925 if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE)
926 return;
927
928 interpolation_state_ = INTERPOLATION_STARTED;
929 interpolator_->StartInterpolating();
930 } 676 }
931 677
932 } // namespace media 678 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698