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

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

Powered by Google App Engine
This is Rietveld 408576698