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

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

Powered by Google App Engine
This is Rietveld 408576698