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

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: reverts reseting callbacks 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 44
45 void Start(Demuxer* demuxer, 45 void Start(Demuxer* demuxer,
46 std::unique_ptr<Renderer> renderer, 46 std::unique_ptr<Renderer> renderer,
47 std::unique_ptr<TextRenderer> text_renderer); 47 std::unique_ptr<TextRenderer> text_renderer);
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_; 127 base::WeakPtr<PipelineImpl> weak_pipeline_;
94 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; 128 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
95 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; 129 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
96 const scoped_refptr<MediaLog> media_log_; 130 const scoped_refptr<MediaLog> media_log_;
97 131
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(weak_factory_.GetWeakPtr(),
151 media_task_runner_, media_log_)); 180 media_task_runner_, media_log_));
152 } 181 }
153 182
154 PipelineImpl::~PipelineImpl() { 183 PipelineImpl::~PipelineImpl() {
155 DVLOG(2) << __FUNCTION__; 184 DVLOG(2) << __FUNCTION__;
156 DCHECK(thread_checker_.CalledOnValidThread()); 185 DCHECK(thread_checker_.CalledOnValidThread());
157 DCHECK(!client_) << "Stop() must complete before destroying object"; 186 DCHECK(!client_) << "Stop() must complete before destroying object";
158 DCHECK(seek_cb_.is_null()); 187 DCHECK(seek_cb_.is_null());
159 DCHECK(suspend_cb_.is_null()); 188 DCHECK(suspend_cb_.is_null());
160 189
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
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__;
177 DCHECK(thread_checker_.CalledOnValidThread()); 199 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 25 matching lines...) Expand all
203 225
204 void PipelineImpl::Stop() { 226 void PipelineImpl::Stop() {
205 DVLOG(2) << __FUNCTION__; 227 DVLOG(2) << __FUNCTION__;
206 DCHECK(thread_checker_.CalledOnValidThread()); 228 DCHECK(thread_checker_.CalledOnValidThread());
207 229
208 if (!IsRunning()) { 230 if (!IsRunning()) {
209 DVLOG(2) << "Media pipeline isn't running. Ignoring Stop()"; 231 DVLOG(2) << "Media pipeline isn't running. Ignoring Stop()";
210 return; 232 return;
211 } 233 }
212 234
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()) { 235 if (media_task_runner_->BelongsToCurrentThread()) {
219 // This path is executed by unittests that share media and main threads. 236 // This path is executed by unittests that share media and main threads.
220 base::Closure stop_cb = base::Bind(&base::DoNothing); 237 base::Closure stop_cb = base::Bind(&base::DoNothing);
221 media_task_runner_->PostTask( 238 media_task_runner_->PostTask(
222 FROM_HERE, 239 FROM_HERE,
223 base::Bind(&RendererWrapper::Stop, 240 base::Bind(&RendererWrapper::Stop,
224 base::Unretained(renderer_wrapper_.get()), stop_cb)); 241 base::Unretained(renderer_wrapper_.get()), stop_cb));
225 } else { 242 } else {
226 // This path is executed by production code where the two task runners - 243 // This path is executed by production code where the two task runners -
227 // main and media - live on different threads. 244 // main and media - live on different threads.
(...skipping 16 matching lines...) Expand all
244 base::Bind(&RendererWrapper::Stop, 261 base::Bind(&RendererWrapper::Stop,
245 base::Unretained(renderer_wrapper_.get()), stop_cb))); 262 base::Unretained(renderer_wrapper_.get()), stop_cb)));
246 waiter.Wait(); 263 waiter.Wait();
247 } 264 }
248 265
249 // Once the pipeline is stopped, nothing is reported back to the client. 266 // Once the pipeline is stopped, nothing is reported back to the client.
250 // Reset all callbacks and client handle. 267 // Reset all callbacks and client handle.
251 seek_cb_.Reset(); 268 seek_cb_.Reset();
252 suspend_cb_.Reset(); 269 suspend_cb_.Reset();
253 client_ = nullptr; 270 client_ = nullptr;
271
272 // Invalidate self weak pointers effectively canceling all pending
DaleCurtis 2016/06/22 21:00:06 This might break if we have any unittests not call
alokp 2016/06/22 21:13:34 Doing this allows us to not have to check for IsRu
273 // notifications in the message queue.
274 weak_factory_.InvalidateWeakPtrs();
254 } 275 }
255 276
256 void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) { 277 void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) {
257 DVLOG(2) << __FUNCTION__; 278 DVLOG(2) << __FUNCTION__;
258 DCHECK(thread_checker_.CalledOnValidThread()); 279 DCHECK(thread_checker_.CalledOnValidThread());
259 DCHECK(!seek_cb.is_null()); 280 DCHECK(!seek_cb.is_null());
260 281
261 if (!IsRunning()) { 282 if (!IsRunning()) {
262 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; 283 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek().";
263 return; 284 return;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 base::Unretained(renderer_wrapper_.get()), volume_)); 365 base::Unretained(renderer_wrapper_.get()), volume_));
345 } 366 }
346 367
347 base::TimeDelta PipelineImpl::GetMediaTime() const { 368 base::TimeDelta PipelineImpl::GetMediaTime() const {
348 DCHECK(thread_checker_.CalledOnValidThread()); 369 DCHECK(thread_checker_.CalledOnValidThread());
349 return renderer_wrapper_->GetMediaTime(); 370 return renderer_wrapper_->GetMediaTime();
350 } 371 }
351 372
352 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { 373 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const {
353 DCHECK(thread_checker_.CalledOnValidThread()); 374 DCHECK(thread_checker_.CalledOnValidThread());
354 return buffered_time_ranges_; 375 return renderer_wrapper_->GetBufferedTimeRanges();
355 } 376 }
356 377
357 base::TimeDelta PipelineImpl::GetMediaDuration() const { 378 base::TimeDelta PipelineImpl::GetMediaDuration() const {
358 DCHECK(thread_checker_.CalledOnValidThread()); 379 DCHECK(thread_checker_.CalledOnValidThread());
359 return duration_; 380 return duration_;
360 } 381 }
361 382
362 bool PipelineImpl::DidLoadingProgress() { 383 bool PipelineImpl::DidLoadingProgress() {
363 DCHECK(thread_checker_.CalledOnValidThread()); 384 DCHECK(thread_checker_.CalledOnValidThread());
364 bool ret = did_loading_progress_; 385 return renderer_wrapper_->DidLoadingProgress();
365 did_loading_progress_ = false;
366 return ret;
367 } 386 }
368 387
369 PipelineStatistics PipelineImpl::GetStatistics() const { 388 PipelineStatistics PipelineImpl::GetStatistics() const {
370 DCHECK(thread_checker_.CalledOnValidThread()); 389 DCHECK(thread_checker_.CalledOnValidThread());
371 return statistics_; 390 return renderer_wrapper_->GetStatistics();
372 } 391 }
373 392
374 void PipelineImpl::SetCdm(CdmContext* cdm_context, 393 void PipelineImpl::SetCdm(CdmContext* cdm_context,
375 const CdmAttachedCB& cdm_attached_cb) { 394 const CdmAttachedCB& cdm_attached_cb) {
376 DVLOG(2) << __FUNCTION__; 395 DVLOG(2) << __FUNCTION__;
377 DCHECK(thread_checker_.CalledOnValidThread()); 396 DCHECK(thread_checker_.CalledOnValidThread());
378 DCHECK(cdm_context); 397 DCHECK(cdm_context);
379 DCHECK(!cdm_attached_cb.is_null()); 398 DCHECK(!cdm_attached_cb.is_null());
380 399
381 media_task_runner_->PostTask( 400 media_task_runner_->PostTask(
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 if (state_ != kPlaying) 513 if (state_ != kPlaying)
495 return; 514 return;
496 515
497 DCHECK(!renderer_ended_); 516 DCHECK(!renderer_ended_);
498 renderer_ended_ = true; 517 renderer_ended_ = true;
499 RunEndedCallbackIfNeeded(); 518 RunEndedCallbackIfNeeded();
500 } 519 }
501 520
502 void PipelineImpl::RendererWrapper::OnStatisticsUpdate( 521 void PipelineImpl::RendererWrapper::OnStatisticsUpdate(
503 const PipelineStatistics& stats) { 522 const PipelineStatistics& stats) {
523 DVLOG(3) << __FUNCTION__;
504 DCHECK(media_task_runner_->BelongsToCurrentThread()); 524 DCHECK(media_task_runner_->BelongsToCurrentThread());
505 525
506 main_task_runner_->PostTask( 526 base::AutoLock auto_lock(shared_state_lock_);
507 FROM_HERE, 527 shared_state_.statistics.audio_bytes_decoded += stats.audio_bytes_decoded;
508 base::Bind(&PipelineImpl::OnStatisticsUpdate, weak_pipeline_, stats)); 528 shared_state_.statistics.video_bytes_decoded += stats.video_bytes_decoded;
529 shared_state_.statistics.video_frames_decoded += stats.video_frames_decoded;
530 shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped;
531 shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage;
532 shared_state_.statistics.video_memory_usage += stats.video_memory_usage;
509 } 533 }
510 534
511 void PipelineImpl::RendererWrapper::OnBufferingStateChange( 535 void PipelineImpl::RendererWrapper::OnBufferingStateChange(
512 BufferingState state) { 536 BufferingState state) {
513 DCHECK(media_task_runner_->BelongsToCurrentThread()); 537 DCHECK(media_task_runner_->BelongsToCurrentThread());
514 DVLOG(2) << __FUNCTION__ << "(" << state << ") "; 538 DVLOG(2) << __FUNCTION__ << "(" << state << ") ";
515 539
516 main_task_runner_->PostTask( 540 main_task_runner_->PostTask(
517 FROM_HERE, 541 FROM_HERE,
518 base::Bind(&PipelineImpl::OnBufferingStateChange, weak_pipeline_, state)); 542 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 614 // meeting 'decode' error when passing media segment but WebMediaPlayer's
591 // ready_state_ is still ReadyStateHaveNothing. In that case, it will 615 // ready_state_ is still ReadyStateHaveNothing. In that case, it will
592 // treat it as NetworkStateFormatError not NetworkStateDecodeError. 616 // treat it as NetworkStateFormatError not NetworkStateDecodeError.
593 ReportMetadata(); 617 ReportMetadata();
594 start_timestamp_ = demuxer_->GetStartTime(); 618 start_timestamp_ = demuxer_->GetStartTime();
595 619
596 return InitializeRenderer(done_cb); 620 return InitializeRenderer(done_cb);
597 621
598 case kPlaying: 622 case kPlaying:
599 DCHECK(start_timestamp_ >= base::TimeDelta()); 623 DCHECK(start_timestamp_ >= base::TimeDelta());
600 renderer_->StartPlayingFrom(start_timestamp_); 624 shared_state_.renderer->StartPlayingFrom(start_timestamp_);
601 { 625 {
602 base::AutoLock auto_lock(media_time_lock_); 626 base::AutoLock auto_lock(shared_state_lock_);
603 suspend_timestamp_ = kNoTimestamp(); 627 shared_state_.suspend_timestamp = kNoTimestamp();
604 } 628 }
605 629
606 if (text_renderer_) 630 if (text_renderer_)
607 text_renderer_->StartPlaying(); 631 text_renderer_->StartPlaying();
608 632
609 main_task_runner_->PostTask( 633 main_task_runner_->PostTask(
610 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_, 634 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_,
611 start_timestamp_)); 635 start_timestamp_));
612 636
613 renderer_->SetPlaybackRate(playback_rate_); 637 shared_state_.renderer->SetPlaybackRate(playback_rate_);
614 renderer_->SetVolume(volume_); 638 shared_state_.renderer->SetVolume(volume_);
615 return; 639 return;
616 640
617 case kSuspended: 641 case kSuspended:
618 renderer_.reset(); 642 DestroyRenderer();
643 {
644 base::AutoLock auto_lock(shared_state_lock_);
645 shared_state_.statistics.audio_memory_usage = 0;
646 shared_state_.statistics.video_memory_usage = 0;
647 }
619 main_task_runner_->PostTask( 648 main_task_runner_->PostTask(
620 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_, 649 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_,
621 suspend_timestamp_)); 650 shared_state_.suspend_timestamp));
622 return; 651 return;
623 652
624 case kStopping: 653 case kStopping:
625 case kStopped: 654 case kStopped:
626 case kCreated: 655 case kCreated:
627 case kSeeking: 656 case kSeeking:
628 case kSuspending: 657 case kSuspending:
629 case kResuming: 658 case kResuming:
630 NOTREACHED() << "State has no transition: " << state_; 659 NOTREACHED() << "State has no transition: " << state_;
631 return; 660 return;
(...skipping 12 matching lines...) Expand all
644 DCHECK_EQ(state_, kSeeking); 673 DCHECK_EQ(state_, kSeeking);
645 SerialRunner::Queue bound_fns; 674 SerialRunner::Queue bound_fns;
646 675
647 // Pause. 676 // Pause.
648 if (text_renderer_) { 677 if (text_renderer_) {
649 bound_fns.Push(base::Bind(&TextRenderer::Pause, 678 bound_fns.Push(base::Bind(&TextRenderer::Pause,
650 base::Unretained(text_renderer_.get()))); 679 base::Unretained(text_renderer_.get())));
651 } 680 }
652 681
653 // Flush. 682 // Flush.
654 DCHECK(renderer_); 683 DCHECK(shared_state_.renderer);
655 bound_fns.Push( 684 bound_fns.Push(base::Bind(&Renderer::Flush,
656 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); 685 base::Unretained(shared_state_.renderer.get())));
657 686
658 if (text_renderer_) { 687 if (text_renderer_) {
659 bound_fns.Push(base::Bind(&TextRenderer::Flush, 688 bound_fns.Push(base::Bind(&TextRenderer::Flush,
660 base::Unretained(text_renderer_.get()))); 689 base::Unretained(text_renderer_.get())));
661 } 690 }
662 691
663 // Seek demuxer. 692 // Seek demuxer.
664 bound_fns.Push( 693 bound_fns.Push(
665 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); 694 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
666 695
667 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 696 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
668 } 697 }
669 698
670 void PipelineImpl::RendererWrapper::DoStop(const base::Closure& done_cb) { 699 void PipelineImpl::RendererWrapper::DoStop(const base::Closure& done_cb) {
671 DVLOG(2) << __FUNCTION__; 700 DVLOG(2) << __FUNCTION__;
672 DCHECK(media_task_runner_->BelongsToCurrentThread()); 701 DCHECK(media_task_runner_->BelongsToCurrentThread());
673 DCHECK_EQ(state_, kStopping); 702 DCHECK_EQ(state_, kStopping);
674 DCHECK(!pending_callbacks_.get()); 703 DCHECK(!pending_callbacks_.get());
675 704
676 // TODO(scherkus): Enforce that Renderer is only called on a single thread, 705 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(); 706 text_renderer_.reset();
685 707
686 if (demuxer_) { 708 if (demuxer_) {
687 demuxer_->Stop(); 709 demuxer_->Stop();
688 demuxer_ = NULL; 710 demuxer_ = NULL;
689 } 711 }
690 712
691 SetState(kStopped); 713 SetState(kStopped);
692 714
693 // Post the stop callback to enqueue it after the tasks that may have been 715 // 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 716 // 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 717 // 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 718 // 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 719 // 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. 720 // problem, but ideally Demuxer should be destroyed on the media thread.
699 media_task_runner_->PostTask(FROM_HERE, done_cb); 721 media_task_runner_->PostTask(FROM_HERE, done_cb);
700 } 722 }
701 723
702 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged( 724 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged(
703 const Ranges<base::TimeDelta>& ranges) { 725 const Ranges<base::TimeDelta>& ranges) {
704 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer 726 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
705 // implementations call DemuxerHost on the media thread. 727 // implementations call DemuxerHost on the media thread.
706 main_task_runner_->PostTask( 728 base::AutoLock auto_lock(shared_state_lock_);
707 FROM_HERE, base::Bind(&PipelineImpl::OnBufferedTimeRangesChange, 729 shared_state_.did_loading_progress = true;
708 weak_pipeline_, ranges)); 730 shared_state_.buffered_time_ranges = ranges;
709 } 731 }
710 732
711 void PipelineImpl::RendererWrapper::Start( 733 void PipelineImpl::RendererWrapper::Start(
712 Demuxer* demuxer, 734 Demuxer* demuxer,
713 std::unique_ptr<Renderer> renderer, 735 std::unique_ptr<Renderer> renderer,
714 std::unique_ptr<TextRenderer> text_renderer) { 736 std::unique_ptr<TextRenderer> text_renderer) {
715 DCHECK(media_task_runner_->BelongsToCurrentThread()); 737 DCHECK(media_task_runner_->BelongsToCurrentThread());
716 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: " 738 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: "
717 << state_; 739 << state_;
718 740
719 DCHECK(!demuxer_); 741 DCHECK(!demuxer_);
720 DCHECK(!renderer_); 742 DCHECK(!shared_state_.renderer);
721 DCHECK(!text_renderer_); 743 DCHECK(!text_renderer_);
722 DCHECK(!renderer_ended_); 744 DCHECK(!renderer_ended_);
723 DCHECK(!text_renderer_ended_); 745 DCHECK(!text_renderer_ended_);
724 demuxer_ = demuxer; 746 demuxer_ = demuxer;
725 { 747 {
726 base::AutoLock auto_lock(media_time_lock_); 748 base::AutoLock auto_lock(shared_state_lock_);
727 renderer_ = std::move(renderer); 749 shared_state_.renderer = std::move(renderer);
728 } 750 }
729 text_renderer_ = std::move(text_renderer); 751 text_renderer_ = std::move(text_renderer);
730 if (text_renderer_) { 752 if (text_renderer_) {
731 text_renderer_->Initialize( 753 text_renderer_->Initialize(
732 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_)); 754 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_));
733 } 755 }
734 756
735 StateTransitionTask(PIPELINE_OK); 757 StateTransitionTask(PIPELINE_OK);
736 } 758 }
737 759
738 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) { 760 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) {
739 DCHECK(media_task_runner_->BelongsToCurrentThread()); 761 DCHECK(media_task_runner_->BelongsToCurrentThread());
740 DCHECK(state_ != kStopping && state_ != kStopped); 762 DCHECK(state_ != kStopping && state_ != kStopped);
741 763
742 SetState(kStopping); 764 SetState(kStopping);
743 765
766 if (shared_state_.statistics.video_frames_decoded > 0) {
767 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount",
768 shared_state_.statistics.video_frames_dropped);
769 }
770
744 // If we stop during starting/seeking/suspending/resuming we don't want to 771 // 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 772 // 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 773 // the pipeline is stopped before it had a chance to complete outstanding
747 // tasks. 774 // tasks.
748 pending_callbacks_.reset(); 775 pending_callbacks_.reset();
749 776
750 DoStop(stop_cb); 777 DoStop(stop_cb);
751 } 778 }
752 779
753 void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) { 780 void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) {
(...skipping 18 matching lines...) Expand all
772 status_ = error; 799 status_ = error;
773 main_task_runner_->PostTask( 800 main_task_runner_->PostTask(
774 FROM_HERE, base::Bind(&PipelineImpl::OnError, weak_pipeline_, error)); 801 FROM_HERE, base::Bind(&PipelineImpl::OnError, weak_pipeline_, error));
775 } 802 }
776 803
777 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) { 804 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) {
778 DCHECK(media_task_runner_->BelongsToCurrentThread()); 805 DCHECK(media_task_runner_->BelongsToCurrentThread());
779 806
780 playback_rate_ = playback_rate; 807 playback_rate_ = playback_rate;
781 if (state_ == kPlaying) 808 if (state_ == kPlaying)
782 renderer_->SetPlaybackRate(playback_rate_); 809 shared_state_.renderer->SetPlaybackRate(playback_rate_);
783 } 810 }
784 811
785 void PipelineImpl::RendererWrapper::SetVolume(float volume) { 812 void PipelineImpl::RendererWrapper::SetVolume(float volume) {
786 DCHECK(media_task_runner_->BelongsToCurrentThread()); 813 DCHECK(media_task_runner_->BelongsToCurrentThread());
787 814
788 volume_ = volume; 815 volume_ = volume;
789 if (state_ == kPlaying) 816 if (state_ == kPlaying)
790 renderer_->SetVolume(volume_); 817 shared_state_.renderer->SetVolume(volume_);
791 } 818 }
792 819
793 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) { 820 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) {
794 DCHECK(media_task_runner_->BelongsToCurrentThread()); 821 DCHECK(media_task_runner_->BelongsToCurrentThread());
795 822
796 // Suppress seeking if we're not fully started. 823 // Suppress seeking if we're not fully started.
797 if (state_ != kPlaying) { 824 if (state_ != kPlaying) {
798 DCHECK(state_ == kStopping || state_ == kStopped) 825 DCHECK(state_ == kStopping || state_ == kStopped)
799 << "Receive seek in unexpected state: " << state_; 826 << "Receive seek in unexpected state: " << state_;
800 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 827 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
(...skipping 15 matching lines...) Expand all
816 void PipelineImpl::RendererWrapper::Suspend() { 843 void PipelineImpl::RendererWrapper::Suspend() {
817 DCHECK(media_task_runner_->BelongsToCurrentThread()); 844 DCHECK(media_task_runner_->BelongsToCurrentThread());
818 845
819 // Suppress suspending if we're not playing. 846 // Suppress suspending if we're not playing.
820 if (state_ != kPlaying) { 847 if (state_ != kPlaying) {
821 DCHECK(state_ == kStopping || state_ == kStopped) 848 DCHECK(state_ == kStopping || state_ == kStopped)
822 << "Receive suspend in unexpected state: " << state_; 849 << "Receive suspend in unexpected state: " << state_;
823 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 850 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
824 return; 851 return;
825 } 852 }
826 DCHECK(renderer_); 853 DCHECK(shared_state_.renderer);
827 DCHECK(!pending_callbacks_.get()); 854 DCHECK(!pending_callbacks_.get());
828 855
829 SetState(kSuspending); 856 SetState(kSuspending);
830 857
831 // Freeze playback and record the media time before flushing. (Flushing clears 858 // Freeze playback and record the media time before flushing. (Flushing clears
832 // the value.) 859 // the value.)
833 renderer_->SetPlaybackRate(0.0); 860 shared_state_.renderer->SetPlaybackRate(0.0);
834 { 861 {
835 base::AutoLock auto_lock(media_time_lock_); 862 base::AutoLock auto_lock(shared_state_lock_);
836 suspend_timestamp_ = renderer_->GetMediaTime(); 863 shared_state_.suspend_timestamp = shared_state_.renderer->GetMediaTime();
837 DCHECK(suspend_timestamp_ != kNoTimestamp()); 864 DCHECK(shared_state_.suspend_timestamp != kNoTimestamp());
838 } 865 }
839 866
840 // Queue the asynchronous actions required to stop playback. (Matches setup in 867 // Queue the asynchronous actions required to stop playback. (Matches setup in
841 // DoSeek().) 868 // DoSeek().)
842 // TODO(sandersd): Share implementation with DoSeek(). 869 // TODO(sandersd): Share implementation with DoSeek().
843 SerialRunner::Queue fns; 870 SerialRunner::Queue fns;
844 871
845 if (text_renderer_) { 872 if (text_renderer_) {
846 fns.Push(base::Bind(&TextRenderer::Pause, 873 fns.Push(base::Bind(&TextRenderer::Pause,
847 base::Unretained(text_renderer_.get()))); 874 base::Unretained(text_renderer_.get())));
848 } 875 }
849 876
850 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); 877 fns.Push(base::Bind(&Renderer::Flush,
878 base::Unretained(shared_state_.renderer.get())));
851 879
852 if (text_renderer_) { 880 if (text_renderer_) {
853 fns.Push(base::Bind(&TextRenderer::Flush, 881 fns.Push(base::Bind(&TextRenderer::Flush,
854 base::Unretained(text_renderer_.get()))); 882 base::Unretained(text_renderer_.get())));
855 } 883 }
856 884
857 pending_callbacks_ = SerialRunner::Run( 885 pending_callbacks_ = SerialRunner::Run(
858 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_)); 886 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_));
859 } 887 }
860 888
861 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer, 889 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer,
862 base::TimeDelta timestamp) { 890 base::TimeDelta timestamp) {
863 DCHECK(media_task_runner_->BelongsToCurrentThread()); 891 DCHECK(media_task_runner_->BelongsToCurrentThread());
864 892
865 // Suppress resuming if we're not suspended. 893 // Suppress resuming if we're not suspended.
866 if (state_ != kSuspended) { 894 if (state_ != kSuspended) {
867 DCHECK(state_ == kStopping || state_ == kStopped) 895 DCHECK(state_ == kStopping || state_ == kStopped)
868 << "Receive resume in unexpected state: " << state_; 896 << "Receive resume in unexpected state: " << state_;
869 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 897 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
870 return; 898 return;
871 } 899 }
872 DCHECK(!renderer_); 900 DCHECK(!shared_state_.renderer);
873 DCHECK(!pending_callbacks_.get()); 901 DCHECK(!pending_callbacks_.get());
874 902
875 SetState(kResuming); 903 SetState(kResuming);
876 904
877 { 905 {
878 base::AutoLock auto_lock(media_time_lock_); 906 base::AutoLock auto_lock(shared_state_lock_);
879 renderer_ = std::move(renderer); 907 shared_state_.renderer = std::move(renderer);
880 } 908 }
881 909
882 // Set up for a seek. (Matches setup in SeekTask().) 910 // Set up for a seek. (Matches setup in SeekTask().)
883 // TODO(sandersd): Share implementation with SeekTask(). 911 // TODO(sandersd): Share implementation with SeekTask().
884 renderer_ended_ = false; 912 renderer_ended_ = false;
885 text_renderer_ended_ = false; 913 text_renderer_ended_ = false;
886 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime()); 914 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime());
887 915
888 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), 916 // 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 917 // 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 918 // kInitDemuxer, and even if we did the current code would seek to the start
891 // instead of |timestamp|). 919 // instead of |timestamp|).
892 SerialRunner::Queue fns; 920 SerialRunner::Queue fns;
893 921
894 fns.Push( 922 fns.Push(
895 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); 923 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_));
896 924
897 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); 925 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_));
898 926
899 pending_callbacks_ = SerialRunner::Run( 927 pending_callbacks_ = SerialRunner::Run(
900 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_)); 928 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_));
901 } 929 }
902 930
931 Ranges<base::TimeDelta> PipelineImpl::RendererWrapper::GetBufferedTimeRanges()
932 const {
933 DCHECK(main_task_runner_->BelongsToCurrentThread());
934
935 base::AutoLock auto_lock(shared_state_lock_);
936 return shared_state_.buffered_time_ranges;
937 }
938
939 bool PipelineImpl::RendererWrapper::DidLoadingProgress() {
940 DCHECK(main_task_runner_->BelongsToCurrentThread());
941
942 base::AutoLock auto_lock(shared_state_lock_);
943 bool did_progress = shared_state_.did_loading_progress;
944 shared_state_.did_loading_progress = false;
945 return did_progress;
946 }
947
948 PipelineStatistics PipelineImpl::RendererWrapper::GetStatistics() const {
949 DCHECK(main_task_runner_->BelongsToCurrentThread());
950
951 base::AutoLock auto_lock(shared_state_lock_);
952 return shared_state_.statistics;
953 }
954
903 void PipelineImpl::RendererWrapper::SetCdm( 955 void PipelineImpl::RendererWrapper::SetCdm(
904 CdmContext* cdm_context, 956 CdmContext* cdm_context,
905 const CdmAttachedCB& cdm_attached_cb) { 957 const CdmAttachedCB& cdm_attached_cb) {
906 DCHECK(media_task_runner_->BelongsToCurrentThread()); 958 DCHECK(media_task_runner_->BelongsToCurrentThread());
907 959
908 if (!renderer_) { 960 if (!shared_state_.renderer) {
909 cdm_context_ = cdm_context; 961 cdm_context_ = cdm_context;
910 cdm_attached_cb.Run(true); 962 cdm_attached_cb.Run(true);
911 return; 963 return;
912 } 964 }
913 965
914 renderer_->SetCdm(cdm_context, 966 shared_state_.renderer->SetCdm(
915 base::Bind(&RendererWrapper::OnCdmAttached, weak_this_, 967 cdm_context, base::Bind(&RendererWrapper::OnCdmAttached, weak_this_,
916 cdm_attached_cb, cdm_context)); 968 cdm_attached_cb, cdm_context));
917 } 969 }
918 970
919 void PipelineImpl::RendererWrapper::OnCdmAttached( 971 void PipelineImpl::RendererWrapper::OnCdmAttached(
920 const CdmAttachedCB& cdm_attached_cb, 972 const CdmAttachedCB& cdm_attached_cb,
921 CdmContext* cdm_context, 973 CdmContext* cdm_context,
922 bool success) { 974 bool success) {
923 DCHECK(media_task_runner_->BelongsToCurrentThread()); 975 DCHECK(media_task_runner_->BelongsToCurrentThread());
924 976
925 if (success) 977 if (success)
926 cdm_context_ = cdm_context; 978 cdm_context_ = cdm_context;
927 cdm_attached_cb.Run(success); 979 cdm_attached_cb.Run(success);
928 } 980 }
929 981
930 void PipelineImpl::RendererWrapper::OnTextRendererEnded() { 982 void PipelineImpl::RendererWrapper::OnTextRendererEnded() {
931 DCHECK(media_task_runner_->BelongsToCurrentThread()); 983 DCHECK(media_task_runner_->BelongsToCurrentThread());
932 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); 984 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
933 985
934 if (state_ != kPlaying) 986 if (state_ != kPlaying)
935 return; 987 return;
936 988
937 DCHECK(!text_renderer_ended_); 989 DCHECK(!text_renderer_ended_);
938 text_renderer_ended_ = true; 990 text_renderer_ended_ = true;
939 991
940 RunEndedCallbackIfNeeded(); 992 RunEndedCallbackIfNeeded();
941 } 993 }
942 994
943 void PipelineImpl::RendererWrapper::RunEndedCallbackIfNeeded() { 995 void PipelineImpl::RendererWrapper::RunEndedCallbackIfNeeded() {
944 DCHECK(media_task_runner_->BelongsToCurrentThread()); 996 DCHECK(media_task_runner_->BelongsToCurrentThread());
945 997
946 if (renderer_ && !renderer_ended_) 998 if (shared_state_.renderer && !renderer_ended_)
947 return; 999 return;
948 1000
949 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) 1001 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_)
950 return; 1002 return;
951 1003
952 DCHECK_EQ(status_, PIPELINE_OK); 1004 DCHECK_EQ(status_, PIPELINE_OK);
953 main_task_runner_->PostTask( 1005 main_task_runner_->PostTask(
954 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_)); 1006 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_));
955 } 1007 }
956 1008
(...skipping 27 matching lines...) Expand all
984 const PipelineStatusCB& done_cb) { 1036 const PipelineStatusCB& done_cb) {
985 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1037 DCHECK(media_task_runner_->BelongsToCurrentThread());
986 1038
987 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && 1039 if (!demuxer_->GetStream(DemuxerStream::AUDIO) &&
988 !demuxer_->GetStream(DemuxerStream::VIDEO)) { 1040 !demuxer_->GetStream(DemuxerStream::VIDEO)) {
989 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); 1041 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER);
990 return; 1042 return;
991 } 1043 }
992 1044
993 if (cdm_context_) 1045 if (cdm_context_)
994 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); 1046 shared_state_.renderer->SetCdm(cdm_context_,
1047 base::Bind(&IgnoreCdmAttached));
995 1048
996 renderer_->Initialize(demuxer_, this, done_cb); 1049 shared_state_.renderer->Initialize(demuxer_, this, done_cb);
1050 }
1051
1052 void PipelineImpl::RendererWrapper::DestroyRenderer() {
1053 DCHECK(media_task_runner_->BelongsToCurrentThread());
1054
1055 std::unique_ptr<Renderer> renderer;
DaleCurtis 2016/06/22 21:00:07 Add a comment here then if you think it matters ho
alokp 2016/06/22 21:13:34 Done.
1056 {
1057 base::AutoLock auto_lock(shared_state_lock_);
1058 renderer.swap(shared_state_.renderer);
1059 }
997 } 1060 }
998 1061
999 void PipelineImpl::RendererWrapper::ReportMetadata() { 1062 void PipelineImpl::RendererWrapper::ReportMetadata() {
1000 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1063 DCHECK(media_task_runner_->BelongsToCurrentThread());
1001 1064
1002 PipelineMetadata metadata; 1065 PipelineMetadata metadata;
1003 metadata.timeline_offset = demuxer_->GetTimelineOffset(); 1066 metadata.timeline_offset = demuxer_->GetTimelineOffset();
1004 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 1067 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
1005 if (stream) { 1068 if (stream) {
1006 metadata.has_video = true; 1069 metadata.has_video = true;
1007 metadata.natural_size = stream->video_decoder_config().natural_size(); 1070 metadata.natural_size = stream->video_decoder_config().natural_size();
1008 metadata.video_rotation = stream->video_rotation(); 1071 metadata.video_rotation = stream->video_rotation();
1009 } 1072 }
1010 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { 1073 if (demuxer_->GetStream(DemuxerStream::AUDIO)) {
1011 metadata.has_audio = true; 1074 metadata.has_audio = true;
1012 } 1075 }
1013 1076
1014 main_task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::OnMetadata, 1077 main_task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::OnMetadata,
1015 weak_pipeline_, metadata)); 1078 weak_pipeline_, metadata));
1016 } 1079 }
1017 1080
1018 void PipelineImpl::OnError(PipelineStatus error) { 1081 void PipelineImpl::OnError(PipelineStatus error) {
1019 DVLOG(2) << __FUNCTION__; 1082 DVLOG(2) << __FUNCTION__;
1020 DCHECK(thread_checker_.CalledOnValidThread()); 1083 DCHECK(thread_checker_.CalledOnValidThread());
1021 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; 1084 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
1022 1085 DCHECK(IsRunning());
1023 if (!IsRunning())
1024 return;
1025 1086
1026 // If the error happens during starting/seeking/suspending/resuming, 1087 // If the error happens during starting/seeking/suspending/resuming,
1027 // report the error via the completion callback for those tasks. 1088 // report the error via the completion callback for those tasks.
1028 // Else report error via the client interface. 1089 // Else report error via the client interface.
1029 if (!seek_cb_.is_null()) { 1090 if (!seek_cb_.is_null()) {
1030 base::ResetAndReturn(&seek_cb_).Run(error); 1091 base::ResetAndReturn(&seek_cb_).Run(error);
1031 } else if (!suspend_cb_.is_null()) { 1092 } else if (!suspend_cb_.is_null()) {
1032 base::ResetAndReturn(&suspend_cb_).Run(error); 1093 base::ResetAndReturn(&suspend_cb_).Run(error);
1033 } else { 1094 } else {
1034 DCHECK(client_); 1095 DCHECK(client_);
1035 client_->OnError(error); 1096 client_->OnError(error);
1036 } 1097 }
1037 1098
1038 // Any kind of error stops the pipeline. 1099 // Any kind of error stops the pipeline.
1039 Stop(); 1100 Stop();
1040 } 1101 }
1041 1102
1042 void PipelineImpl::OnEnded() { 1103 void PipelineImpl::OnEnded() {
1043 DVLOG(2) << __FUNCTION__; 1104 DVLOG(2) << __FUNCTION__;
1044 DCHECK(thread_checker_.CalledOnValidThread()); 1105 DCHECK(thread_checker_.CalledOnValidThread());
1106 DCHECK(IsRunning());
1045 1107
1046 if (IsRunning()) { 1108 DCHECK(client_);
1047 DCHECK(client_); 1109 client_->OnEnded();
1048 client_->OnEnded();
1049 }
1050 } 1110 }
1051 1111
1052 void PipelineImpl::OnMetadata(PipelineMetadata metadata) { 1112 void PipelineImpl::OnMetadata(PipelineMetadata metadata) {
1053 DVLOG(2) << __FUNCTION__; 1113 DVLOG(2) << __FUNCTION__;
1054 DCHECK(thread_checker_.CalledOnValidThread()); 1114 DCHECK(thread_checker_.CalledOnValidThread());
1115 DCHECK(IsRunning());
1055 1116
1056 if (IsRunning()) { 1117 DCHECK(client_);
1057 DCHECK(client_); 1118 client_->OnMetadata(metadata);
1058 client_->OnMetadata(metadata);
1059 }
1060 } 1119 }
1061 1120
1062 void PipelineImpl::OnBufferingStateChange(BufferingState state) { 1121 void PipelineImpl::OnBufferingStateChange(BufferingState state) {
1063 DVLOG(2) << __FUNCTION__ << "(" << state << ")"; 1122 DVLOG(2) << __FUNCTION__ << "(" << state << ")";
1064 DCHECK(thread_checker_.CalledOnValidThread()); 1123 DCHECK(thread_checker_.CalledOnValidThread());
1124 DCHECK(IsRunning());
1065 1125
1066 if (IsRunning()) { 1126 DCHECK(client_);
1067 DCHECK(client_); 1127 client_->OnBufferingStateChange(state);
1068 client_->OnBufferingStateChange(state);
1069 }
1070 } 1128 }
1071 1129
1072 void PipelineImpl::OnDurationChange(base::TimeDelta duration) { 1130 void PipelineImpl::OnDurationChange(base::TimeDelta duration) {
1073 DVLOG(2) << __FUNCTION__; 1131 DVLOG(2) << __FUNCTION__;
1074 DCHECK(thread_checker_.CalledOnValidThread()); 1132 DCHECK(thread_checker_.CalledOnValidThread());
1133 DCHECK(IsRunning());
1075 1134
1076 duration_ = duration; 1135 duration_ = duration;
1077 1136
1078 if (IsRunning()) { 1137 DCHECK(client_);
1079 DCHECK(client_); 1138 client_->OnDurationChange();
1080 client_->OnDurationChange();
1081 }
1082 } 1139 }
1083 1140
1084 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, 1141 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config,
1085 const AddTextTrackDoneCB& done_cb) { 1142 const AddTextTrackDoneCB& done_cb) {
1086 DVLOG(2) << __FUNCTION__; 1143 DVLOG(2) << __FUNCTION__;
1087 DCHECK(thread_checker_.CalledOnValidThread()); 1144 DCHECK(thread_checker_.CalledOnValidThread());
1145 DCHECK(IsRunning());
1088 1146
1089 if (IsRunning()) { 1147 DCHECK(client_);
1090 DCHECK(client_); 1148 client_->OnAddTextTrack(config, done_cb);
1091 client_->OnAddTextTrack(config, done_cb);
1092 }
1093 } 1149 }
1094 1150
1095 void PipelineImpl::OnWaitingForDecryptionKey() { 1151 void PipelineImpl::OnWaitingForDecryptionKey() {
1096 DVLOG(2) << __FUNCTION__; 1152 DVLOG(2) << __FUNCTION__;
1097 DCHECK(thread_checker_.CalledOnValidThread()); 1153 DCHECK(thread_checker_.CalledOnValidThread());
1154 DCHECK(IsRunning());
1098 1155
1099 if (IsRunning()) { 1156 DCHECK(client_);
1100 DCHECK(client_); 1157 client_->OnWaitingForDecryptionKey();
1101 client_->OnWaitingForDecryptionKey();
1102 }
1103 } 1158 }
1104 1159
1105 void PipelineImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { 1160 void PipelineImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1106 DVLOG(2) << __FUNCTION__; 1161 DVLOG(2) << __FUNCTION__;
1107 DCHECK(thread_checker_.CalledOnValidThread()); 1162 DCHECK(thread_checker_.CalledOnValidThread());
1163 DCHECK(IsRunning());
1108 1164
1109 if (IsRunning()) { 1165 DCHECK(client_);
1110 DCHECK(client_); 1166 client_->OnVideoNaturalSizeChange(size);
1111 client_->OnVideoNaturalSizeChange(size);
1112 }
1113 } 1167 }
1114 1168
1115 void PipelineImpl::OnVideoOpacityChange(bool opaque) { 1169 void PipelineImpl::OnVideoOpacityChange(bool opaque) {
1116 DVLOG(2) << __FUNCTION__; 1170 DVLOG(2) << __FUNCTION__;
1117 DCHECK(thread_checker_.CalledOnValidThread()); 1171 DCHECK(thread_checker_.CalledOnValidThread());
1172 DCHECK(IsRunning());
1118 1173
1119 if (IsRunning()) { 1174 DCHECK(client_);
1120 DCHECK(client_); 1175 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 } 1176 }
1145 1177
1146 void PipelineImpl::OnSeekDone(base::TimeDelta start_time) { 1178 void PipelineImpl::OnSeekDone(base::TimeDelta start_time) {
1147 DVLOG(3) << __FUNCTION__ << "(" << start_time.InMicroseconds() << ")"; 1179 DVLOG(3) << __FUNCTION__ << "(" << start_time.InMicroseconds() << ")";
1148 DCHECK(thread_checker_.CalledOnValidThread()); 1180 DCHECK(thread_checker_.CalledOnValidThread());
1181 DCHECK(IsRunning());
1149 1182
1150 if (IsRunning()) { 1183 DCHECK(!seek_cb_.is_null());
1151 DCHECK(!seek_cb_.is_null()); 1184 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1152 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1153 }
1154 } 1185 }
1155 1186
1156 void PipelineImpl::OnSuspendDone(base::TimeDelta suspend_time) { 1187 void PipelineImpl::OnSuspendDone(base::TimeDelta suspend_time) {
1157 DVLOG(3) << __FUNCTION__ << "(" << suspend_time.InMicroseconds() << ")"; 1188 DVLOG(3) << __FUNCTION__ << "(" << suspend_time.InMicroseconds() << ")";
1158 DCHECK(thread_checker_.CalledOnValidThread()); 1189 DCHECK(thread_checker_.CalledOnValidThread());
1190 DCHECK(IsRunning());
1159 1191
1160 // Reset audio-video memory usage since renderer has been destroyed. 1192 DCHECK(!suspend_cb_.is_null());
1161 statistics_.audio_memory_usage = 0; 1193 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 } 1194 }
1169 1195
1170 PipelineImpl::RendererWrapper::RendererWrapper( 1196 PipelineImpl::RendererWrapper::RendererWrapper(
1171 base::WeakPtr<PipelineImpl> weak_pipeline, 1197 base::WeakPtr<PipelineImpl> weak_pipeline,
1172 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, 1198 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
1173 scoped_refptr<MediaLog> media_log) 1199 scoped_refptr<MediaLog> media_log)
1174 : weak_pipeline_(weak_pipeline), 1200 : weak_pipeline_(weak_pipeline),
1175 media_task_runner_(std::move(media_task_runner)), 1201 media_task_runner_(std::move(media_task_runner)),
1176 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), 1202 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
1177 media_log_(std::move(media_log)), 1203 media_log_(std::move(media_log)),
1178 demuxer_(nullptr), 1204 demuxer_(nullptr),
1179 playback_rate_(kDefaultPlaybackRate), 1205 playback_rate_(kDefaultPlaybackRate),
1180 volume_(kDefaultVolume), 1206 volume_(kDefaultVolume),
1181 cdm_context_(nullptr), 1207 cdm_context_(nullptr),
1182 state_(kCreated), 1208 state_(kCreated),
1183 status_(PIPELINE_OK), 1209 status_(PIPELINE_OK),
1184 suspend_timestamp_(kNoTimestamp()),
1185 renderer_ended_(false), 1210 renderer_ended_(false),
1186 text_renderer_ended_(false), 1211 text_renderer_ended_(false),
1187 weak_factory_(this) { 1212 weak_factory_(this) {
1188 weak_this_ = weak_factory_.GetWeakPtr(); 1213 weak_this_ = weak_factory_.GetWeakPtr();
1189 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 1214 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
1190 } 1215 }
1191 1216
1192 PipelineImpl::RendererWrapper::~RendererWrapper() { 1217 PipelineImpl::RendererWrapper::~RendererWrapper() {
1193 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1218 DCHECK(media_task_runner_->BelongsToCurrentThread());
1194 DCHECK(state_ == kCreated || state_ == kStopped); 1219 DCHECK(state_ == kCreated || state_ == kStopped);
1195 } 1220 }
1196 1221
1197 base::TimeDelta PipelineImpl::RendererWrapper::GetMediaTime() { 1222 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()); 1223 DCHECK(main_task_runner_->BelongsToCurrentThread());
1202 1224
1203 base::AutoLock auto_lock(media_time_lock_); 1225 base::AutoLock auto_lock(shared_state_lock_);
1204 if (suspend_timestamp_ != kNoTimestamp()) 1226 if (shared_state_.suspend_timestamp != kNoTimestamp())
1205 return suspend_timestamp_; 1227 return shared_state_.suspend_timestamp;
1206 return renderer_ ? renderer_->GetMediaTime() : base::TimeDelta(); 1228 return shared_state_.renderer ? shared_state_.renderer->GetMediaTime()
1229 : base::TimeDelta();
1207 } 1230 }
1208 1231
1209 } // namespace media 1232 } // 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