Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/pipeline.h" | 5 #include "media/base/pipeline.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 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/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 17 #include "base/synchronization/condition_variable.h" | 17 #include "base/synchronization/condition_variable.h" |
| 18 #include "media/base/audio_decoder.h" | 18 #include "media/base/audio_decoder.h" |
| 19 #include "media/base/audio_renderer.h" | 19 #include "media/base/audio_renderer.h" |
| 20 #include "media/base/callback_util.h" | |
| 21 #include "media/base/clock.h" | 20 #include "media/base/clock.h" |
| 22 #include "media/base/filter_collection.h" | 21 #include "media/base/filter_collection.h" |
| 23 #include "media/base/media_log.h" | 22 #include "media/base/media_log.h" |
| 24 #include "media/base/video_decoder.h" | 23 #include "media/base/video_decoder.h" |
| 25 #include "media/base/video_renderer.h" | 24 #include "media/base/video_renderer.h" |
| 26 | 25 |
| 27 using base::TimeDelta; | 26 using base::TimeDelta; |
| 28 | 27 |
| 29 namespace media { | 28 namespace media { |
| 30 | 29 |
| 30 // Used to convert a callback to a function accepting a Closure into a callback | |
|
Ami GONE FROM CHROMIUM
2012/08/03 19:29:01
s/callback to a /bound/ twice
scherkus (not reviewing)
2012/08/03 20:19:04
Done.
| |
| 31 // to a function accepting a PipelineStatusCB. Since closures have no way of | |
| 32 // reporting a status |status_cb| is executed with PIPELINE_OK. | |
| 33 typedef base::Callback<void(const base::Closure&)> ClosureFunc; | |
| 34 void RunClosureFunc(const ClosureFunc& closure, | |
| 35 const PipelineStatusCB& status_cb) { | |
| 36 closure.Run(base::Bind(status_cb, PIPELINE_OK)); | |
| 37 } | |
| 38 | |
| 31 PipelineStatusNotification::PipelineStatusNotification() | 39 PipelineStatusNotification::PipelineStatusNotification() |
| 32 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) { | 40 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) { |
| 33 } | 41 } |
| 34 | 42 |
| 35 PipelineStatusNotification::~PipelineStatusNotification() { | 43 PipelineStatusNotification::~PipelineStatusNotification() { |
| 36 DCHECK(notified_); | 44 DCHECK(notified_); |
| 37 } | 45 } |
| 38 | 46 |
| 39 PipelineStatusCB PipelineStatusNotification::Callback() { | 47 PipelineStatusCB PipelineStatusNotification::Callback() { |
| 40 return base::Bind(&PipelineStatusNotification::Notify, | 48 return base::Bind(&PipelineStatusNotification::Notify, |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 444 // Since the byte->time calculation is approximate, fudge the beginning & | 452 // Since the byte->time calculation is approximate, fudge the beginning & |
| 445 // ending areas to look better. | 453 // ending areas to look better. |
| 446 TimeDelta epsilon = clock_->Duration() / 100; | 454 TimeDelta epsilon = clock_->Duration() / 100; |
| 447 if (time_offset < epsilon) | 455 if (time_offset < epsilon) |
| 448 return TimeDelta(); | 456 return TimeDelta(); |
| 449 if (time_offset + epsilon > clock_->Duration()) | 457 if (time_offset + epsilon > clock_->Duration()) |
| 450 return clock_->Duration(); | 458 return clock_->Duration(); |
| 451 return time_offset; | 459 return time_offset; |
| 452 } | 460 } |
| 453 | 461 |
| 454 void Pipeline::DoPause(const base::Closure& done_cb) { | 462 void Pipeline::DoPause(const PipelineStatusCB& done_cb) { |
| 455 DCHECK(message_loop_->BelongsToCurrentThread()); | 463 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 456 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); | 464 DCHECK(!pending_callbacks_.get()); |
| 465 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( | |
| 466 new std::queue<PipelineStatusCBFunc>()); | |
| 457 | 467 |
| 458 if (audio_renderer_) | 468 if (audio_renderer_) { |
| 459 closures->push(base::Bind(&AudioRenderer::Pause, audio_renderer_)); | 469 status_cbs->push(base::Bind( |
| 470 &RunClosureFunc, base::Bind(&AudioRenderer::Pause, audio_renderer_))); | |
| 471 } | |
| 460 | 472 |
| 461 if (video_renderer_) | 473 if (video_renderer_) { |
| 462 closures->push(base::Bind(&VideoRenderer::Pause, video_renderer_)); | 474 status_cbs->push(base::Bind( |
| 475 &RunClosureFunc, base::Bind(&VideoRenderer::Pause, video_renderer_))); | |
| 476 } | |
| 463 | 477 |
| 464 RunInSeries(closures.Pass(), done_cb); | 478 pending_callbacks_ = SerialCallbackRunner::Run(status_cbs.Pass(), done_cb); |
| 465 } | 479 } |
| 466 | 480 |
| 467 void Pipeline::DoFlush(const base::Closure& done_cb) { | 481 void Pipeline::DoFlush(const PipelineStatusCB& done_cb) { |
| 468 DCHECK(message_loop_->BelongsToCurrentThread()); | 482 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 469 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); | 483 DCHECK(!pending_callbacks_.get()); |
| 484 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( | |
| 485 new std::queue<PipelineStatusCBFunc>()); | |
| 470 | 486 |
| 471 if (audio_renderer_) | 487 if (audio_renderer_) { |
| 472 closures->push(base::Bind(&AudioRenderer::Flush, audio_renderer_)); | 488 status_cbs->push(base::Bind( |
| 489 &RunClosureFunc, base::Bind(&AudioRenderer::Flush, audio_renderer_))); | |
| 490 } | |
| 473 | 491 |
| 474 if (video_renderer_) | 492 if (video_renderer_) { |
| 475 closures->push(base::Bind(&VideoRenderer::Flush, video_renderer_)); | 493 status_cbs->push(base::Bind( |
| 494 &RunClosureFunc, base::Bind(&VideoRenderer::Flush, video_renderer_))); | |
| 495 } | |
| 476 | 496 |
| 477 RunInParallel(closures.Pass(), done_cb); | 497 pending_callbacks_ = SerialCallbackRunner::Run(status_cbs.Pass(), done_cb); |
| 478 } | 498 } |
| 479 | 499 |
| 480 void Pipeline::DoPlay(const base::Closure& done_cb) { | 500 void Pipeline::DoPlay(const PipelineStatusCB& done_cb) { |
| 481 DCHECK(message_loop_->BelongsToCurrentThread()); | 501 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 482 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); | 502 DCHECK(!pending_callbacks_.get()); |
| 503 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( | |
| 504 new std::queue<PipelineStatusCBFunc>()); | |
| 483 | 505 |
| 484 if (audio_renderer_) | 506 if (audio_renderer_) { |
| 485 closures->push(base::Bind(&AudioRenderer::Play, audio_renderer_)); | 507 status_cbs->push(base::Bind( |
| 508 &RunClosureFunc, base::Bind(&AudioRenderer::Play, audio_renderer_))); | |
| 509 } | |
| 486 | 510 |
| 487 if (video_renderer_) | 511 if (video_renderer_) { |
| 488 closures->push(base::Bind(&VideoRenderer::Play, video_renderer_)); | 512 status_cbs->push(base::Bind( |
| 513 &RunClosureFunc, base::Bind(&VideoRenderer::Play, video_renderer_))); | |
| 514 } | |
| 489 | 515 |
| 490 RunInSeries(closures.Pass(), done_cb); | 516 pending_callbacks_ = SerialCallbackRunner::Run(status_cbs.Pass(), done_cb); |
| 491 } | 517 } |
| 492 | 518 |
| 493 void Pipeline::DoStop(const base::Closure& done_cb) { | 519 void Pipeline::DoStop(const PipelineStatusCB& done_cb) { |
| 494 DCHECK(message_loop_->BelongsToCurrentThread()); | 520 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 495 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); | 521 DCHECK(!pending_callbacks_.get()); |
| 522 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( | |
| 523 new std::queue<PipelineStatusCBFunc>()); | |
| 496 | 524 |
| 497 if (demuxer_) | 525 if (demuxer_) { |
| 498 closures->push(base::Bind(&Demuxer::Stop, demuxer_)); | 526 status_cbs->push(base::Bind( |
| 527 &RunClosureFunc, base::Bind(&Demuxer::Stop, demuxer_))); | |
| 528 } | |
| 499 | 529 |
| 500 if (audio_renderer_) | 530 if (audio_renderer_) { |
| 501 closures->push(base::Bind(&AudioRenderer::Stop, audio_renderer_)); | 531 status_cbs->push(base::Bind( |
| 532 &RunClosureFunc, base::Bind(&AudioRenderer::Stop, audio_renderer_))); | |
| 533 } | |
| 502 | 534 |
| 503 if (video_renderer_) | 535 if (video_renderer_) { |
| 504 closures->push(base::Bind(&VideoRenderer::Stop, video_renderer_)); | 536 status_cbs->push(base::Bind( |
| 537 &RunClosureFunc, base::Bind(&VideoRenderer::Stop, video_renderer_))); | |
| 538 } | |
| 505 | 539 |
| 506 RunInSeries(closures.Pass(), done_cb); | 540 pending_callbacks_ = SerialCallbackRunner::Run(status_cbs.Pass(), done_cb); |
| 507 } | 541 } |
| 508 | 542 |
| 509 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { | 543 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { |
| 510 DCHECK(IsRunning()); | 544 DCHECK(IsRunning()); |
| 511 base::AutoLock auto_lock(lock_); | 545 base::AutoLock auto_lock(lock_); |
| 512 buffered_byte_ranges_.Add(start, end); | 546 buffered_byte_ranges_.Add(start, end); |
| 513 did_loading_progress_ = true; | 547 did_loading_progress_ = true; |
| 514 } | 548 } |
| 515 | 549 |
| 516 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, | 550 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 538 } | 572 } |
| 539 | 573 |
| 540 // Called from any thread. | 574 // Called from any thread. |
| 541 void Pipeline::OnFilterInitialize(PipelineStatus status) { | 575 void Pipeline::OnFilterInitialize(PipelineStatus status) { |
| 542 // Continue the initialize task by proceeding to the next stage. | 576 // Continue the initialize task by proceeding to the next stage. |
| 543 message_loop_->PostTask(FROM_HERE, base::Bind( | 577 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 544 &Pipeline::InitializeTask, this, status)); | 578 &Pipeline::InitializeTask, this, status)); |
| 545 } | 579 } |
| 546 | 580 |
| 547 // Called from any thread. | 581 // Called from any thread. |
| 548 void Pipeline::OnFilterStateTransition() { | |
| 549 message_loop_->PostTask(FROM_HERE, base::Bind( | |
| 550 &Pipeline::FilterStateTransitionTask, this)); | |
| 551 } | |
| 552 | |
| 553 // Called from any thread. | |
| 554 // This method makes the PipelineStatusCB behave like a Closure. It | 582 // This method makes the PipelineStatusCB behave like a Closure. It |
| 555 // makes it look like a host()->SetError() call followed by a call to | 583 // makes it look like a host()->SetError() call followed by a call to |
| 556 // OnFilterStateTransition() when errors occur. | 584 // OnFilterStateTransition() when errors occur. |
| 557 // | 585 // |
| 558 // TODO: Revisit this code when SetError() is removed from FilterHost and | 586 // TODO: Revisit this code when SetError() is removed from FilterHost and |
| 559 // all the Closures are converted to PipelineStatusCB. | 587 // all the Closures are converted to PipelineStatusCB. |
| 560 void Pipeline::OnFilterStateTransitionWithStatus(PipelineStatus status) { | 588 void Pipeline::OnFilterStateTransition(PipelineStatus status) { |
| 561 if (status != PIPELINE_OK) | 589 if (status != PIPELINE_OK) |
| 562 SetError(status); | 590 SetError(status); |
| 563 OnFilterStateTransition(); | 591 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 592 &Pipeline::FilterStateTransitionTask, this)); | |
| 564 } | 593 } |
| 565 | 594 |
| 566 void Pipeline::OnTeardownStateTransition() { | 595 void Pipeline::OnTeardownStateTransition(PipelineStatus status) { |
| 596 // Ignore any errors during teardown. | |
| 567 message_loop_->PostTask(FROM_HERE, base::Bind( | 597 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 568 &Pipeline::TeardownStateTransitionTask, this)); | 598 &Pipeline::TeardownStateTransitionTask, this)); |
| 569 } | 599 } |
| 570 | 600 |
| 571 // Called from any thread. | 601 // Called from any thread. |
| 572 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { | 602 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { |
| 573 base::AutoLock auto_lock(lock_); | 603 base::AutoLock auto_lock(lock_); |
| 574 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; | 604 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; |
| 575 statistics_.video_bytes_decoded += stats.video_bytes_decoded; | 605 statistics_.video_bytes_decoded += stats.video_bytes_decoded; |
| 576 statistics_.video_frames_decoded += stats.video_frames_decoded; | 606 statistics_.video_frames_decoded += stats.video_frames_decoded; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 687 // to set the initial playback rate and volume. | 717 // to set the initial playback rate and volume. |
| 688 PlaybackRateChangedTask(GetPlaybackRate()); | 718 PlaybackRateChangedTask(GetPlaybackRate()); |
| 689 VolumeChangedTask(GetVolume()); | 719 VolumeChangedTask(GetVolume()); |
| 690 | 720 |
| 691 // Fire a seek request to get the renderers to preroll. We can skip a seek | 721 // Fire a seek request to get the renderers to preroll. We can skip a seek |
| 692 // here as the demuxer should be at the start of the stream. | 722 // here as the demuxer should be at the start of the stream. |
| 693 seek_pending_ = true; | 723 seek_pending_ = true; |
| 694 SetState(kSeeking); | 724 SetState(kSeeking); |
| 695 seek_timestamp_ = demuxer_->GetStartTime(); | 725 seek_timestamp_ = demuxer_->GetStartTime(); |
| 696 DoSeek(seek_timestamp_, true, | 726 DoSeek(seek_timestamp_, true, |
| 697 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); | 727 base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 698 } | 728 } |
| 699 } | 729 } |
| 700 | 730 |
| 701 // This method is called as a result of the client calling Pipeline::Stop() or | 731 // This method is called as a result of the client calling Pipeline::Stop() or |
| 702 // as the result of an error condition. | 732 // as the result of an error condition. |
| 703 // We stop the filters in the reverse order. | 733 // We stop the filters in the reverse order. |
| 704 // | 734 // |
| 705 // TODO(scherkus): beware! this can get posted multiple times since we post | 735 // TODO(scherkus): beware! this can get posted multiple times since we post |
| 706 // Stop() tasks even if we've already stopped. Perhaps this should no-op for | 736 // Stop() tasks even if we've already stopped. Perhaps this should no-op for |
| 707 // additional calls, however most of this logic will be changing. | 737 // additional calls, however most of this logic will be changing. |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 882 demuxer_->OnAudioRendererDisabled(); | 912 demuxer_->OnAudioRendererDisabled(); |
| 883 | 913 |
| 884 // Start clock since there is no more audio to | 914 // Start clock since there is no more audio to |
| 885 // trigger clock updates. | 915 // trigger clock updates. |
| 886 clock_->SetMaxTime(clock_->Duration()); | 916 clock_->SetMaxTime(clock_->Duration()); |
| 887 StartClockIfWaitingForTimeUpdate_Locked(); | 917 StartClockIfWaitingForTimeUpdate_Locked(); |
| 888 } | 918 } |
| 889 | 919 |
| 890 void Pipeline::FilterStateTransitionTask() { | 920 void Pipeline::FilterStateTransitionTask() { |
| 891 DCHECK(message_loop_->BelongsToCurrentThread()); | 921 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 922 DCHECK(pending_callbacks_.get()) | |
| 923 << "Filter state transitions must be completed via pending_callbacks_"; | |
| 924 pending_callbacks_.reset(); | |
| 892 | 925 |
| 893 // No reason transitioning if we've errored or have stopped. | 926 // No reason transitioning if we've errored or have stopped. |
| 894 if (IsPipelineStopped()) { | 927 if (IsPipelineStopped()) { |
| 895 return; | 928 return; |
| 896 } | 929 } |
| 897 | 930 |
| 898 // If we are tearing down, don't allow any state changes. Teardown | 931 // If we are tearing down, don't allow any state changes. Teardown |
| 899 // state changes will come in via TeardownStateTransitionTask(). | 932 // state changes will come in via TeardownStateTransitionTask(). |
| 900 if (IsPipelineTearingDown()) { | 933 if (IsPipelineTearingDown()) { |
| 901 return; | 934 return; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 916 } | 949 } |
| 917 | 950 |
| 918 // Carry out the action for the current state. | 951 // Carry out the action for the current state. |
| 919 if (TransientState(state_)) { | 952 if (TransientState(state_)) { |
| 920 if (state_ == kPausing) { | 953 if (state_ == kPausing) { |
| 921 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 954 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 922 } else if (state_ == kFlushing) { | 955 } else if (state_ == kFlushing) { |
| 923 DoFlush(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 956 DoFlush(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 924 } else if (state_ == kSeeking) { | 957 } else if (state_ == kSeeking) { |
| 925 DoSeek(seek_timestamp_, false, | 958 DoSeek(seek_timestamp_, false, |
| 926 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); | 959 base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 927 } else if (state_ == kStarting) { | 960 } else if (state_ == kStarting) { |
| 928 DoPlay(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 961 DoPlay(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 929 } else if (state_ == kStopping) { | 962 } else if (state_ == kStopping) { |
| 930 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 963 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 931 } else { | 964 } else { |
| 932 NOTREACHED() << "Unexpected state: " << state_; | 965 NOTREACHED() << "Unexpected state: " << state_; |
| 933 } | 966 } |
| 934 } else if (state_ == kStarted) { | 967 } else if (state_ == kStarted) { |
| 935 FinishInitialization(); | 968 FinishInitialization(); |
| 936 | 969 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 957 // We had a pending stop request need to be honored right now. | 990 // We had a pending stop request need to be honored right now. |
| 958 TearDownPipeline(); | 991 TearDownPipeline(); |
| 959 } | 992 } |
| 960 } else { | 993 } else { |
| 961 NOTREACHED() << "Unexpected state: " << state_; | 994 NOTREACHED() << "Unexpected state: " << state_; |
| 962 } | 995 } |
| 963 } | 996 } |
| 964 | 997 |
| 965 void Pipeline::TeardownStateTransitionTask() { | 998 void Pipeline::TeardownStateTransitionTask() { |
| 966 DCHECK(IsPipelineTearingDown()); | 999 DCHECK(IsPipelineTearingDown()); |
| 1000 DCHECK(pending_callbacks_.get()) | |
| 1001 << "Teardown state transitions must be completed via pending_callbacks_"; | |
| 1002 pending_callbacks_.reset(); | |
| 1003 | |
| 967 switch (state_) { | 1004 switch (state_) { |
| 968 case kStopping: | 1005 case kStopping: |
| 969 SetState(error_caused_teardown_ ? kError : kStopped); | 1006 SetState(error_caused_teardown_ ? kError : kStopped); |
| 970 FinishDestroyingFiltersTask(); | 1007 FinishDestroyingFiltersTask(); |
| 971 break; | 1008 break; |
| 972 case kPausing: | 1009 case kPausing: |
| 973 SetState(kFlushing); | 1010 SetState(kFlushing); |
| 974 DoFlush(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1011 DoFlush(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 975 break; | 1012 break; |
| 976 case kFlushing: | 1013 case kFlushing: |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1164 DCHECK(message_loop_->BelongsToCurrentThread()); | 1201 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1165 DCHECK_NE(kStopped, state_); | 1202 DCHECK_NE(kStopped, state_); |
| 1166 | 1203 |
| 1167 DCHECK(!tearing_down_ || // Teardown on Stop(). | 1204 DCHECK(!tearing_down_ || // Teardown on Stop(). |
| 1168 (tearing_down_ && error_caused_teardown_) || // Teardown on error. | 1205 (tearing_down_ && error_caused_teardown_) || // Teardown on error. |
| 1169 (tearing_down_ && stop_pending_)); // Stop during teardown by error. | 1206 (tearing_down_ && stop_pending_)); // Stop during teardown by error. |
| 1170 | 1207 |
| 1171 // Mark that we already start tearing down operation. | 1208 // Mark that we already start tearing down operation. |
| 1172 tearing_down_ = true; | 1209 tearing_down_ = true; |
| 1173 | 1210 |
| 1211 // Cancel any pending operation so we can proceed with teardown. | |
| 1212 pending_callbacks_.reset(); | |
| 1213 | |
| 1174 switch (state_) { | 1214 switch (state_) { |
| 1175 case kCreated: | 1215 case kCreated: |
| 1176 case kError: | 1216 case kError: |
| 1177 SetState(kStopped); | 1217 SetState(kStopped); |
| 1178 // Need to put this in the message loop to make sure that it comes | 1218 // Need to put this in the message loop to make sure that it comes |
| 1179 // after any pending callback tasks that are already queued. | 1219 // after any pending callback tasks that are already queued. |
| 1180 message_loop_->PostTask(FROM_HERE, base::Bind( | 1220 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 1181 &Pipeline::FinishDestroyingFiltersTask, this)); | 1221 &Pipeline::FinishDestroyingFiltersTask, this)); |
| 1182 break; | 1222 break; |
| 1183 | 1223 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1222 break; | 1262 break; |
| 1223 // default: intentionally left out to force new states to cause compiler | 1263 // default: intentionally left out to force new states to cause compiler |
| 1224 // errors. | 1264 // errors. |
| 1225 }; | 1265 }; |
| 1226 } | 1266 } |
| 1227 | 1267 |
| 1228 void Pipeline::DoSeek(base::TimeDelta seek_timestamp, | 1268 void Pipeline::DoSeek(base::TimeDelta seek_timestamp, |
| 1229 bool skip_demuxer_seek, | 1269 bool skip_demuxer_seek, |
| 1230 const PipelineStatusCB& done_cb) { | 1270 const PipelineStatusCB& done_cb) { |
| 1231 DCHECK(message_loop_->BelongsToCurrentThread()); | 1271 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1272 DCHECK(!pending_callbacks_.get()); | |
| 1232 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( | 1273 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( |
| 1233 new std::queue<PipelineStatusCBFunc>()); | 1274 new std::queue<PipelineStatusCBFunc>()); |
| 1234 | 1275 |
| 1235 if (!skip_demuxer_seek) | 1276 if (!skip_demuxer_seek) { |
| 1236 status_cbs->push(base::Bind(&Demuxer::Seek, demuxer_, seek_timestamp)); | 1277 status_cbs->push(base::Bind( |
| 1278 &Demuxer::Seek, demuxer_, seek_timestamp)); | |
| 1279 } | |
| 1237 | 1280 |
| 1238 if (audio_renderer_) | 1281 if (audio_renderer_) { |
| 1239 status_cbs->push(base::Bind( | 1282 status_cbs->push(base::Bind( |
| 1240 &AudioRenderer::Preroll, audio_renderer_, seek_timestamp)); | 1283 &AudioRenderer::Preroll, audio_renderer_, seek_timestamp)); |
| 1284 } | |
| 1241 | 1285 |
| 1242 if (video_renderer_) | 1286 if (video_renderer_) { |
| 1243 status_cbs->push(base::Bind( | 1287 status_cbs->push(base::Bind( |
| 1244 &VideoRenderer::Preroll, video_renderer_, seek_timestamp)); | 1288 &VideoRenderer::Preroll, video_renderer_, seek_timestamp)); |
| 1289 } | |
| 1245 | 1290 |
| 1246 RunInSeriesWithStatus(status_cbs.Pass(), base::Bind( | 1291 pending_callbacks_ = SerialCallbackRunner::Run(status_cbs.Pass(), done_cb); |
| 1247 &Pipeline::ReportStatus, this, done_cb)); | |
| 1248 } | 1292 } |
| 1249 | 1293 |
| 1250 void Pipeline::OnAudioUnderflow() { | 1294 void Pipeline::OnAudioUnderflow() { |
| 1251 if (!message_loop_->BelongsToCurrentThread()) { | 1295 if (!message_loop_->BelongsToCurrentThread()) { |
| 1252 message_loop_->PostTask(FROM_HERE, base::Bind( | 1296 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 1253 &Pipeline::OnAudioUnderflow, this)); | 1297 &Pipeline::OnAudioUnderflow, this)); |
| 1254 return; | 1298 return; |
| 1255 } | 1299 } |
| 1256 | 1300 |
| 1257 if (state_ != kStarted) | 1301 if (state_ != kStarted) |
| 1258 return; | 1302 return; |
| 1259 | 1303 |
| 1260 if (audio_renderer_) | 1304 if (audio_renderer_) |
| 1261 audio_renderer_->ResumeAfterUnderflow(true); | 1305 audio_renderer_->ResumeAfterUnderflow(true); |
| 1262 } | 1306 } |
| 1263 | 1307 |
| 1264 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1308 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
| 1265 lock_.AssertAcquired(); | 1309 lock_.AssertAcquired(); |
| 1266 if (!waiting_for_clock_update_) | 1310 if (!waiting_for_clock_update_) |
| 1267 return; | 1311 return; |
| 1268 | 1312 |
| 1269 waiting_for_clock_update_ = false; | 1313 waiting_for_clock_update_ = false; |
| 1270 clock_->Play(); | 1314 clock_->Play(); |
| 1271 } | 1315 } |
| 1272 | 1316 |
| 1273 } // namespace media | 1317 } // namespace media |
| OLD | NEW |