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

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

Issue 2071503003: Avoid flooding main thread by caching state on media thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: adds dcheck Created 4 years, 6 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
« no previous file with comments | « media/base/pipeline_impl.h ('k') | no next file » | 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_impl.h" 5 #include "media/base/pipeline_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
(...skipping 19 matching lines...) Expand all
30 #include "media/base/video_decoder_config.h" 30 #include "media/base/video_decoder_config.h"
31 31
32 static const double kDefaultPlaybackRate = 0.0; 32 static const double kDefaultPlaybackRate = 0.0;
33 static const float kDefaultVolume = 1.0f; 33 static const float kDefaultVolume = 1.0f;
34 34
35 namespace media { 35 namespace media {
36 36
37 class PipelineImpl::RendererWrapper : public DemuxerHost, 37 class PipelineImpl::RendererWrapper : public DemuxerHost,
38 public RendererClient { 38 public RendererClient {
39 public: 39 public:
40 RendererWrapper(base::WeakPtr<PipelineImpl> weak_pipeline, 40 RendererWrapper(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
41 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
42 scoped_refptr<MediaLog> media_log); 41 scoped_refptr<MediaLog> media_log);
43 ~RendererWrapper() final; 42 ~RendererWrapper() final;
44 43
45 void Start(Demuxer* demuxer, 44 void Start(Demuxer* demuxer,
46 std::unique_ptr<Renderer> renderer, 45 std::unique_ptr<Renderer> renderer,
47 std::unique_ptr<TextRenderer> text_renderer); 46 std::unique_ptr<TextRenderer> text_renderer,
47 base::WeakPtr<PipelineImpl> weak_pipeline);
48 void Stop(const base::Closure& stop_cb); 48 void Stop(const base::Closure& stop_cb);
49 void Seek(base::TimeDelta time); 49 void Seek(base::TimeDelta time);
50 void Suspend(); 50 void Suspend();
51 void Resume(std::unique_ptr<Renderer> renderer, base::TimeDelta time); 51 void Resume(std::unique_ptr<Renderer> renderer, base::TimeDelta time);
52 void SetPlaybackRate(double playback_rate); 52 void SetPlaybackRate(double playback_rate);
53 void SetVolume(float volume); 53 void SetVolume(float volume);
54 base::TimeDelta GetMediaTime(); 54 base::TimeDelta GetMediaTime() const;
55 Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
56 bool DidLoadingProgress();
57 PipelineStatistics GetStatistics() const;
55 void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); 58 void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
56 59
57 private: 60 private:
61 // Contains state shared between main and media thread.
62 // Main thread can only read. Media thread can both - read and write.
63 // So it is not necessary to lock when reading from the media thread.
64 // This struct should only contain state that is not immediately needed by
65 // PipelineClient and can be cached on the media thread until queried.
66 // Alternatively we could cache it on the main thread by posting the
67 // notification to the main thread. But some of the state change notifications
68 // (OnStatisticsUpdate and OnBufferedTimeRangesChanged) arrive much more
69 // frequently than needed. Posting all those notifications to the main thread
70 // causes performance issues: crbug.com/619975.
71 struct SharedState {
72 // TODO(scherkus): Enforce that Renderer is only called on a single thread,
73 // even for accessing media time http://crbug.com/370634
74 std::unique_ptr<Renderer> renderer;
75
76 // True when OnBufferedTimeRangesChanged() has been called more recently
77 // than DidLoadingProgress().
78 bool did_loading_progress = false;
79
80 // Amount of available buffered data as reported by Demuxer.
81 Ranges<base::TimeDelta> buffered_time_ranges;
82
83 // Accumulated statistics reported by the renderer.
84 PipelineStatistics statistics;
85
86 // The media timestamp to return while the pipeline is suspended.
87 // Otherwise set to kNoTimestamp().
88 base::TimeDelta suspend_timestamp = kNoTimestamp();
89 };
90
58 // DemuxerHost implementaion. 91 // DemuxerHost implementaion.
59 void OnBufferedTimeRangesChanged(const Ranges<base::TimeDelta>& ranges) final; 92 void OnBufferedTimeRangesChanged(const Ranges<base::TimeDelta>& ranges) final;
60 void SetDuration(base::TimeDelta duration) final; 93 void SetDuration(base::TimeDelta duration) final;
61 void OnDemuxerError(PipelineStatus error) final; 94 void OnDemuxerError(PipelineStatus error) final;
62 void AddTextStream(DemuxerStream* text_stream, 95 void AddTextStream(DemuxerStream* text_stream,
63 const TextTrackConfig& config) final; 96 const TextTrackConfig& config) final;
64 void RemoveTextStream(DemuxerStream* text_stream) final; 97 void RemoveTextStream(DemuxerStream* text_stream) final;
65 98
66 // RendererClient implementation. 99 // RendererClient implementation.
67 void OnError(PipelineStatus error) final; 100 void OnError(PipelineStatus error) final;
(...skipping 13 matching lines...) Expand all
81 State GetNextState() const; 114 State GetNextState() const;
82 void StateTransitionTask(PipelineStatus status); 115 void StateTransitionTask(PipelineStatus status);
83 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, 116 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb,
84 CdmContext* cdm_context, 117 CdmContext* cdm_context,
85 bool success); 118 bool success);
86 void AddTextStreamTask(DemuxerStream* text_stream, 119 void AddTextStreamTask(DemuxerStream* text_stream,
87 const TextTrackConfig& config); 120 const TextTrackConfig& config);
88 void RemoveTextStreamTask(DemuxerStream* text_stream); 121 void RemoveTextStreamTask(DemuxerStream* text_stream);
89 void InitializeDemuxer(const PipelineStatusCB& done_cb); 122 void InitializeDemuxer(const PipelineStatusCB& done_cb);
90 void InitializeRenderer(const PipelineStatusCB& done_cb); 123 void InitializeRenderer(const PipelineStatusCB& done_cb);
124 void DestroyRenderer();
91 void ReportMetadata(); 125 void ReportMetadata();
92 126
93 base::WeakPtr<PipelineImpl> weak_pipeline_;
94 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; 127 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
95 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; 128 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
96 const scoped_refptr<MediaLog> media_log_; 129 const scoped_refptr<MediaLog> media_log_;
97 130
131 base::WeakPtr<PipelineImpl> weak_pipeline_;
98 Demuxer* demuxer_; 132 Demuxer* demuxer_;
99 std::unique_ptr<Renderer> renderer_;
100 std::unique_ptr<TextRenderer> text_renderer_; 133 std::unique_ptr<TextRenderer> text_renderer_;
101 double playback_rate_; 134 double playback_rate_;
102 float volume_; 135 float volume_;
103 CdmContext* cdm_context_; 136 CdmContext* cdm_context_;
104 137
105 // Lock used to serialize members - |renderer_| and |suspend_timestamp_| - 138 // Lock used to serialize |shared_state_|.
106 // accessed in GetMediaTime(), which is the only member function called on 139 mutable base::Lock shared_state_lock_;
107 // the main thread. 140
108 mutable base::Lock media_time_lock_; 141 // State shared between main and media thread.
142 SharedState shared_state_;
109 143
110 // Current state of the pipeline. 144 // Current state of the pipeline.
111 State state_; 145 State state_;
112 146
113 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that 147 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
114 // the pipeline is operating correctly. Any other value indicates that the 148 // the pipeline is operating correctly. Any other value indicates that the
115 // pipeline is stopped or is stopping. Clients can call the Stop() method to 149 // pipeline is stopped or is stopping. Clients can call the Stop() method to
116 // reset the pipeline state, and restore this to PIPELINE_OK. 150 // reset the pipeline state, and restore this to PIPELINE_OK.
117 PipelineStatus status_; 151 PipelineStatus status_;
118 152
119 // The timestamp to start playback from after starting/seeking/resuming has 153 // The timestamp to start playback from after starting/seeking/resuming has
120 // completed. 154 // completed.
121 base::TimeDelta start_timestamp_; 155 base::TimeDelta start_timestamp_;
122 156
123 // The media timestamp to return while the pipeline is suspended.
124 // Otherwise set to kNoTimestamp().
125 base::TimeDelta suspend_timestamp_;
126
127 // Whether we've received the audio/video/text ended events. 157 // Whether we've received the audio/video/text ended events.
128 bool renderer_ended_; 158 bool renderer_ended_;
129 bool text_renderer_ended_; 159 bool text_renderer_ended_;
130 160
131 // Series of tasks to Start(), Seek(), and Resume(). 161 // Series of tasks to Start(), Seek(), and Resume().
132 std::unique_ptr<SerialRunner> pending_callbacks_; 162 std::unique_ptr<SerialRunner> pending_callbacks_;
133 163
134 base::WeakPtr<RendererWrapper> weak_this_; 164 base::WeakPtr<RendererWrapper> weak_this_;
135 base::WeakPtrFactory<RendererWrapper> weak_factory_; 165 base::WeakPtrFactory<RendererWrapper> weak_factory_;
136 DISALLOW_COPY_AND_ASSIGN(RendererWrapper); 166 DISALLOW_COPY_AND_ASSIGN(RendererWrapper);
137 }; 167 };
138 168
139 PipelineImpl::PipelineImpl( 169 PipelineImpl::PipelineImpl(
140 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 170 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
141 MediaLog* media_log) 171 MediaLog* media_log)
142 : media_task_runner_(media_task_runner), 172 : media_task_runner_(media_task_runner),
143 media_log_(media_log), 173 media_log_(media_log),
144 client_(nullptr), 174 client_(nullptr),
145 playback_rate_(kDefaultPlaybackRate), 175 playback_rate_(kDefaultPlaybackRate),
146 volume_(kDefaultVolume), 176 volume_(kDefaultVolume),
147 did_loading_progress_(false),
148 weak_factory_(this) { 177 weak_factory_(this) {
149 DVLOG(2) << __FUNCTION__; 178 DVLOG(2) << __FUNCTION__;
150 renderer_wrapper_.reset(new RendererWrapper(weak_factory_.GetWeakPtr(), 179 renderer_wrapper_.reset(new RendererWrapper(media_task_runner_, media_log_));
151 media_task_runner_, media_log_));
152 } 180 }
153 181
154 PipelineImpl::~PipelineImpl() { 182 PipelineImpl::~PipelineImpl() {
155 DVLOG(2) << __FUNCTION__; 183 DVLOG(2) << __FUNCTION__;
156 DCHECK(thread_checker_.CalledOnValidThread()); 184 DCHECK(thread_checker_.CalledOnValidThread());
157 DCHECK(!client_) << "Stop() must complete before destroying object"; 185 DCHECK(!client_) << "Stop() must complete before destroying object";
158 DCHECK(seek_cb_.is_null()); 186 DCHECK(seek_cb_.is_null());
159 DCHECK(suspend_cb_.is_null()); 187 DCHECK(suspend_cb_.is_null());
160 188 DCHECK(!weak_factory_.HasWeakPtrs());
161 // Invalidate self weak pointers effectively canceling all pending
162 // notifications in the message queue.
163 // Do this before posting the DeleteSoon task to the media thread to
164 // guarantee that the WeakPtr<PipelineImpl> passed to the RendererWrapper
165 // is not invalidated on the media thread.
166 weak_factory_.InvalidateWeakPtrs();
167 189
168 // RendererWrapper is deleted on the media thread. 190 // RendererWrapper is deleted on the media thread.
169 media_task_runner_->DeleteSoon(FROM_HERE, renderer_wrapper_.release()); 191 media_task_runner_->DeleteSoon(FROM_HERE, renderer_wrapper_.release());
170 } 192 }
171 193
172 void PipelineImpl::Start(Demuxer* demuxer, 194 void PipelineImpl::Start(Demuxer* demuxer,
173 std::unique_ptr<Renderer> renderer, 195 std::unique_ptr<Renderer> renderer,
174 Client* client, 196 Client* client,
175 const PipelineStatusCB& seek_cb) { 197 const PipelineStatusCB& seek_cb) {
176 DVLOG(2) << __FUNCTION__; 198 DVLOG(2) << __FUNCTION__;
(...skipping 14 matching lines...) Expand all
191 text_renderer.reset(new TextRenderer( 213 text_renderer.reset(new TextRenderer(
192 media_task_runner_, 214 media_task_runner_,
193 BindToCurrentLoop(base::Bind(&PipelineImpl::OnAddTextTrack, 215 BindToCurrentLoop(base::Bind(&PipelineImpl::OnAddTextTrack,
194 weak_factory_.GetWeakPtr())))); 216 weak_factory_.GetWeakPtr()))));
195 } 217 }
196 218
197 media_task_runner_->PostTask( 219 media_task_runner_->PostTask(
198 FROM_HERE, 220 FROM_HERE,
199 base::Bind(&RendererWrapper::Start, 221 base::Bind(&RendererWrapper::Start,
200 base::Unretained(renderer_wrapper_.get()), demuxer, 222 base::Unretained(renderer_wrapper_.get()), demuxer,
201 base::Passed(&renderer), base::Passed(&text_renderer))); 223 base::Passed(&renderer), base::Passed(&text_renderer),
224 weak_factory_.GetWeakPtr()));
202 } 225 }
203 226
204 void PipelineImpl::Stop() { 227 void PipelineImpl::Stop() {
205 DVLOG(2) << __FUNCTION__; 228 DVLOG(2) << __FUNCTION__;
206 DCHECK(thread_checker_.CalledOnValidThread()); 229 DCHECK(thread_checker_.CalledOnValidThread());
207 230
208 if (!IsRunning()) { 231 if (!IsRunning()) {
209 DVLOG(2) << "Media pipeline isn't running. Ignoring Stop()"; 232 DVLOG(2) << "Media pipeline isn't running. Ignoring Stop()";
210 return; 233 return;
211 } 234 }
212 235
213 if (statistics_.video_frames_decoded > 0) {
214 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount",
215 statistics_.video_frames_dropped);
216 }
217
218 if (media_task_runner_->BelongsToCurrentThread()) { 236 if (media_task_runner_->BelongsToCurrentThread()) {
219 // This path is executed by unittests that share media and main threads. 237 // This path is executed by unittests that share media and main threads.
220 base::Closure stop_cb = base::Bind(&base::DoNothing); 238 base::Closure stop_cb = base::Bind(&base::DoNothing);
221 media_task_runner_->PostTask( 239 media_task_runner_->PostTask(
222 FROM_HERE, 240 FROM_HERE,
223 base::Bind(&RendererWrapper::Stop, 241 base::Bind(&RendererWrapper::Stop,
224 base::Unretained(renderer_wrapper_.get()), stop_cb)); 242 base::Unretained(renderer_wrapper_.get()), stop_cb));
225 } else { 243 } else {
226 // This path is executed by production code where the two task runners - 244 // This path is executed by production code where the two task runners -
227 // main and media - live on different threads. 245 // main and media - live on different threads.
(...skipping 16 matching lines...) Expand all
244 base::Bind(&RendererWrapper::Stop, 262 base::Bind(&RendererWrapper::Stop,
245 base::Unretained(renderer_wrapper_.get()), stop_cb))); 263 base::Unretained(renderer_wrapper_.get()), stop_cb)));
246 waiter.Wait(); 264 waiter.Wait();
247 } 265 }
248 266
249 // Once the pipeline is stopped, nothing is reported back to the client. 267 // Once the pipeline is stopped, nothing is reported back to the client.
250 // Reset all callbacks and client handle. 268 // Reset all callbacks and client handle.
251 seek_cb_.Reset(); 269 seek_cb_.Reset();
252 suspend_cb_.Reset(); 270 suspend_cb_.Reset();
253 client_ = nullptr; 271 client_ = nullptr;
272
273 // Invalidate self weak pointers effectively canceling all pending
274 // notifications in the message queue.
275 weak_factory_.InvalidateWeakPtrs();
254 } 276 }
255 277
256 void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) { 278 void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) {
257 DVLOG(2) << __FUNCTION__; 279 DVLOG(2) << __FUNCTION__;
258 DCHECK(thread_checker_.CalledOnValidThread()); 280 DCHECK(thread_checker_.CalledOnValidThread());
259 DCHECK(!seek_cb.is_null()); 281 DCHECK(!seek_cb.is_null());
260 282
261 if (!IsRunning()) { 283 if (!IsRunning()) {
262 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; 284 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek().";
263 return; 285 return;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 base::Unretained(renderer_wrapper_.get()), volume_)); 366 base::Unretained(renderer_wrapper_.get()), volume_));
345 } 367 }
346 368
347 base::TimeDelta PipelineImpl::GetMediaTime() const { 369 base::TimeDelta PipelineImpl::GetMediaTime() const {
348 DCHECK(thread_checker_.CalledOnValidThread()); 370 DCHECK(thread_checker_.CalledOnValidThread());
349 return renderer_wrapper_->GetMediaTime(); 371 return renderer_wrapper_->GetMediaTime();
350 } 372 }
351 373
352 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { 374 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const {
353 DCHECK(thread_checker_.CalledOnValidThread()); 375 DCHECK(thread_checker_.CalledOnValidThread());
354 return buffered_time_ranges_; 376 return renderer_wrapper_->GetBufferedTimeRanges();
355 } 377 }
356 378
357 base::TimeDelta PipelineImpl::GetMediaDuration() const { 379 base::TimeDelta PipelineImpl::GetMediaDuration() const {
358 DCHECK(thread_checker_.CalledOnValidThread()); 380 DCHECK(thread_checker_.CalledOnValidThread());
359 return duration_; 381 return duration_;
360 } 382 }
361 383
362 bool PipelineImpl::DidLoadingProgress() { 384 bool PipelineImpl::DidLoadingProgress() {
363 DCHECK(thread_checker_.CalledOnValidThread()); 385 DCHECK(thread_checker_.CalledOnValidThread());
364 bool ret = did_loading_progress_; 386 return renderer_wrapper_->DidLoadingProgress();
365 did_loading_progress_ = false;
366 return ret;
367 } 387 }
368 388
369 PipelineStatistics PipelineImpl::GetStatistics() const { 389 PipelineStatistics PipelineImpl::GetStatistics() const {
370 DCHECK(thread_checker_.CalledOnValidThread()); 390 DCHECK(thread_checker_.CalledOnValidThread());
371 return statistics_; 391 return renderer_wrapper_->GetStatistics();
372 } 392 }
373 393
374 void PipelineImpl::SetCdm(CdmContext* cdm_context, 394 void PipelineImpl::SetCdm(CdmContext* cdm_context,
375 const CdmAttachedCB& cdm_attached_cb) { 395 const CdmAttachedCB& cdm_attached_cb) {
376 DVLOG(2) << __FUNCTION__; 396 DVLOG(2) << __FUNCTION__;
377 DCHECK(thread_checker_.CalledOnValidThread()); 397 DCHECK(thread_checker_.CalledOnValidThread());
378 DCHECK(cdm_context); 398 DCHECK(cdm_context);
379 DCHECK(!cdm_attached_cb.is_null()); 399 DCHECK(!cdm_attached_cb.is_null());
380 400
381 media_task_runner_->PostTask( 401 media_task_runner_->PostTask(
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 if (state_ != kPlaying) 514 if (state_ != kPlaying)
495 return; 515 return;
496 516
497 DCHECK(!renderer_ended_); 517 DCHECK(!renderer_ended_);
498 renderer_ended_ = true; 518 renderer_ended_ = true;
499 RunEndedCallbackIfNeeded(); 519 RunEndedCallbackIfNeeded();
500 } 520 }
501 521
502 void PipelineImpl::RendererWrapper::OnStatisticsUpdate( 522 void PipelineImpl::RendererWrapper::OnStatisticsUpdate(
503 const PipelineStatistics& stats) { 523 const PipelineStatistics& stats) {
524 DVLOG(3) << __FUNCTION__;
504 DCHECK(media_task_runner_->BelongsToCurrentThread()); 525 DCHECK(media_task_runner_->BelongsToCurrentThread());
505 526
506 main_task_runner_->PostTask( 527 base::AutoLock auto_lock(shared_state_lock_);
507 FROM_HERE, 528 shared_state_.statistics.audio_bytes_decoded += stats.audio_bytes_decoded;
508 base::Bind(&PipelineImpl::OnStatisticsUpdate, weak_pipeline_, stats)); 529 shared_state_.statistics.video_bytes_decoded += stats.video_bytes_decoded;
530 shared_state_.statistics.video_frames_decoded += stats.video_frames_decoded;
531 shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped;
532 shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage;
533 shared_state_.statistics.video_memory_usage += stats.video_memory_usage;
509 } 534 }
510 535
511 void PipelineImpl::RendererWrapper::OnBufferingStateChange( 536 void PipelineImpl::RendererWrapper::OnBufferingStateChange(
512 BufferingState state) { 537 BufferingState state) {
513 DCHECK(media_task_runner_->BelongsToCurrentThread()); 538 DCHECK(media_task_runner_->BelongsToCurrentThread());
514 DVLOG(2) << __FUNCTION__ << "(" << state << ") "; 539 DVLOG(2) << __FUNCTION__ << "(" << state << ") ";
515 540
516 main_task_runner_->PostTask( 541 main_task_runner_->PostTask(
517 FROM_HERE, 542 FROM_HERE,
518 base::Bind(&PipelineImpl::OnBufferingStateChange, weak_pipeline_, state)); 543 base::Bind(&PipelineImpl::OnBufferingStateChange, weak_pipeline_, state));
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 // meeting 'decode' error when passing media segment but WebMediaPlayer's 615 // meeting 'decode' error when passing media segment but WebMediaPlayer's
591 // ready_state_ is still ReadyStateHaveNothing. In that case, it will 616 // ready_state_ is still ReadyStateHaveNothing. In that case, it will
592 // treat it as NetworkStateFormatError not NetworkStateDecodeError. 617 // treat it as NetworkStateFormatError not NetworkStateDecodeError.
593 ReportMetadata(); 618 ReportMetadata();
594 start_timestamp_ = demuxer_->GetStartTime(); 619 start_timestamp_ = demuxer_->GetStartTime();
595 620
596 return InitializeRenderer(done_cb); 621 return InitializeRenderer(done_cb);
597 622
598 case kPlaying: 623 case kPlaying:
599 DCHECK(start_timestamp_ >= base::TimeDelta()); 624 DCHECK(start_timestamp_ >= base::TimeDelta());
600 renderer_->StartPlayingFrom(start_timestamp_); 625 shared_state_.renderer->StartPlayingFrom(start_timestamp_);
601 { 626 {
602 base::AutoLock auto_lock(media_time_lock_); 627 base::AutoLock auto_lock(shared_state_lock_);
603 suspend_timestamp_ = kNoTimestamp(); 628 shared_state_.suspend_timestamp = kNoTimestamp();
604 } 629 }
605 630
606 if (text_renderer_) 631 if (text_renderer_)
607 text_renderer_->StartPlaying(); 632 text_renderer_->StartPlaying();
608 633
609 main_task_runner_->PostTask( 634 main_task_runner_->PostTask(
610 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_, 635 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_,
611 start_timestamp_)); 636 start_timestamp_));
612 637
613 renderer_->SetPlaybackRate(playback_rate_); 638 shared_state_.renderer->SetPlaybackRate(playback_rate_);
614 renderer_->SetVolume(volume_); 639 shared_state_.renderer->SetVolume(volume_);
615 return; 640 return;
616 641
617 case kSuspended: 642 case kSuspended:
618 renderer_.reset(); 643 DestroyRenderer();
644 {
645 base::AutoLock auto_lock(shared_state_lock_);
646 shared_state_.statistics.audio_memory_usage = 0;
647 shared_state_.statistics.video_memory_usage = 0;
648 }
619 main_task_runner_->PostTask( 649 main_task_runner_->PostTask(
620 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_, 650 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_,
621 suspend_timestamp_)); 651 shared_state_.suspend_timestamp));
622 return; 652 return;
623 653
624 case kStopping: 654 case kStopping:
625 case kStopped: 655 case kStopped:
626 case kCreated: 656 case kCreated:
627 case kSeeking: 657 case kSeeking:
628 case kSuspending: 658 case kSuspending:
629 case kResuming: 659 case kResuming:
630 NOTREACHED() << "State has no transition: " << state_; 660 NOTREACHED() << "State has no transition: " << state_;
631 return; 661 return;
(...skipping 12 matching lines...) Expand all
644 DCHECK_EQ(state_, kSeeking); 674 DCHECK_EQ(state_, kSeeking);
645 SerialRunner::Queue bound_fns; 675 SerialRunner::Queue bound_fns;
646 676
647 // Pause. 677 // Pause.
648 if (text_renderer_) { 678 if (text_renderer_) {
649 bound_fns.Push(base::Bind(&TextRenderer::Pause, 679 bound_fns.Push(base::Bind(&TextRenderer::Pause,
650 base::Unretained(text_renderer_.get()))); 680 base::Unretained(text_renderer_.get())));
651 } 681 }
652 682
653 // Flush. 683 // Flush.
654 DCHECK(renderer_); 684 DCHECK(shared_state_.renderer);
655 bound_fns.Push( 685 bound_fns.Push(base::Bind(&Renderer::Flush,
656 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); 686 base::Unretained(shared_state_.renderer.get())));
657 687
658 if (text_renderer_) { 688 if (text_renderer_) {
659 bound_fns.Push(base::Bind(&TextRenderer::Flush, 689 bound_fns.Push(base::Bind(&TextRenderer::Flush,
660 base::Unretained(text_renderer_.get()))); 690 base::Unretained(text_renderer_.get())));
661 } 691 }
662 692
663 // Seek demuxer. 693 // Seek demuxer.
664 bound_fns.Push( 694 bound_fns.Push(
665 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); 695 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
666 696
667 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 697 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
668 } 698 }
669 699
670 void PipelineImpl::RendererWrapper::DoStop(const base::Closure& done_cb) { 700 void PipelineImpl::RendererWrapper::DoStop(const base::Closure& done_cb) {
671 DVLOG(2) << __FUNCTION__; 701 DVLOG(2) << __FUNCTION__;
672 DCHECK(media_task_runner_->BelongsToCurrentThread()); 702 DCHECK(media_task_runner_->BelongsToCurrentThread());
673 DCHECK_EQ(state_, kStopping); 703 DCHECK_EQ(state_, kStopping);
674 DCHECK(!pending_callbacks_.get()); 704 DCHECK(!pending_callbacks_.get());
675 705
676 // TODO(scherkus): Enforce that Renderer is only called on a single thread, 706 DestroyRenderer();
677 // even for accessing media time http://crbug.com/370634
678 std::unique_ptr<Renderer> renderer;
679 {
680 base::AutoLock auto_lock(media_time_lock_);
681 renderer.swap(renderer_);
682 }
683 renderer.reset();
684 text_renderer_.reset(); 707 text_renderer_.reset();
685 708
686 if (demuxer_) { 709 if (demuxer_) {
687 demuxer_->Stop(); 710 demuxer_->Stop();
688 demuxer_ = NULL; 711 demuxer_ = NULL;
689 } 712 }
690 713
691 SetState(kStopped); 714 SetState(kStopped);
692 715
693 // Post the stop callback to enqueue it after the tasks that may have been 716 // Post the stop callback to enqueue it after the tasks that may have been
694 // posted by Demuxer and Renderer during stopping. Note that in theory the 717 // posted by Demuxer and Renderer during stopping. Note that in theory the
695 // tasks posted by Demuxer/Renderer may post even more tasks that will get 718 // tasks posted by Demuxer/Renderer may post even more tasks that will get
696 // enqueued after |done_cb|. This may be problematic because Demuxer may 719 // enqueued after |done_cb|. This may be problematic because Demuxer may
697 // get destroyed as soon as |done_cb| is run. In practice this is not a 720 // get destroyed as soon as |done_cb| is run. In practice this is not a
698 // problem, but ideally Demuxer should be destroyed on the media thread. 721 // problem, but ideally Demuxer should be destroyed on the media thread.
699 media_task_runner_->PostTask(FROM_HERE, done_cb); 722 media_task_runner_->PostTask(FROM_HERE, done_cb);
700 } 723 }
701 724
702 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged( 725 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged(
703 const Ranges<base::TimeDelta>& ranges) { 726 const Ranges<base::TimeDelta>& ranges) {
704 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer 727 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
705 // implementations call DemuxerHost on the media thread. 728 // implementations call DemuxerHost on the media thread.
706 main_task_runner_->PostTask( 729 base::AutoLock auto_lock(shared_state_lock_);
707 FROM_HERE, base::Bind(&PipelineImpl::OnBufferedTimeRangesChange, 730 shared_state_.did_loading_progress = true;
708 weak_pipeline_, ranges)); 731 shared_state_.buffered_time_ranges = ranges;
709 } 732 }
710 733
711 void PipelineImpl::RendererWrapper::Start( 734 void PipelineImpl::RendererWrapper::Start(
712 Demuxer* demuxer, 735 Demuxer* demuxer,
713 std::unique_ptr<Renderer> renderer, 736 std::unique_ptr<Renderer> renderer,
714 std::unique_ptr<TextRenderer> text_renderer) { 737 std::unique_ptr<TextRenderer> text_renderer,
738 base::WeakPtr<PipelineImpl> weak_pipeline) {
715 DCHECK(media_task_runner_->BelongsToCurrentThread()); 739 DCHECK(media_task_runner_->BelongsToCurrentThread());
716 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: " 740 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: "
717 << state_; 741 << state_;
718 742
719 DCHECK(!demuxer_); 743 DCHECK(!demuxer_);
720 DCHECK(!renderer_); 744 DCHECK(!shared_state_.renderer);
721 DCHECK(!text_renderer_); 745 DCHECK(!text_renderer_);
722 DCHECK(!renderer_ended_); 746 DCHECK(!renderer_ended_);
723 DCHECK(!text_renderer_ended_); 747 DCHECK(!text_renderer_ended_);
748 DCHECK(!weak_pipeline_);
724 demuxer_ = demuxer; 749 demuxer_ = demuxer;
725 { 750 {
726 base::AutoLock auto_lock(media_time_lock_); 751 base::AutoLock auto_lock(shared_state_lock_);
727 renderer_ = std::move(renderer); 752 shared_state_.renderer = std::move(renderer);
728 } 753 }
729 text_renderer_ = std::move(text_renderer); 754 text_renderer_ = std::move(text_renderer);
730 if (text_renderer_) { 755 if (text_renderer_) {
731 text_renderer_->Initialize( 756 text_renderer_->Initialize(
732 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_)); 757 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_));
733 } 758 }
759 weak_pipeline_ = weak_pipeline;
734 760
735 StateTransitionTask(PIPELINE_OK); 761 StateTransitionTask(PIPELINE_OK);
736 } 762 }
737 763
738 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) { 764 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) {
739 DCHECK(media_task_runner_->BelongsToCurrentThread()); 765 DCHECK(media_task_runner_->BelongsToCurrentThread());
740 DCHECK(state_ != kStopping && state_ != kStopped); 766 DCHECK(state_ != kStopping && state_ != kStopped);
741 767
742 SetState(kStopping); 768 SetState(kStopping);
743 769
770 if (shared_state_.statistics.video_frames_decoded > 0) {
771 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount",
772 shared_state_.statistics.video_frames_dropped);
773 }
774
744 // If we stop during starting/seeking/suspending/resuming we don't want to 775 // If we stop during starting/seeking/suspending/resuming we don't want to
745 // leave outstanding callbacks around. The callbacks also do not get run if 776 // leave outstanding callbacks around. The callbacks also do not get run if
746 // the pipeline is stopped before it had a chance to complete outstanding 777 // the pipeline is stopped before it had a chance to complete outstanding
747 // tasks. 778 // tasks.
748 pending_callbacks_.reset(); 779 pending_callbacks_.reset();
749 780
750 DoStop(stop_cb); 781 DoStop(stop_cb);
751 } 782 }
752 783
753 void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) { 784 void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) {
(...skipping 18 matching lines...) Expand all
772 status_ = error; 803 status_ = error;
773 main_task_runner_->PostTask( 804 main_task_runner_->PostTask(
774 FROM_HERE, base::Bind(&PipelineImpl::OnError, weak_pipeline_, error)); 805 FROM_HERE, base::Bind(&PipelineImpl::OnError, weak_pipeline_, error));
775 } 806 }
776 807
777 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) { 808 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) {
778 DCHECK(media_task_runner_->BelongsToCurrentThread()); 809 DCHECK(media_task_runner_->BelongsToCurrentThread());
779 810
780 playback_rate_ = playback_rate; 811 playback_rate_ = playback_rate;
781 if (state_ == kPlaying) 812 if (state_ == kPlaying)
782 renderer_->SetPlaybackRate(playback_rate_); 813 shared_state_.renderer->SetPlaybackRate(playback_rate_);
783 } 814 }
784 815
785 void PipelineImpl::RendererWrapper::SetVolume(float volume) { 816 void PipelineImpl::RendererWrapper::SetVolume(float volume) {
786 DCHECK(media_task_runner_->BelongsToCurrentThread()); 817 DCHECK(media_task_runner_->BelongsToCurrentThread());
787 818
788 volume_ = volume; 819 volume_ = volume;
789 if (state_ == kPlaying) 820 if (state_ == kPlaying)
790 renderer_->SetVolume(volume_); 821 shared_state_.renderer->SetVolume(volume_);
791 } 822 }
792 823
793 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) { 824 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) {
794 DCHECK(media_task_runner_->BelongsToCurrentThread()); 825 DCHECK(media_task_runner_->BelongsToCurrentThread());
795 826
796 // Suppress seeking if we're not fully started. 827 // Suppress seeking if we're not fully started.
797 if (state_ != kPlaying) { 828 if (state_ != kPlaying) {
798 DCHECK(state_ == kStopping || state_ == kStopped) 829 DCHECK(state_ == kStopping || state_ == kStopped)
799 << "Receive seek in unexpected state: " << state_; 830 << "Receive seek in unexpected state: " << state_;
800 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 831 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
(...skipping 15 matching lines...) Expand all
816 void PipelineImpl::RendererWrapper::Suspend() { 847 void PipelineImpl::RendererWrapper::Suspend() {
817 DCHECK(media_task_runner_->BelongsToCurrentThread()); 848 DCHECK(media_task_runner_->BelongsToCurrentThread());
818 849
819 // Suppress suspending if we're not playing. 850 // Suppress suspending if we're not playing.
820 if (state_ != kPlaying) { 851 if (state_ != kPlaying) {
821 DCHECK(state_ == kStopping || state_ == kStopped) 852 DCHECK(state_ == kStopping || state_ == kStopped)
822 << "Receive suspend in unexpected state: " << state_; 853 << "Receive suspend in unexpected state: " << state_;
823 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 854 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
824 return; 855 return;
825 } 856 }
826 DCHECK(renderer_); 857 DCHECK(shared_state_.renderer);
827 DCHECK(!pending_callbacks_.get()); 858 DCHECK(!pending_callbacks_.get());
828 859
829 SetState(kSuspending); 860 SetState(kSuspending);
830 861
831 // Freeze playback and record the media time before flushing. (Flushing clears 862 // Freeze playback and record the media time before flushing. (Flushing clears
832 // the value.) 863 // the value.)
833 renderer_->SetPlaybackRate(0.0); 864 shared_state_.renderer->SetPlaybackRate(0.0);
834 { 865 {
835 base::AutoLock auto_lock(media_time_lock_); 866 base::AutoLock auto_lock(shared_state_lock_);
836 suspend_timestamp_ = renderer_->GetMediaTime(); 867 shared_state_.suspend_timestamp = shared_state_.renderer->GetMediaTime();
837 DCHECK(suspend_timestamp_ != kNoTimestamp()); 868 DCHECK(shared_state_.suspend_timestamp != kNoTimestamp());
838 } 869 }
839 870
840 // Queue the asynchronous actions required to stop playback. (Matches setup in 871 // Queue the asynchronous actions required to stop playback. (Matches setup in
841 // DoSeek().) 872 // DoSeek().)
842 // TODO(sandersd): Share implementation with DoSeek(). 873 // TODO(sandersd): Share implementation with DoSeek().
843 SerialRunner::Queue fns; 874 SerialRunner::Queue fns;
844 875
845 if (text_renderer_) { 876 if (text_renderer_) {
846 fns.Push(base::Bind(&TextRenderer::Pause, 877 fns.Push(base::Bind(&TextRenderer::Pause,
847 base::Unretained(text_renderer_.get()))); 878 base::Unretained(text_renderer_.get())));
848 } 879 }
849 880
850 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); 881 fns.Push(base::Bind(&Renderer::Flush,
882 base::Unretained(shared_state_.renderer.get())));
851 883
852 if (text_renderer_) { 884 if (text_renderer_) {
853 fns.Push(base::Bind(&TextRenderer::Flush, 885 fns.Push(base::Bind(&TextRenderer::Flush,
854 base::Unretained(text_renderer_.get()))); 886 base::Unretained(text_renderer_.get())));
855 } 887 }
856 888
857 pending_callbacks_ = SerialRunner::Run( 889 pending_callbacks_ = SerialRunner::Run(
858 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_)); 890 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_));
859 } 891 }
860 892
861 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer, 893 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer,
862 base::TimeDelta timestamp) { 894 base::TimeDelta timestamp) {
863 DCHECK(media_task_runner_->BelongsToCurrentThread()); 895 DCHECK(media_task_runner_->BelongsToCurrentThread());
864 896
865 // Suppress resuming if we're not suspended. 897 // Suppress resuming if we're not suspended.
866 if (state_ != kSuspended) { 898 if (state_ != kSuspended) {
867 DCHECK(state_ == kStopping || state_ == kStopped) 899 DCHECK(state_ == kStopping || state_ == kStopped)
868 << "Receive resume in unexpected state: " << state_; 900 << "Receive resume in unexpected state: " << state_;
869 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 901 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
870 return; 902 return;
871 } 903 }
872 DCHECK(!renderer_); 904 DCHECK(!shared_state_.renderer);
873 DCHECK(!pending_callbacks_.get()); 905 DCHECK(!pending_callbacks_.get());
874 906
875 SetState(kResuming); 907 SetState(kResuming);
876 908
877 { 909 {
878 base::AutoLock auto_lock(media_time_lock_); 910 base::AutoLock auto_lock(shared_state_lock_);
879 renderer_ = std::move(renderer); 911 shared_state_.renderer = std::move(renderer);
880 } 912 }
881 913
882 // Set up for a seek. (Matches setup in SeekTask().) 914 // Set up for a seek. (Matches setup in SeekTask().)
883 // TODO(sandersd): Share implementation with SeekTask(). 915 // TODO(sandersd): Share implementation with SeekTask().
884 renderer_ended_ = false; 916 renderer_ended_ = false;
885 text_renderer_ended_ = false; 917 text_renderer_ended_ = false;
886 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime()); 918 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime());
887 919
888 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), 920 // Queue the asynchronous actions required to start playback. Unlike DoSeek(),
889 // we need to initialize the renderer ourselves (we don't want to enter state 921 // we need to initialize the renderer ourselves (we don't want to enter state
890 // kInitDemuxer, and even if we did the current code would seek to the start 922 // kInitDemuxer, and even if we did the current code would seek to the start
891 // instead of |timestamp|). 923 // instead of |timestamp|).
892 SerialRunner::Queue fns; 924 SerialRunner::Queue fns;
893 925
894 fns.Push( 926 fns.Push(
895 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); 927 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_));
896 928
897 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); 929 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_));
898 930
899 pending_callbacks_ = SerialRunner::Run( 931 pending_callbacks_ = SerialRunner::Run(
900 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_)); 932 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_));
901 } 933 }
902 934
935 Ranges<base::TimeDelta> PipelineImpl::RendererWrapper::GetBufferedTimeRanges()
936 const {
937 DCHECK(main_task_runner_->BelongsToCurrentThread());
938
939 base::AutoLock auto_lock(shared_state_lock_);
940 return shared_state_.buffered_time_ranges;
941 }
942
943 bool PipelineImpl::RendererWrapper::DidLoadingProgress() {
944 DCHECK(main_task_runner_->BelongsToCurrentThread());
945
946 base::AutoLock auto_lock(shared_state_lock_);
947 bool did_progress = shared_state_.did_loading_progress;
948 shared_state_.did_loading_progress = false;
949 return did_progress;
950 }
951
952 PipelineStatistics PipelineImpl::RendererWrapper::GetStatistics() const {
953 DCHECK(main_task_runner_->BelongsToCurrentThread());
954
955 base::AutoLock auto_lock(shared_state_lock_);
956 return shared_state_.statistics;
957 }
958
903 void PipelineImpl::RendererWrapper::SetCdm( 959 void PipelineImpl::RendererWrapper::SetCdm(
904 CdmContext* cdm_context, 960 CdmContext* cdm_context,
905 const CdmAttachedCB& cdm_attached_cb) { 961 const CdmAttachedCB& cdm_attached_cb) {
906 DCHECK(media_task_runner_->BelongsToCurrentThread()); 962 DCHECK(media_task_runner_->BelongsToCurrentThread());
907 963
908 if (!renderer_) { 964 if (!shared_state_.renderer) {
909 cdm_context_ = cdm_context; 965 cdm_context_ = cdm_context;
910 cdm_attached_cb.Run(true); 966 cdm_attached_cb.Run(true);
911 return; 967 return;
912 } 968 }
913 969
914 renderer_->SetCdm(cdm_context, 970 shared_state_.renderer->SetCdm(
915 base::Bind(&RendererWrapper::OnCdmAttached, weak_this_, 971 cdm_context, base::Bind(&RendererWrapper::OnCdmAttached, weak_this_,
916 cdm_attached_cb, cdm_context)); 972 cdm_attached_cb, cdm_context));
917 } 973 }
918 974
919 void PipelineImpl::RendererWrapper::OnCdmAttached( 975 void PipelineImpl::RendererWrapper::OnCdmAttached(
920 const CdmAttachedCB& cdm_attached_cb, 976 const CdmAttachedCB& cdm_attached_cb,
921 CdmContext* cdm_context, 977 CdmContext* cdm_context,
922 bool success) { 978 bool success) {
923 DCHECK(media_task_runner_->BelongsToCurrentThread()); 979 DCHECK(media_task_runner_->BelongsToCurrentThread());
924 980
925 if (success) 981 if (success)
926 cdm_context_ = cdm_context; 982 cdm_context_ = cdm_context;
927 cdm_attached_cb.Run(success); 983 cdm_attached_cb.Run(success);
928 } 984 }
929 985
930 void PipelineImpl::RendererWrapper::OnTextRendererEnded() { 986 void PipelineImpl::RendererWrapper::OnTextRendererEnded() {
931 DCHECK(media_task_runner_->BelongsToCurrentThread()); 987 DCHECK(media_task_runner_->BelongsToCurrentThread());
932 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); 988 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
933 989
934 if (state_ != kPlaying) 990 if (state_ != kPlaying)
935 return; 991 return;
936 992
937 DCHECK(!text_renderer_ended_); 993 DCHECK(!text_renderer_ended_);
938 text_renderer_ended_ = true; 994 text_renderer_ended_ = true;
939 995
940 RunEndedCallbackIfNeeded(); 996 RunEndedCallbackIfNeeded();
941 } 997 }
942 998
943 void PipelineImpl::RendererWrapper::RunEndedCallbackIfNeeded() { 999 void PipelineImpl::RendererWrapper::RunEndedCallbackIfNeeded() {
944 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1000 DCHECK(media_task_runner_->BelongsToCurrentThread());
945 1001
946 if (renderer_ && !renderer_ended_) 1002 if (shared_state_.renderer && !renderer_ended_)
947 return; 1003 return;
948 1004
949 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) 1005 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_)
950 return; 1006 return;
951 1007
952 DCHECK_EQ(status_, PIPELINE_OK); 1008 DCHECK_EQ(status_, PIPELINE_OK);
953 main_task_runner_->PostTask( 1009 main_task_runner_->PostTask(
954 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_)); 1010 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_));
955 } 1011 }
956 1012
(...skipping 27 matching lines...) Expand all
984 const PipelineStatusCB& done_cb) { 1040 const PipelineStatusCB& done_cb) {
985 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1041 DCHECK(media_task_runner_->BelongsToCurrentThread());
986 1042
987 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && 1043 if (!demuxer_->GetStream(DemuxerStream::AUDIO) &&
988 !demuxer_->GetStream(DemuxerStream::VIDEO)) { 1044 !demuxer_->GetStream(DemuxerStream::VIDEO)) {
989 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); 1045 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER);
990 return; 1046 return;
991 } 1047 }
992 1048
993 if (cdm_context_) 1049 if (cdm_context_)
994 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); 1050 shared_state_.renderer->SetCdm(cdm_context_,
1051 base::Bind(&IgnoreCdmAttached));
995 1052
996 renderer_->Initialize(demuxer_, this, done_cb); 1053 shared_state_.renderer->Initialize(demuxer_, this, done_cb);
1054 }
1055
1056 void PipelineImpl::RendererWrapper::DestroyRenderer() {
1057 DCHECK(media_task_runner_->BelongsToCurrentThread());
1058
1059 // Destroy the renderer outside the lock scope to avoid holding the lock
1060 // while renderer is being destroyed (in case Renderer destructor is costly).
1061 std::unique_ptr<Renderer> renderer;
1062 {
1063 base::AutoLock auto_lock(shared_state_lock_);
1064 renderer.swap(shared_state_.renderer);
1065 }
997 } 1066 }
998 1067
999 void PipelineImpl::RendererWrapper::ReportMetadata() { 1068 void PipelineImpl::RendererWrapper::ReportMetadata() {
1000 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1069 DCHECK(media_task_runner_->BelongsToCurrentThread());
1001 1070
1002 PipelineMetadata metadata; 1071 PipelineMetadata metadata;
1003 metadata.timeline_offset = demuxer_->GetTimelineOffset(); 1072 metadata.timeline_offset = demuxer_->GetTimelineOffset();
1004 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 1073 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
1005 if (stream) { 1074 if (stream) {
1006 metadata.has_video = true; 1075 metadata.has_video = true;
1007 metadata.natural_size = stream->video_decoder_config().natural_size(); 1076 metadata.natural_size = stream->video_decoder_config().natural_size();
1008 metadata.video_rotation = stream->video_rotation(); 1077 metadata.video_rotation = stream->video_rotation();
1009 } 1078 }
1010 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { 1079 if (demuxer_->GetStream(DemuxerStream::AUDIO)) {
1011 metadata.has_audio = true; 1080 metadata.has_audio = true;
1012 } 1081 }
1013 1082
1014 main_task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::OnMetadata, 1083 main_task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::OnMetadata,
1015 weak_pipeline_, metadata)); 1084 weak_pipeline_, metadata));
1016 } 1085 }
1017 1086
1018 void PipelineImpl::OnError(PipelineStatus error) { 1087 void PipelineImpl::OnError(PipelineStatus error) {
1019 DVLOG(2) << __FUNCTION__; 1088 DVLOG(2) << __FUNCTION__;
1020 DCHECK(thread_checker_.CalledOnValidThread()); 1089 DCHECK(thread_checker_.CalledOnValidThread());
1021 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; 1090 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
1022 1091 DCHECK(IsRunning());
1023 if (!IsRunning())
1024 return;
1025 1092
1026 // If the error happens during starting/seeking/suspending/resuming, 1093 // If the error happens during starting/seeking/suspending/resuming,
1027 // report the error via the completion callback for those tasks. 1094 // report the error via the completion callback for those tasks.
1028 // Else report error via the client interface. 1095 // Else report error via the client interface.
1029 if (!seek_cb_.is_null()) { 1096 if (!seek_cb_.is_null()) {
1030 base::ResetAndReturn(&seek_cb_).Run(error); 1097 base::ResetAndReturn(&seek_cb_).Run(error);
1031 } else if (!suspend_cb_.is_null()) { 1098 } else if (!suspend_cb_.is_null()) {
1032 base::ResetAndReturn(&suspend_cb_).Run(error); 1099 base::ResetAndReturn(&suspend_cb_).Run(error);
1033 } else { 1100 } else {
1034 DCHECK(client_); 1101 DCHECK(client_);
1035 client_->OnError(error); 1102 client_->OnError(error);
1036 } 1103 }
1037 1104
1038 // Any kind of error stops the pipeline. 1105 // Any kind of error stops the pipeline.
1039 Stop(); 1106 Stop();
1040 } 1107 }
1041 1108
1042 void PipelineImpl::OnEnded() { 1109 void PipelineImpl::OnEnded() {
1043 DVLOG(2) << __FUNCTION__; 1110 DVLOG(2) << __FUNCTION__;
1044 DCHECK(thread_checker_.CalledOnValidThread()); 1111 DCHECK(thread_checker_.CalledOnValidThread());
1112 DCHECK(IsRunning());
1045 1113
1046 if (IsRunning()) { 1114 DCHECK(client_);
1047 DCHECK(client_); 1115 client_->OnEnded();
1048 client_->OnEnded();
1049 }
1050 } 1116 }
1051 1117
1052 void PipelineImpl::OnMetadata(PipelineMetadata metadata) { 1118 void PipelineImpl::OnMetadata(PipelineMetadata metadata) {
1053 DVLOG(2) << __FUNCTION__; 1119 DVLOG(2) << __FUNCTION__;
1054 DCHECK(thread_checker_.CalledOnValidThread()); 1120 DCHECK(thread_checker_.CalledOnValidThread());
1121 DCHECK(IsRunning());
1055 1122
1056 if (IsRunning()) { 1123 DCHECK(client_);
1057 DCHECK(client_); 1124 client_->OnMetadata(metadata);
1058 client_->OnMetadata(metadata);
1059 }
1060 } 1125 }
1061 1126
1062 void PipelineImpl::OnBufferingStateChange(BufferingState state) { 1127 void PipelineImpl::OnBufferingStateChange(BufferingState state) {
1063 DVLOG(2) << __FUNCTION__ << "(" << state << ")"; 1128 DVLOG(2) << __FUNCTION__ << "(" << state << ")";
1064 DCHECK(thread_checker_.CalledOnValidThread()); 1129 DCHECK(thread_checker_.CalledOnValidThread());
1130 DCHECK(IsRunning());
1065 1131
1066 if (IsRunning()) { 1132 DCHECK(client_);
1067 DCHECK(client_); 1133 client_->OnBufferingStateChange(state);
1068 client_->OnBufferingStateChange(state);
1069 }
1070 } 1134 }
1071 1135
1072 void PipelineImpl::OnDurationChange(base::TimeDelta duration) { 1136 void PipelineImpl::OnDurationChange(base::TimeDelta duration) {
1073 DVLOG(2) << __FUNCTION__; 1137 DVLOG(2) << __FUNCTION__;
1074 DCHECK(thread_checker_.CalledOnValidThread()); 1138 DCHECK(thread_checker_.CalledOnValidThread());
1139 DCHECK(IsRunning());
1075 1140
1076 duration_ = duration; 1141 duration_ = duration;
1077 1142
1078 if (IsRunning()) { 1143 DCHECK(client_);
1079 DCHECK(client_); 1144 client_->OnDurationChange();
1080 client_->OnDurationChange();
1081 }
1082 } 1145 }
1083 1146
1084 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, 1147 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config,
1085 const AddTextTrackDoneCB& done_cb) { 1148 const AddTextTrackDoneCB& done_cb) {
1086 DVLOG(2) << __FUNCTION__; 1149 DVLOG(2) << __FUNCTION__;
1087 DCHECK(thread_checker_.CalledOnValidThread()); 1150 DCHECK(thread_checker_.CalledOnValidThread());
1151 DCHECK(IsRunning());
1088 1152
1089 if (IsRunning()) { 1153 DCHECK(client_);
1090 DCHECK(client_); 1154 client_->OnAddTextTrack(config, done_cb);
1091 client_->OnAddTextTrack(config, done_cb);
1092 }
1093 } 1155 }
1094 1156
1095 void PipelineImpl::OnWaitingForDecryptionKey() { 1157 void PipelineImpl::OnWaitingForDecryptionKey() {
1096 DVLOG(2) << __FUNCTION__; 1158 DVLOG(2) << __FUNCTION__;
1097 DCHECK(thread_checker_.CalledOnValidThread()); 1159 DCHECK(thread_checker_.CalledOnValidThread());
1160 DCHECK(IsRunning());
1098 1161
1099 if (IsRunning()) { 1162 DCHECK(client_);
1100 DCHECK(client_); 1163 client_->OnWaitingForDecryptionKey();
1101 client_->OnWaitingForDecryptionKey();
1102 }
1103 } 1164 }
1104 1165
1105 void PipelineImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { 1166 void PipelineImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1106 DVLOG(2) << __FUNCTION__; 1167 DVLOG(2) << __FUNCTION__;
1107 DCHECK(thread_checker_.CalledOnValidThread()); 1168 DCHECK(thread_checker_.CalledOnValidThread());
1169 DCHECK(IsRunning());
1108 1170
1109 if (IsRunning()) { 1171 DCHECK(client_);
1110 DCHECK(client_); 1172 client_->OnVideoNaturalSizeChange(size);
1111 client_->OnVideoNaturalSizeChange(size);
1112 }
1113 } 1173 }
1114 1174
1115 void PipelineImpl::OnVideoOpacityChange(bool opaque) { 1175 void PipelineImpl::OnVideoOpacityChange(bool opaque) {
1116 DVLOG(2) << __FUNCTION__; 1176 DVLOG(2) << __FUNCTION__;
1117 DCHECK(thread_checker_.CalledOnValidThread()); 1177 DCHECK(thread_checker_.CalledOnValidThread());
1178 DCHECK(IsRunning());
1118 1179
1119 if (IsRunning()) { 1180 DCHECK(client_);
1120 DCHECK(client_); 1181 client_->OnVideoOpacityChange(opaque);
1121 client_->OnVideoOpacityChange(opaque);
1122 }
1123 }
1124
1125 void PipelineImpl::OnBufferedTimeRangesChange(
1126 const Ranges<base::TimeDelta>& ranges) {
1127 DVLOG(3) << __FUNCTION__;
1128 DCHECK(thread_checker_.CalledOnValidThread());
1129
1130 buffered_time_ranges_ = ranges;
1131 did_loading_progress_ = true;
1132 }
1133
1134 void PipelineImpl::OnStatisticsUpdate(const PipelineStatistics& stats) {
1135 DVLOG(3) << __FUNCTION__;
1136 DCHECK(thread_checker_.CalledOnValidThread());
1137
1138 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded;
1139 statistics_.video_bytes_decoded += stats.video_bytes_decoded;
1140 statistics_.video_frames_decoded += stats.video_frames_decoded;
1141 statistics_.video_frames_dropped += stats.video_frames_dropped;
1142 statistics_.audio_memory_usage += stats.audio_memory_usage;
1143 statistics_.video_memory_usage += stats.video_memory_usage;
1144 } 1182 }
1145 1183
1146 void PipelineImpl::OnSeekDone(base::TimeDelta start_time) { 1184 void PipelineImpl::OnSeekDone(base::TimeDelta start_time) {
1147 DVLOG(3) << __FUNCTION__ << "(" << start_time.InMicroseconds() << ")"; 1185 DVLOG(3) << __FUNCTION__ << "(" << start_time.InMicroseconds() << ")";
1148 DCHECK(thread_checker_.CalledOnValidThread()); 1186 DCHECK(thread_checker_.CalledOnValidThread());
1187 DCHECK(IsRunning());
1149 1188
1150 if (IsRunning()) { 1189 DCHECK(!seek_cb_.is_null());
1151 DCHECK(!seek_cb_.is_null()); 1190 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1152 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1153 }
1154 } 1191 }
1155 1192
1156 void PipelineImpl::OnSuspendDone(base::TimeDelta suspend_time) { 1193 void PipelineImpl::OnSuspendDone(base::TimeDelta suspend_time) {
1157 DVLOG(3) << __FUNCTION__ << "(" << suspend_time.InMicroseconds() << ")"; 1194 DVLOG(3) << __FUNCTION__ << "(" << suspend_time.InMicroseconds() << ")";
1158 DCHECK(thread_checker_.CalledOnValidThread()); 1195 DCHECK(thread_checker_.CalledOnValidThread());
1196 DCHECK(IsRunning());
1159 1197
1160 // Reset audio-video memory usage since renderer has been destroyed. 1198 DCHECK(!suspend_cb_.is_null());
1161 statistics_.audio_memory_usage = 0; 1199 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK);
1162 statistics_.video_memory_usage = 0;
1163
1164 if (IsRunning()) {
1165 DCHECK(!suspend_cb_.is_null());
1166 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK);
1167 }
1168 } 1200 }
1169 1201
1170 PipelineImpl::RendererWrapper::RendererWrapper( 1202 PipelineImpl::RendererWrapper::RendererWrapper(
1171 base::WeakPtr<PipelineImpl> weak_pipeline,
1172 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, 1203 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
1173 scoped_refptr<MediaLog> media_log) 1204 scoped_refptr<MediaLog> media_log)
1174 : weak_pipeline_(weak_pipeline), 1205 : media_task_runner_(std::move(media_task_runner)),
1175 media_task_runner_(std::move(media_task_runner)),
1176 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), 1206 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
1177 media_log_(std::move(media_log)), 1207 media_log_(std::move(media_log)),
1178 demuxer_(nullptr), 1208 demuxer_(nullptr),
1179 playback_rate_(kDefaultPlaybackRate), 1209 playback_rate_(kDefaultPlaybackRate),
1180 volume_(kDefaultVolume), 1210 volume_(kDefaultVolume),
1181 cdm_context_(nullptr), 1211 cdm_context_(nullptr),
1182 state_(kCreated), 1212 state_(kCreated),
1183 status_(PIPELINE_OK), 1213 status_(PIPELINE_OK),
1184 suspend_timestamp_(kNoTimestamp()),
1185 renderer_ended_(false), 1214 renderer_ended_(false),
1186 text_renderer_ended_(false), 1215 text_renderer_ended_(false),
1187 weak_factory_(this) { 1216 weak_factory_(this) {
1188 weak_this_ = weak_factory_.GetWeakPtr(); 1217 weak_this_ = weak_factory_.GetWeakPtr();
1189 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 1218 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
1190 } 1219 }
1191 1220
1192 PipelineImpl::RendererWrapper::~RendererWrapper() { 1221 PipelineImpl::RendererWrapper::~RendererWrapper() {
1193 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1222 DCHECK(media_task_runner_->BelongsToCurrentThread());
1194 DCHECK(state_ == kCreated || state_ == kStopped); 1223 DCHECK(state_ == kCreated || state_ == kStopped);
1195 } 1224 }
1196 1225
1197 base::TimeDelta PipelineImpl::RendererWrapper::GetMediaTime() { 1226 base::TimeDelta PipelineImpl::RendererWrapper::GetMediaTime() const {
1198 // This is the only member function that gets called on the main thread.
1199 // TODO(alokp): Enforce that Renderer is only called on a single thread,
1200 // even for accessing media time http://crbug.com/370634.
1201 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1227 DCHECK(main_task_runner_->BelongsToCurrentThread());
1202 1228
1203 base::AutoLock auto_lock(media_time_lock_); 1229 base::AutoLock auto_lock(shared_state_lock_);
1204 if (suspend_timestamp_ != kNoTimestamp()) 1230 if (shared_state_.suspend_timestamp != kNoTimestamp())
1205 return suspend_timestamp_; 1231 return shared_state_.suspend_timestamp;
1206 return renderer_ ? renderer_->GetMediaTime() : base::TimeDelta(); 1232 return shared_state_.renderer ? shared_state_.renderer->GetMediaTime()
1233 : base::TimeDelta();
1207 } 1234 }
1208 1235
1209 } // namespace media 1236 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698