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

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