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/buffers.h" | 20 #include "media/base/buffers.h" |
| 21 #include "media/base/clock.h" | 21 #include "media/base/clock.h" |
| 22 #include "media/base/filter_collection.h" | 22 #include "media/base/filter_collection.h" |
| 23 #include "media/base/media_log.h" | 23 #include "media/base/media_log.h" |
| 24 #include "media/base/video_decoder.h" | 24 #include "media/base/video_decoder.h" |
| 25 #include "media/base/video_decoder_config.h" | |
| 25 #include "media/base/video_renderer.h" | 26 #include "media/base/video_renderer.h" |
| 26 | 27 |
| 27 using base::TimeDelta; | 28 using base::TimeDelta; |
| 28 | 29 |
| 29 namespace media { | 30 namespace media { |
| 30 | 31 |
| 31 PipelineStatusNotification::PipelineStatusNotification() | 32 PipelineStatusNotification::PipelineStatusNotification() |
| 32 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) { | 33 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) { |
| 33 } | 34 } |
| 34 | 35 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 100 DCHECK(stop_cb_.is_null()); | 101 DCHECK(stop_cb_.is_null()); |
| 101 DCHECK(!seek_pending_); | 102 DCHECK(!seek_pending_); |
| 102 | 103 |
| 103 media_log_->AddEvent( | 104 media_log_->AddEvent( |
| 104 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); | 105 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); |
| 105 } | 106 } |
| 106 | 107 |
| 107 void Pipeline::Start(scoped_ptr<FilterCollection> collection, | 108 void Pipeline::Start(scoped_ptr<FilterCollection> collection, |
| 108 const PipelineStatusCB& ended_cb, | 109 const PipelineStatusCB& ended_cb, |
| 109 const PipelineStatusCB& error_cb, | 110 const PipelineStatusCB& error_cb, |
| 110 const PipelineStatusCB& start_cb) { | 111 const PipelineStatusCB& start_cb, |
| 112 const ReadyStateCB& ready_state_cb) { | |
| 111 base::AutoLock auto_lock(lock_); | 113 base::AutoLock auto_lock(lock_); |
| 112 CHECK(!running_) << "Media pipeline is already running"; | 114 CHECK(!running_) << "Media pipeline is already running"; |
| 113 | 115 |
| 114 running_ = true; | 116 running_ = true; |
| 115 message_loop_->PostTask(FROM_HERE, base::Bind( | 117 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 116 &Pipeline::StartTask, this, base::Passed(&collection), | 118 &Pipeline::StartTask, this, base::Passed(&collection), |
| 117 ended_cb, error_cb, start_cb)); | 119 ended_cb, error_cb, start_cb, ready_state_cb)); |
| 118 } | 120 } |
| 119 | 121 |
| 120 void Pipeline::Stop(const base::Closure& stop_cb) { | 122 void Pipeline::Stop(const base::Closure& stop_cb) { |
| 121 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
| 122 message_loop_->PostTask(FROM_HERE, base::Bind( | 124 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 123 &Pipeline::StopTask, this, stop_cb)); | 125 &Pipeline::StopTask, this, stop_cb)); |
| 124 } | 126 } |
| 125 | 127 |
| 126 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { | 128 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { |
| 127 base::AutoLock auto_lock(lock_); | 129 base::AutoLock auto_lock(lock_); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 272 if (cb.is_null()) | 274 if (cb.is_null()) |
| 273 return; | 275 return; |
| 274 cb.Run(status); | 276 cb.Run(status); |
| 275 // Prevent double-reporting of errors to clients. | 277 // Prevent double-reporting of errors to clients. |
| 276 if (status != PIPELINE_OK) | 278 if (status != PIPELINE_OK) |
| 277 error_cb_.Reset(); | 279 error_cb_.Reset(); |
| 278 } | 280 } |
| 279 | 281 |
| 280 void Pipeline::FinishInitialization() { | 282 void Pipeline::FinishInitialization() { |
| 281 DCHECK(message_loop_->BelongsToCurrentThread()); | 283 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 284 if (!ready_state_cb_.is_null()) | |
| 285 ready_state_cb_.Run(HaveEnoughData); | |
|
scherkus (not reviewing)
2012/08/15 19:53:43
fix indent
acolwell GONE FROM CHROMIUM
2012/08/15 23:21:15
Done.
| |
| 286 | |
| 282 // Execute the seek callback, if present. Note that this might be the | 287 // Execute the seek callback, if present. Note that this might be the |
| 283 // initial callback passed into Start(). | 288 // initial callback passed into Start(). |
| 284 ReportStatus(seek_cb_, status_); | 289 ReportStatus(seek_cb_, status_); |
| 285 seek_timestamp_ = kNoTimestamp(); | 290 seek_timestamp_ = kNoTimestamp(); |
| 286 seek_cb_.Reset(); | 291 seek_cb_.Reset(); |
| 287 } | 292 } |
| 288 | 293 |
| 289 // static | 294 // static |
| 290 bool Pipeline::TransientState(State state) { | 295 bool Pipeline::TransientState(State state) { |
| 291 return state == kPausing || | 296 return state == kPausing || |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 540 base::AutoLock auto_lock(lock_); | 545 base::AutoLock auto_lock(lock_); |
| 541 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; | 546 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; |
| 542 statistics_.video_bytes_decoded += stats.video_bytes_decoded; | 547 statistics_.video_bytes_decoded += stats.video_bytes_decoded; |
| 543 statistics_.video_frames_decoded += stats.video_frames_decoded; | 548 statistics_.video_frames_decoded += stats.video_frames_decoded; |
| 544 statistics_.video_frames_dropped += stats.video_frames_dropped; | 549 statistics_.video_frames_dropped += stats.video_frames_dropped; |
| 545 } | 550 } |
| 546 | 551 |
| 547 void Pipeline::StartTask(scoped_ptr<FilterCollection> filter_collection, | 552 void Pipeline::StartTask(scoped_ptr<FilterCollection> filter_collection, |
| 548 const PipelineStatusCB& ended_cb, | 553 const PipelineStatusCB& ended_cb, |
| 549 const PipelineStatusCB& error_cb, | 554 const PipelineStatusCB& error_cb, |
| 550 const PipelineStatusCB& start_cb) { | 555 const PipelineStatusCB& start_cb, |
|
Ami GONE FROM CHROMIUM
2012/08/15 18:00:08
AFAICT start_cb.Run() is always called with OK (el
scherkus (not reviewing)
2012/08/15 19:53:43
start_cb is set as seek_cb, meaning it will get ca
acolwell GONE FROM CHROMIUM
2012/08/15 23:21:15
So I've kept the callback for now, but I've rename
| |
| 556 const ReadyStateCB& ready_state_cb) { | |
| 551 DCHECK(message_loop_->BelongsToCurrentThread()); | 557 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 552 DCHECK_EQ(kCreated, state_); | 558 DCHECK_EQ(kCreated, state_); |
| 553 filter_collection_ = filter_collection.Pass(); | 559 filter_collection_ = filter_collection.Pass(); |
| 554 ended_cb_ = ended_cb; | 560 ended_cb_ = ended_cb; |
| 555 error_cb_ = error_cb; | 561 error_cb_ = error_cb; |
| 556 seek_cb_ = start_cb; | 562 seek_cb_ = start_cb; |
| 563 ready_state_cb_ = ready_state_cb; | |
| 557 | 564 |
| 558 // Kick off initialization. | 565 // Kick off initialization. |
| 559 pipeline_init_state_.reset(new PipelineInitState()); | 566 pipeline_init_state_.reset(new PipelineInitState()); |
| 560 | 567 |
| 561 SetState(kInitDemuxer); | 568 SetState(kInitDemuxer); |
| 562 InitializeDemuxer(); | 569 InitializeDemuxer(); |
| 563 } | 570 } |
| 564 | 571 |
| 565 // Main initialization method called on the pipeline thread. This code attempts | 572 // Main initialization method called on the pipeline thread. This code attempts |
| 566 // to use the specified filter factory to build a pipeline. | 573 // to use the specified filter factory to build a pipeline. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 612 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder)) { | 619 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder)) { |
| 613 base::AutoLock auto_lock(lock_); | 620 base::AutoLock auto_lock(lock_); |
| 614 has_audio_ = true; | 621 has_audio_ = true; |
| 615 return; | 622 return; |
| 616 } | 623 } |
| 617 } | 624 } |
| 618 | 625 |
| 619 // Assuming audio renderer was created, create video renderer. | 626 // Assuming audio renderer was created, create video renderer. |
| 620 if (state_ == kInitAudioRenderer) { | 627 if (state_ == kInitAudioRenderer) { |
| 621 SetState(kInitVideoRenderer); | 628 SetState(kInitVideoRenderer); |
| 622 if (InitializeVideoRenderer(demuxer_->GetStream(DemuxerStream::VIDEO))) { | 629 scoped_refptr<DemuxerStream> video_stream = |
| 630 demuxer_->GetStream(DemuxerStream::VIDEO); | |
| 631 if (InitializeVideoRenderer(video_stream)) { | |
| 623 base::AutoLock auto_lock(lock_); | 632 base::AutoLock auto_lock(lock_); |
| 624 has_video_ = true; | 633 has_video_ = true; |
| 634 | |
| 635 // Get an initial natural size so we have something when we signal | |
| 636 // the HaveMetadata ready state. | |
| 637 natural_size_ = video_stream->video_decoder_config().natural_size(); | |
| 625 return; | 638 return; |
| 626 } | 639 } |
| 627 } | 640 } |
| 628 | 641 |
| 629 if (state_ == kInitVideoRenderer) { | 642 if (state_ == kInitVideoRenderer) { |
| 630 if (!IsPipelineOk() || !(HasAudio() || HasVideo())) { | 643 if (!IsPipelineOk() || !(HasAudio() || HasVideo())) { |
| 631 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); | 644 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); |
| 632 return; | 645 return; |
| 633 } | 646 } |
| 634 | 647 |
| 635 // Clear initialization state now that we're done. | 648 // Clear initialization state now that we're done. |
| 636 filter_collection_.reset(); | 649 filter_collection_.reset(); |
| 637 pipeline_init_state_.reset(); | 650 pipeline_init_state_.reset(); |
| 638 | 651 |
| 639 // Initialization was successful, we are now considered paused, so it's safe | 652 // Initialization was successful, we are now considered paused, so it's safe |
| 640 // to set the initial playback rate and volume. | 653 // to set the initial playback rate and volume. |
| 641 PlaybackRateChangedTask(GetPlaybackRate()); | 654 PlaybackRateChangedTask(GetPlaybackRate()); |
| 642 VolumeChangedTask(GetVolume()); | 655 VolumeChangedTask(GetVolume()); |
| 643 | 656 |
| 657 if (!ready_state_cb_.is_null()) | |
| 658 ready_state_cb_.Run(HaveMetadata); | |
| 659 | |
| 644 // Fire a seek request to get the renderers to preroll. We can skip a seek | 660 // Fire a seek request to get the renderers to preroll. We can skip a seek |
| 645 // here as the demuxer should be at the start of the stream. | 661 // here as the demuxer should be at the start of the stream. |
| 646 seek_pending_ = true; | 662 seek_pending_ = true; |
| 647 SetState(kSeeking); | 663 SetState(kSeeking); |
| 648 seek_timestamp_ = demuxer_->GetStartTime(); | 664 seek_timestamp_ = demuxer_->GetStartTime(); |
| 649 DoSeek(seek_timestamp_, true, | 665 DoSeek(seek_timestamp_, true, |
| 650 base::Bind(&Pipeline::OnFilterStateTransition, this)); | 666 base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 651 } | 667 } |
| 652 } | 668 } |
| 653 | 669 |
| (...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1210 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1226 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
| 1211 lock_.AssertAcquired(); | 1227 lock_.AssertAcquired(); |
| 1212 if (!waiting_for_clock_update_) | 1228 if (!waiting_for_clock_update_) |
| 1213 return; | 1229 return; |
| 1214 | 1230 |
| 1215 waiting_for_clock_update_ = false; | 1231 waiting_for_clock_update_ = false; |
| 1216 clock_->Play(); | 1232 clock_->Play(); |
| 1217 } | 1233 } |
| 1218 | 1234 |
| 1219 } // namespace media | 1235 } // namespace media |
| OLD | NEW |