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

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

Issue 10854151: Allow transitioning to HAVE_METADATA before pipeline initialization completes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase and address final comments Created 8 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
« no previous file with comments | « media/base/pipeline.h ('k') | media/base/pipeline_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/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_number_conversions.h" 16 #include "base/string_number_conversions.h"
17 #include "base/string_util.h" 17 #include "base/string_util.h"
18 #include "base/synchronization/condition_variable.h" 18 #include "base/synchronization/condition_variable.h"
19 #include "media/base/audio_decoder.h" 19 #include "media/base/audio_decoder.h"
20 #include "media/base/audio_renderer.h" 20 #include "media/base/audio_renderer.h"
21 #include "media/base/buffers.h" 21 #include "media/base/buffers.h"
22 #include "media/base/clock.h" 22 #include "media/base/clock.h"
23 #include "media/base/filter_collection.h" 23 #include "media/base/filter_collection.h"
24 #include "media/base/media_log.h" 24 #include "media/base/media_log.h"
25 #include "media/base/video_decoder.h" 25 #include "media/base/video_decoder.h"
26 #include "media/base/video_decoder_config.h"
26 #include "media/base/video_renderer.h" 27 #include "media/base/video_renderer.h"
27 28
28 using base::TimeDelta; 29 using base::TimeDelta;
29 30
30 namespace media { 31 namespace media {
31 32
32 PipelineStatusNotification::PipelineStatusNotification() 33 PipelineStatusNotification::PipelineStatusNotification()
33 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) { 34 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) {
34 } 35 }
35 36
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 DCHECK(stop_cb_.is_null()); 103 DCHECK(stop_cb_.is_null());
103 DCHECK(!seek_pending_); 104 DCHECK(!seek_pending_);
104 105
105 media_log_->AddEvent( 106 media_log_->AddEvent(
106 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); 107 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED));
107 } 108 }
108 109
109 void Pipeline::Start(scoped_ptr<FilterCollection> collection, 110 void Pipeline::Start(scoped_ptr<FilterCollection> collection,
110 const PipelineStatusCB& ended_cb, 111 const PipelineStatusCB& ended_cb,
111 const PipelineStatusCB& error_cb, 112 const PipelineStatusCB& error_cb,
112 const PipelineStatusCB& start_cb) { 113 const PipelineStatusCB& seek_cb,
114 const BufferingStateCB& buffering_state_cb) {
113 base::AutoLock auto_lock(lock_); 115 base::AutoLock auto_lock(lock_);
114 CHECK(!running_) << "Media pipeline is already running"; 116 CHECK(!running_) << "Media pipeline is already running";
117 DCHECK(!buffering_state_cb.is_null());
115 118
116 running_ = true; 119 running_ = true;
117 message_loop_->PostTask(FROM_HERE, base::Bind( 120 message_loop_->PostTask(FROM_HERE, base::Bind(
118 &Pipeline::StartTask, this, base::Passed(&collection), 121 &Pipeline::StartTask, this, base::Passed(&collection),
119 ended_cb, error_cb, start_cb)); 122 ended_cb, error_cb, seek_cb, buffering_state_cb));
120 } 123 }
121 124
122 void Pipeline::Stop(const base::Closure& stop_cb) { 125 void Pipeline::Stop(const base::Closure& stop_cb) {
123 base::AutoLock auto_lock(lock_); 126 base::AutoLock auto_lock(lock_);
124 message_loop_->PostTask(FROM_HERE, base::Bind( 127 message_loop_->PostTask(FROM_HERE, base::Bind(
125 &Pipeline::StopTask, this, stop_cb)); 128 &Pipeline::StopTask, this, stop_cb));
126 } 129 }
127 130
128 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { 131 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) {
129 base::AutoLock auto_lock(lock_); 132 base::AutoLock auto_lock(lock_);
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 void Pipeline::ReportStatus(const PipelineStatusCB& cb, PipelineStatus status) { 278 void Pipeline::ReportStatus(const PipelineStatusCB& cb, PipelineStatus status) {
276 DCHECK(message_loop_->BelongsToCurrentThread()); 279 DCHECK(message_loop_->BelongsToCurrentThread());
277 if (cb.is_null()) 280 if (cb.is_null())
278 return; 281 return;
279 cb.Run(status); 282 cb.Run(status);
280 // Prevent double-reporting of errors to clients. 283 // Prevent double-reporting of errors to clients.
281 if (status != PIPELINE_OK) 284 if (status != PIPELINE_OK)
282 error_cb_.Reset(); 285 error_cb_.Reset();
283 } 286 }
284 287
285 void Pipeline::FinishInitialization() { 288 void Pipeline::FinishSeek() {
286 DCHECK(message_loop_->BelongsToCurrentThread()); 289 DCHECK(message_loop_->BelongsToCurrentThread());
290 seek_timestamp_ = kNoTimestamp();
291 seek_pending_ = false;
292
287 // Execute the seek callback, if present. Note that this might be the 293 // Execute the seek callback, if present. Note that this might be the
288 // initial callback passed into Start(). 294 // initial callback passed into Start().
289 ReportStatus(seek_cb_, status_); 295 ReportStatus(seek_cb_, status_);
290 seek_timestamp_ = kNoTimestamp();
291 seek_cb_.Reset(); 296 seek_cb_.Reset();
292 } 297 }
293 298
294 // static 299 // static
295 bool Pipeline::TransientState(State state) { 300 bool Pipeline::TransientState(State state) {
296 return state == kPausing || 301 return state == kPausing ||
297 state == kFlushing || 302 state == kFlushing ||
298 state == kSeeking || 303 state == kSeeking ||
299 state == kStarting || 304 state == kStarting ||
300 state == kStopping; 305 state == kStopping;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 base::AutoLock auto_lock(lock_); 551 base::AutoLock auto_lock(lock_);
547 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; 552 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded;
548 statistics_.video_bytes_decoded += stats.video_bytes_decoded; 553 statistics_.video_bytes_decoded += stats.video_bytes_decoded;
549 statistics_.video_frames_decoded += stats.video_frames_decoded; 554 statistics_.video_frames_decoded += stats.video_frames_decoded;
550 statistics_.video_frames_dropped += stats.video_frames_dropped; 555 statistics_.video_frames_dropped += stats.video_frames_dropped;
551 } 556 }
552 557
553 void Pipeline::StartTask(scoped_ptr<FilterCollection> filter_collection, 558 void Pipeline::StartTask(scoped_ptr<FilterCollection> filter_collection,
554 const PipelineStatusCB& ended_cb, 559 const PipelineStatusCB& ended_cb,
555 const PipelineStatusCB& error_cb, 560 const PipelineStatusCB& error_cb,
556 const PipelineStatusCB& start_cb) { 561 const PipelineStatusCB& seek_cb,
562 const BufferingStateCB& buffering_state_cb) {
557 DCHECK(message_loop_->BelongsToCurrentThread()); 563 DCHECK(message_loop_->BelongsToCurrentThread());
558 CHECK_EQ(kCreated, state_) 564 CHECK_EQ(kCreated, state_)
559 << "Media pipeline cannot be started more than once"; 565 << "Media pipeline cannot be started more than once";
560 566
561 filter_collection_ = filter_collection.Pass(); 567 filter_collection_ = filter_collection.Pass();
562 ended_cb_ = ended_cb; 568 ended_cb_ = ended_cb;
563 error_cb_ = error_cb; 569 error_cb_ = error_cb;
564 seek_cb_ = start_cb; 570 seek_cb_ = seek_cb;
571 buffering_state_cb_ = buffering_state_cb;
565 572
566 // Kick off initialization. 573 // Kick off initialization.
567 pipeline_init_state_.reset(new PipelineInitState()); 574 pipeline_init_state_.reset(new PipelineInitState());
568 575
569 SetState(kInitDemuxer); 576 SetState(kInitDemuxer);
570 InitializeDemuxer(); 577 InitializeDemuxer();
571 } 578 }
572 579
573 // Main initialization method called on the pipeline thread. This code attempts 580 // Main initialization method called on the pipeline thread. This code attempts
574 // to use the specified filter factory to build a pipeline. 581 // to use the specified filter factory to build a pipeline.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder)) { 627 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder)) {
621 base::AutoLock auto_lock(lock_); 628 base::AutoLock auto_lock(lock_);
622 has_audio_ = true; 629 has_audio_ = true;
623 return; 630 return;
624 } 631 }
625 } 632 }
626 633
627 // Assuming audio renderer was created, create video renderer. 634 // Assuming audio renderer was created, create video renderer.
628 if (state_ == kInitAudioRenderer) { 635 if (state_ == kInitAudioRenderer) {
629 SetState(kInitVideoRenderer); 636 SetState(kInitVideoRenderer);
630 if (InitializeVideoRenderer(demuxer_->GetStream(DemuxerStream::VIDEO))) { 637 scoped_refptr<DemuxerStream> video_stream =
638 demuxer_->GetStream(DemuxerStream::VIDEO);
639 if (InitializeVideoRenderer(video_stream)) {
631 base::AutoLock auto_lock(lock_); 640 base::AutoLock auto_lock(lock_);
632 has_video_ = true; 641 has_video_ = true;
642
643 // Get an initial natural size so we have something when we signal
644 // the kHaveMetadata buffering state.
645 natural_size_ = video_stream->video_decoder_config().natural_size();
633 return; 646 return;
634 } 647 }
635 } 648 }
636 649
637 if (state_ == kInitVideoRenderer) { 650 if (state_ == kInitVideoRenderer) {
638 if (!IsPipelineOk() || !(HasAudio() || HasVideo())) { 651 if (!IsPipelineOk() || !(HasAudio() || HasVideo())) {
639 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); 652 SetError(PIPELINE_ERROR_COULD_NOT_RENDER);
640 return; 653 return;
641 } 654 }
642 655
643 // Clear initialization state now that we're done. 656 // Clear initialization state now that we're done.
644 filter_collection_.reset(); 657 filter_collection_.reset();
645 pipeline_init_state_.reset(); 658 pipeline_init_state_.reset();
646 659
647 // Initialization was successful, we are now considered paused, so it's safe 660 // Initialization was successful, we are now considered paused, so it's safe
648 // to set the initial playback rate and volume. 661 // to set the initial playback rate and volume.
649 PlaybackRateChangedTask(GetPlaybackRate()); 662 PlaybackRateChangedTask(GetPlaybackRate());
650 VolumeChangedTask(GetVolume()); 663 VolumeChangedTask(GetVolume());
651 664
665 buffering_state_cb_.Run(kHaveMetadata);
666
652 // Fire a seek request to get the renderers to preroll. We can skip a seek 667 // Fire a seek request to get the renderers to preroll. We can skip a seek
653 // here as the demuxer should be at the start of the stream. 668 // here as the demuxer should be at the start of the stream.
654 seek_pending_ = true; 669 seek_pending_ = true;
655 SetState(kSeeking); 670 SetState(kSeeking);
656 seek_timestamp_ = demuxer_->GetStartTime(); 671 seek_timestamp_ = demuxer_->GetStartTime();
657 DoSeek(seek_timestamp_, true, 672 DoSeek(seek_timestamp_, true,
658 base::Bind(&Pipeline::OnFilterStateTransition, this)); 673 base::Bind(&Pipeline::OnFilterStateTransition, this));
659 } 674 }
660 } 675 }
661 676
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
899 DoSeek(seek_timestamp_, false, 914 DoSeek(seek_timestamp_, false,
900 base::Bind(&Pipeline::OnFilterStateTransition, this)); 915 base::Bind(&Pipeline::OnFilterStateTransition, this));
901 } else if (state_ == kStarting) { 916 } else if (state_ == kStarting) {
902 DoPlay(base::Bind(&Pipeline::OnFilterStateTransition, this)); 917 DoPlay(base::Bind(&Pipeline::OnFilterStateTransition, this));
903 } else if (state_ == kStopping) { 918 } else if (state_ == kStopping) {
904 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); 919 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this));
905 } else { 920 } else {
906 NOTREACHED() << "Unexpected state: " << state_; 921 NOTREACHED() << "Unexpected state: " << state_;
907 } 922 }
908 } else if (state_ == kStarted) { 923 } else if (state_ == kStarted) {
909 FinishInitialization();
910 924
911 // Finally, complete the seek. 925 // Fire canplaythrough immediately after playback begins because of
912 seek_pending_ = false; 926 // crbug.com/106480.
927 // TODO(vrk): set ready state to HaveFutureData when bug above is fixed.
928 if (status_ == PIPELINE_OK)
929 buffering_state_cb_.Run(kPrerollCompleted);
930
931 FinishSeek();
913 932
914 // If a playback rate change was requested during a seek, do it now that 933 // If a playback rate change was requested during a seek, do it now that
915 // the seek has compelted. 934 // the seek has compelted.
916 if (playback_rate_change_pending_) { 935 if (playback_rate_change_pending_) {
917 playback_rate_change_pending_ = false; 936 playback_rate_change_pending_ = false;
918 PlaybackRateChangedTask(pending_playback_rate_); 937 PlaybackRateChangedTask(pending_playback_rate_);
919 } 938 }
920 939
921 base::AutoLock auto_lock(lock_); 940 base::AutoLock auto_lock(lock_);
922 // We use audio stream to update the clock. So if there is such a stream, 941 // We use audio stream to update the clock. So if there is such a stream,
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
1138 case kInitAudioDecoder: 1157 case kInitAudioDecoder:
1139 case kInitAudioRenderer: 1158 case kInitAudioRenderer:
1140 case kInitVideoRenderer: 1159 case kInitVideoRenderer:
1141 // Make it look like initialization was successful. 1160 // Make it look like initialization was successful.
1142 filter_collection_.reset(); 1161 filter_collection_.reset();
1143 pipeline_init_state_.reset(); 1162 pipeline_init_state_.reset();
1144 1163
1145 SetState(kStopping); 1164 SetState(kStopping);
1146 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); 1165 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this));
1147 1166
1148 FinishInitialization(); 1167 FinishSeek();
1149 break; 1168 break;
1150 1169
1151 case kPausing: 1170 case kPausing:
1152 case kSeeking: 1171 case kSeeking:
1153 case kFlushing: 1172 case kFlushing:
1154 case kStarting: 1173 case kStarting:
1155 SetState(kStopping); 1174 SetState(kStopping);
1156 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); 1175 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this));
1157 1176
1158 if (seek_pending_) { 1177 if (seek_pending_)
1159 seek_pending_ = false; 1178 FinishSeek();
1160 FinishInitialization();
1161 }
1162 1179
1163 break; 1180 break;
1164 1181
1165 case kStarted: 1182 case kStarted:
1166 SetState(kPausing); 1183 SetState(kPausing);
1167 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); 1184 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this));
1168 break; 1185 break;
1169 1186
1170 case kStopping: 1187 case kStopping:
1171 case kStopped: 1188 case kStopped:
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1218 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { 1235 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() {
1219 lock_.AssertAcquired(); 1236 lock_.AssertAcquired();
1220 if (!waiting_for_clock_update_) 1237 if (!waiting_for_clock_update_)
1221 return; 1238 return;
1222 1239
1223 waiting_for_clock_update_ = false; 1240 waiting_for_clock_update_ = false;
1224 clock_->Play(); 1241 clock_->Play();
1225 } 1242 }
1226 1243
1227 } // namespace media 1244 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline.h ('k') | media/base/pipeline_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698