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

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

Powered by Google App Engine
This is Rietveld 408576698