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

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

Issue 2091893003: Make PipelineImpl state change tasks consistent. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixes tests 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') | media/base/pipeline_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/pipeline_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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 void RemoveTextStreamTask(DemuxerStream* text_stream); 112 void RemoveTextStreamTask(DemuxerStream* text_stream);
113 113
114 // Common handlers for notifications from renderers and demuxer. 114 // Common handlers for notifications from renderers and demuxer.
115 void OnPipelineError(PipelineStatus error); 115 void OnPipelineError(PipelineStatus error);
116 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, 116 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb,
117 CdmContext* cdm_context, 117 CdmContext* cdm_context,
118 bool success); 118 bool success);
119 void CheckPlaybackEnded(); 119 void CheckPlaybackEnded();
120 120
121 // State transition tasks. 121 // State transition tasks.
122 void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
123 void DoStop(const base::Closure& done_cb);
124 void SetState(State next_state); 122 void SetState(State next_state);
125 State GetNextState() const; 123 void CompleteSeek(base::TimeDelta seek_time, PipelineStatus status);
126 void StateTransitionTask(PipelineStatus status); 124 void CompleteSuspend(PipelineStatus status);
127 void InitializeDemuxer(const PipelineStatusCB& done_cb); 125 void InitializeDemuxer(const PipelineStatusCB& done_cb);
128 void InitializeRenderer(const PipelineStatusCB& done_cb); 126 void InitializeRenderer(const PipelineStatusCB& done_cb);
129 void DestroyRenderer(); 127 void DestroyRenderer();
130 void ReportMetadata(); 128 void ReportMetadata();
131 129
132 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; 130 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
133 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; 131 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
134 const scoped_refptr<MediaLog> media_log_; 132 const scoped_refptr<MediaLog> media_log_;
135 133
136 base::WeakPtr<PipelineImpl> weak_pipeline_; 134 base::WeakPtr<PipelineImpl> weak_pipeline_;
(...skipping 11 matching lines...) Expand all
148 146
149 // Current state of the pipeline. 147 // Current state of the pipeline.
150 State state_; 148 State state_;
151 149
152 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that 150 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
153 // the pipeline is operating correctly. Any other value indicates that the 151 // the pipeline is operating correctly. Any other value indicates that the
154 // 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
155 // reset the pipeline state, and restore this to PIPELINE_OK. 153 // reset the pipeline state, and restore this to PIPELINE_OK.
156 PipelineStatus status_; 154 PipelineStatus status_;
157 155
158 // The timestamp to start playback from after starting/seeking/resuming has
159 // completed.
160 base::TimeDelta start_timestamp_;
161
162 // Whether we've received the audio/video/text ended events. 156 // Whether we've received the audio/video/text ended events.
163 bool renderer_ended_; 157 bool renderer_ended_;
164 bool text_renderer_ended_; 158 bool text_renderer_ended_;
165 159
166 // Series of tasks to Start(), Seek(), and Resume(). 160 // Series of tasks to Start(), Seek(), and Resume().
167 std::unique_ptr<SerialRunner> pending_callbacks_; 161 std::unique_ptr<SerialRunner> pending_callbacks_;
168 162
169 base::WeakPtr<RendererWrapper> weak_this_; 163 base::WeakPtr<RendererWrapper> weak_this_;
170 base::WeakPtrFactory<RendererWrapper> weak_factory_; 164 base::WeakPtrFactory<RendererWrapper> weak_factory_;
171 DISALLOW_COPY_AND_ASSIGN(RendererWrapper); 165 DISALLOW_COPY_AND_ASSIGN(RendererWrapper);
(...skipping 16 matching lines...) Expand all
188 weak_factory_(this) { 182 weak_factory_(this) {
189 weak_this_ = weak_factory_.GetWeakPtr(); 183 weak_this_ = weak_factory_.GetWeakPtr();
190 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 184 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
191 } 185 }
192 186
193 PipelineImpl::RendererWrapper::~RendererWrapper() { 187 PipelineImpl::RendererWrapper::~RendererWrapper() {
194 DCHECK(media_task_runner_->BelongsToCurrentThread()); 188 DCHECK(media_task_runner_->BelongsToCurrentThread());
195 DCHECK(state_ == kCreated || state_ == kStopped); 189 DCHECK(state_ == kCreated || state_ == kStopped);
196 } 190 }
197 191
192 // Note that the usage of base::Unretained() with the renderers is considered
193 // safe as they are owned by |pending_callbacks_| and share the same lifetime.
194 //
195 // That being said, deleting the renderers while keeping |pending_callbacks_|
196 // running on the media thread would result in crashes.
197
198 void PipelineImpl::RendererWrapper::Start( 198 void PipelineImpl::RendererWrapper::Start(
199 Demuxer* demuxer, 199 Demuxer* demuxer,
200 std::unique_ptr<Renderer> renderer, 200 std::unique_ptr<Renderer> renderer,
201 std::unique_ptr<TextRenderer> text_renderer, 201 std::unique_ptr<TextRenderer> text_renderer,
202 base::WeakPtr<PipelineImpl> weak_pipeline) { 202 base::WeakPtr<PipelineImpl> weak_pipeline) {
203 DCHECK(media_task_runner_->BelongsToCurrentThread()); 203 DCHECK(media_task_runner_->BelongsToCurrentThread());
204 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: " 204 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: "
205 << state_; 205 << state_;
206 206
207 SetState(kStarting);
208
207 DCHECK(!demuxer_); 209 DCHECK(!demuxer_);
208 DCHECK(!shared_state_.renderer); 210 DCHECK(!shared_state_.renderer);
209 DCHECK(!text_renderer_); 211 DCHECK(!text_renderer_);
210 DCHECK(!renderer_ended_); 212 DCHECK(!renderer_ended_);
211 DCHECK(!text_renderer_ended_); 213 DCHECK(!text_renderer_ended_);
212 DCHECK(!weak_pipeline_); 214 DCHECK(!weak_pipeline_);
213 demuxer_ = demuxer; 215 demuxer_ = demuxer;
214 { 216 {
215 base::AutoLock auto_lock(shared_state_lock_); 217 base::AutoLock auto_lock(shared_state_lock_);
216 shared_state_.renderer = std::move(renderer); 218 shared_state_.renderer = std::move(renderer);
217 } 219 }
218 text_renderer_ = std::move(text_renderer); 220 text_renderer_ = std::move(text_renderer);
219 if (text_renderer_) { 221 if (text_renderer_) {
220 text_renderer_->Initialize( 222 text_renderer_->Initialize(
221 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_)); 223 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_));
222 } 224 }
223 weak_pipeline_ = weak_pipeline; 225 weak_pipeline_ = weak_pipeline;
224 226
225 StateTransitionTask(PIPELINE_OK); 227 // Queue asynchronous actions required to start.
228 DCHECK(!pending_callbacks_);
229 SerialRunner::Queue fns;
230
231 // Initialize demuxer.
232 fns.Push(base::Bind(&RendererWrapper::InitializeDemuxer, weak_this_));
233
234 // Once the demuxer is initialized successfully, media metadata must be
235 // available - report the metadata to client.
236 fns.Push(base::Bind(&RendererWrapper::ReportMetadata, weak_this_));
237
238 // Initialize renderer.
239 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_));
240
241 // Run tasks.
242 pending_callbacks_ =
243 SerialRunner::Run(fns, base::Bind(&RendererWrapper::CompleteSeek,
244 weak_this_, base::TimeDelta()));
226 } 245 }
227 246
228 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) { 247 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) {
229 DCHECK(media_task_runner_->BelongsToCurrentThread()); 248 DCHECK(media_task_runner_->BelongsToCurrentThread());
230 DCHECK(state_ != kStopping && state_ != kStopped); 249 DCHECK(state_ != kStopping && state_ != kStopped);
231 250
232 SetState(kStopping); 251 SetState(kStopping);
233 252
234 if (shared_state_.statistics.video_frames_decoded > 0) { 253 if (shared_state_.statistics.video_frames_decoded > 0) {
235 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", 254 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount",
236 shared_state_.statistics.video_frames_dropped); 255 shared_state_.statistics.video_frames_dropped);
237 } 256 }
238 257
239 // If we stop during starting/seeking/suspending/resuming we don't want to 258 // If we stop during starting/seeking/suspending/resuming we don't want to
240 // leave outstanding callbacks around. The callbacks also do not get run if 259 // leave outstanding callbacks around. The callbacks also do not get run if
241 // the pipeline is stopped before it had a chance to complete outstanding 260 // the pipeline is stopped before it had a chance to complete outstanding
242 // tasks. 261 // tasks.
243 pending_callbacks_.reset(); 262 pending_callbacks_.reset();
244 263
245 DoStop(stop_cb); 264 DestroyRenderer();
alokp 2016/06/24 06:15:06 DoStop() moved here.
265 text_renderer_.reset();
266
267 if (demuxer_) {
268 demuxer_->Stop();
269 demuxer_ = NULL;
270 }
271
272 SetState(kStopped);
273
274 // Post the stop callback to enqueue it after the tasks that may have been
275 // posted by Demuxer and Renderer during stopping. Note that in theory the
276 // tasks posted by Demuxer/Renderer may post even more tasks that will get
277 // enqueued after |stop_cb|. This may be problematic because Demuxer may
278 // get destroyed as soon as |stop_cb| is run. In practice this is not a
279 // problem, but ideally Demuxer should be destroyed on the media thread.
280 media_task_runner_->PostTask(FROM_HERE, stop_cb);
246 } 281 }
247 282
248 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) { 283 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) {
249 DCHECK(media_task_runner_->BelongsToCurrentThread()); 284 DCHECK(media_task_runner_->BelongsToCurrentThread());
250 285
251 // Suppress seeking if we're not fully started. 286 // Suppress seeking if we're not fully started.
252 if (state_ != kPlaying) { 287 if (state_ != kPlaying) {
253 DCHECK(state_ == kStopping || state_ == kStopped) 288 DCHECK(state_ == kStopping || state_ == kStopped)
254 << "Receive seek in unexpected state: " << state_; 289 << "Receive seek in unexpected state: " << state_;
255 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 290 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
256 return; 291 return;
257 } 292 }
258 293
259 const base::TimeDelta seek_timestamp = 294 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime());
260 std::max(time, demuxer_->GetStartTime());
261 295
262 SetState(kSeeking); 296 SetState(kSeeking);
263 renderer_ended_ = false; 297 renderer_ended_ = false;
264 text_renderer_ended_ = false; 298 text_renderer_ended_ = false;
265 start_timestamp_ = seek_timestamp;
266 299
267 DoSeek(seek_timestamp, 300 // Queue asynchronous actions required to start.
alokp 2016/06/24 06:15:07 DoSeek() moved here.
268 base::Bind(&RendererWrapper::StateTransitionTask, weak_this_)); 301 DCHECK(!pending_callbacks_);
302 SerialRunner::Queue bound_fns;
303
304 // Pause.
305 if (text_renderer_) {
306 bound_fns.Push(base::Bind(&TextRenderer::Pause,
307 base::Unretained(text_renderer_.get())));
308 }
309
310 // Flush.
311 DCHECK(shared_state_.renderer);
312 bound_fns.Push(base::Bind(&Renderer::Flush,
313 base::Unretained(shared_state_.renderer.get())));
314
315 if (text_renderer_) {
316 bound_fns.Push(base::Bind(&TextRenderer::Flush,
317 base::Unretained(text_renderer_.get())));
318 }
319
320 // Seek demuxer.
321 bound_fns.Push(
322 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
323
324 // Run tasks.
325 pending_callbacks_ = SerialRunner::Run(
326 bound_fns,
327 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, seek_timestamp));
269 } 328 }
270 329
271 void PipelineImpl::RendererWrapper::Suspend() { 330 void PipelineImpl::RendererWrapper::Suspend() {
272 DCHECK(media_task_runner_->BelongsToCurrentThread()); 331 DCHECK(media_task_runner_->BelongsToCurrentThread());
273 332
274 // Suppress suspending if we're not playing. 333 // Suppress suspending if we're not playing.
275 if (state_ != kPlaying) { 334 if (state_ != kPlaying) {
276 DCHECK(state_ == kStopping || state_ == kStopped) 335 DCHECK(state_ == kStopping || state_ == kStopped)
277 << "Receive suspend in unexpected state: " << state_; 336 << "Receive suspend in unexpected state: " << state_;
278 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 337 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
279 return; 338 return;
280 } 339 }
281 DCHECK(shared_state_.renderer); 340 DCHECK(shared_state_.renderer);
282 DCHECK(!pending_callbacks_.get()); 341 DCHECK(!pending_callbacks_.get());
283 342
284 SetState(kSuspending); 343 SetState(kSuspending);
285 344
286 // Freeze playback and record the media time before flushing. (Flushing clears 345 // Freeze playback and record the media time before flushing. (Flushing clears
287 // the value.) 346 // the value.)
288 shared_state_.renderer->SetPlaybackRate(0.0); 347 shared_state_.renderer->SetPlaybackRate(0.0);
289 { 348 {
290 base::AutoLock auto_lock(shared_state_lock_); 349 base::AutoLock auto_lock(shared_state_lock_);
291 shared_state_.suspend_timestamp = shared_state_.renderer->GetMediaTime(); 350 shared_state_.suspend_timestamp = shared_state_.renderer->GetMediaTime();
292 DCHECK(shared_state_.suspend_timestamp != kNoTimestamp()); 351 DCHECK(shared_state_.suspend_timestamp != kNoTimestamp());
293 } 352 }
294 353
295 // Queue the asynchronous actions required to stop playback. (Matches setup in 354 // Queue the asynchronous actions required to stop playback.
296 // DoSeek().)
297 // TODO(sandersd): Share implementation with DoSeek().
298 SerialRunner::Queue fns; 355 SerialRunner::Queue fns;
299 356
300 if (text_renderer_) { 357 if (text_renderer_) {
301 fns.Push(base::Bind(&TextRenderer::Pause, 358 fns.Push(base::Bind(&TextRenderer::Pause,
302 base::Unretained(text_renderer_.get()))); 359 base::Unretained(text_renderer_.get())));
303 } 360 }
304 361
305 fns.Push(base::Bind(&Renderer::Flush, 362 fns.Push(base::Bind(&Renderer::Flush,
306 base::Unretained(shared_state_.renderer.get()))); 363 base::Unretained(shared_state_.renderer.get())));
307 364
308 if (text_renderer_) { 365 if (text_renderer_) {
309 fns.Push(base::Bind(&TextRenderer::Flush, 366 fns.Push(base::Bind(&TextRenderer::Flush,
310 base::Unretained(text_renderer_.get()))); 367 base::Unretained(text_renderer_.get())));
311 } 368 }
312 369
313 pending_callbacks_ = SerialRunner::Run( 370 pending_callbacks_ = SerialRunner::Run(
314 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_)); 371 fns, base::Bind(&RendererWrapper::CompleteSuspend, weak_this_));
315 } 372 }
316 373
317 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer, 374 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer,
318 base::TimeDelta timestamp) { 375 base::TimeDelta timestamp) {
319 DCHECK(media_task_runner_->BelongsToCurrentThread()); 376 DCHECK(media_task_runner_->BelongsToCurrentThread());
320 377
321 // Suppress resuming if we're not suspended. 378 // Suppress resuming if we're not suspended.
322 if (state_ != kSuspended) { 379 if (state_ != kSuspended) {
323 DCHECK(state_ == kStopping || state_ == kStopped) 380 DCHECK(state_ == kStopping || state_ == kStopped)
324 << "Receive resume in unexpected state: " << state_; 381 << "Receive resume in unexpected state: " << state_;
325 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); 382 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
326 return; 383 return;
327 } 384 }
328 DCHECK(!shared_state_.renderer); 385 DCHECK(!shared_state_.renderer);
329 DCHECK(!pending_callbacks_.get()); 386 DCHECK(!pending_callbacks_.get());
330 387
331 SetState(kResuming); 388 SetState(kResuming);
332 389
333 { 390 {
334 base::AutoLock auto_lock(shared_state_lock_); 391 base::AutoLock auto_lock(shared_state_lock_);
335 shared_state_.renderer = std::move(renderer); 392 shared_state_.renderer = std::move(renderer);
336 } 393 }
337 394
338 // Set up for a seek. (Matches setup in SeekTask().)
339 // TODO(sandersd): Share implementation with SeekTask().
340 renderer_ended_ = false; 395 renderer_ended_ = false;
341 text_renderer_ended_ = false; 396 text_renderer_ended_ = false;
342 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime()); 397 base::TimeDelta start_timestamp =
398 std::max(timestamp, demuxer_->GetStartTime());
343 399
344 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), 400 // Queue the asynchronous actions required to start playback.
345 // we need to initialize the renderer ourselves (we don't want to enter state
346 // kInitDemuxer, and even if we did the current code would seek to the start
347 // instead of |timestamp|).
348 SerialRunner::Queue fns; 401 SerialRunner::Queue fns;
349 402
350 fns.Push( 403 fns.Push(
351 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); 404 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp));
352 405
353 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); 406 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_));
354 407
355 pending_callbacks_ = SerialRunner::Run( 408 pending_callbacks_ = SerialRunner::Run(
356 fns, base::Bind(&RendererWrapper::StateTransitionTask, weak_this_)); 409 fns,
410 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, start_timestamp));
357 } 411 }
358 412
359 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) { 413 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) {
360 DCHECK(media_task_runner_->BelongsToCurrentThread()); 414 DCHECK(media_task_runner_->BelongsToCurrentThread());
361 415
362 playback_rate_ = playback_rate; 416 playback_rate_ = playback_rate;
363 if (state_ == kPlaying) 417 if (state_ == kPlaying)
364 shared_state_.renderer->SetPlaybackRate(playback_rate_); 418 shared_state_.renderer->SetPlaybackRate(playback_rate_);
365 } 419 }
366 420
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 return; 666 return;
613 667
614 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) 668 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_)
615 return; 669 return;
616 670
617 DCHECK_EQ(status_, PIPELINE_OK); 671 DCHECK_EQ(status_, PIPELINE_OK);
618 main_task_runner_->PostTask( 672 main_task_runner_->PostTask(
619 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_)); 673 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_));
620 } 674 }
621 675
622 // Note that the usage of base::Unretained() with the renderers is considered
623 // safe as they are owned by |pending_callbacks_| and share the same lifetime.
624 //
625 // That being said, deleting the renderers while keeping |pending_callbacks_|
626 // running on the media thread would result in crashes.
627 void PipelineImpl::RendererWrapper::DoSeek(base::TimeDelta seek_timestamp,
628 const PipelineStatusCB& done_cb) {
629 DCHECK(media_task_runner_->BelongsToCurrentThread());
630 DCHECK(!pending_callbacks_.get());
631 DCHECK_EQ(state_, kSeeking);
632 SerialRunner::Queue bound_fns;
633
634 // Pause.
635 if (text_renderer_) {
636 bound_fns.Push(base::Bind(&TextRenderer::Pause,
637 base::Unretained(text_renderer_.get())));
638 }
639
640 // Flush.
641 DCHECK(shared_state_.renderer);
642 bound_fns.Push(base::Bind(&Renderer::Flush,
643 base::Unretained(shared_state_.renderer.get())));
644
645 if (text_renderer_) {
646 bound_fns.Push(base::Bind(&TextRenderer::Flush,
647 base::Unretained(text_renderer_.get())));
648 }
649
650 // Seek demuxer.
651 bound_fns.Push(
652 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
653
654 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
655 }
656
657 void PipelineImpl::RendererWrapper::DoStop(const base::Closure& done_cb) {
658 DVLOG(2) << __FUNCTION__;
659 DCHECK(media_task_runner_->BelongsToCurrentThread());
660 DCHECK_EQ(state_, kStopping);
661 DCHECK(!pending_callbacks_.get());
662
663 DestroyRenderer();
664 text_renderer_.reset();
665
666 if (demuxer_) {
667 demuxer_->Stop();
668 demuxer_ = NULL;
669 }
670
671 SetState(kStopped);
672
673 // Post the stop callback to enqueue it after the tasks that may have been
674 // posted by Demuxer and Renderer during stopping. Note that in theory the
675 // tasks posted by Demuxer/Renderer may post even more tasks that will get
676 // enqueued after |done_cb|. This may be problematic because Demuxer may
677 // get destroyed as soon as |done_cb| is run. In practice this is not a
678 // problem, but ideally Demuxer should be destroyed on the media thread.
679 media_task_runner_->PostTask(FROM_HERE, done_cb);
680 }
681
682 void PipelineImpl::RendererWrapper::SetState(State next_state) { 676 void PipelineImpl::RendererWrapper::SetState(State next_state) {
683 DCHECK(media_task_runner_->BelongsToCurrentThread()); 677 DCHECK(media_task_runner_->BelongsToCurrentThread());
684 DVLOG(1) << PipelineImpl::GetStateString(state_) << " -> " 678 DVLOG(1) << PipelineImpl::GetStateString(state_) << " -> "
685 << PipelineImpl::GetStateString(next_state); 679 << PipelineImpl::GetStateString(next_state);
686 680
687 state_ = next_state; 681 state_ = next_state;
688 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); 682 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state));
689 } 683 }
690 684
691 PipelineImpl::State PipelineImpl::RendererWrapper::GetNextState() const { 685 void PipelineImpl::RendererWrapper::CompleteSeek(base::TimeDelta seek_time,
686 PipelineStatus status) {
692 DCHECK(media_task_runner_->BelongsToCurrentThread()); 687 DCHECK(media_task_runner_->BelongsToCurrentThread());
693 DCHECK_EQ(status_, PIPELINE_OK) 688 DCHECK(state_ == kStarting || state_ == kSeeking || state_ == kResuming);
694 << "State transitions don't happen when there's an error: " << status_;
695 689
696 switch (state_) { 690 DCHECK(pending_callbacks_);
697 case kCreated: 691 pending_callbacks_.reset();
698 return kInitDemuxer;
699 692
700 case kInitDemuxer:
701 return kInitRenderer;
702
703 case kInitRenderer:
704 case kSeeking:
705 return kPlaying;
706
707 case kSuspending:
708 return kSuspended;
709
710 case kSuspended:
711 return kResuming;
712
713 case kResuming:
714 return kPlaying;
715
716 case kPlaying:
717 case kStopping:
718 case kStopped:
719 break;
720 }
721 NOTREACHED() << "State has no transition: " << state_;
722 return state_;
723 }
724 void PipelineImpl::RendererWrapper::StateTransitionTask(PipelineStatus status) {
725 DCHECK(media_task_runner_->BelongsToCurrentThread());
726
727 // No-op any state transitions if we're stopping or already encountered error.
728 if (state_ == kStopping || state_ == kStopped || status_ != PIPELINE_OK)
729 return;
730
731 // Report error from the previous operation.
732 if (status != PIPELINE_OK) { 693 if (status != PIPELINE_OK) {
733 OnPipelineError(status); 694 OnPipelineError(status);
734 return; 695 return;
735 } 696 }
736 697
737 // Guard against accidentally clearing |pending_callbacks_| for states that 698 shared_state_.renderer->StartPlayingFrom(
alokp 2016/06/24 06:15:07 copied from PipelineImpl::RendererWrapper::StateTr
738 // use it as well as states that should not be using it. 699 std::max(seek_time, demuxer_->GetStartTime()));
739 DCHECK_EQ(pending_callbacks_.get() != NULL, 700 {
740 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); 701 base::AutoLock auto_lock(shared_state_lock_);
702 shared_state_.suspend_timestamp = kNoTimestamp();
703 }
741 704
705 if (text_renderer_)
706 text_renderer_->StartPlaying();
707
708 shared_state_.renderer->SetPlaybackRate(playback_rate_);
709 shared_state_.renderer->SetVolume(volume_);
710
711 SetState(kPlaying);
712 main_task_runner_->PostTask(
713 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_));
714 }
715
716 void PipelineImpl::RendererWrapper::CompleteSuspend(PipelineStatus status) {
717 DCHECK(media_task_runner_->BelongsToCurrentThread());
718 DCHECK_EQ(kSuspending, state_);
719
720 DCHECK(pending_callbacks_);
742 pending_callbacks_.reset(); 721 pending_callbacks_.reset();
743 722
744 PipelineStatusCB done_cb = 723 // In case we are suspending or suspended, the error may be recoverable,
745 base::Bind(&RendererWrapper::StateTransitionTask, weak_this_); 724 // so don't propagate it now, instead let the subsequent seek during resume
725 // propagate it if it's unrecoverable.
726 LOG_IF(WARNING, status != PIPELINE_OK)
727 << "Encountered pipeline error while suspending: " << status;
746 728
747 // Switch states, performing any entrance actions for the new state as well. 729 DestroyRenderer();
alokp 2016/06/24 06:15:07 copied from PipelineImpl::RendererWrapper::StateTr
748 SetState(GetNextState()); 730 {
749 switch (state_) { 731 base::AutoLock auto_lock(shared_state_lock_);
750 case kInitDemuxer: 732 shared_state_.statistics.audio_memory_usage = 0;
751 return InitializeDemuxer(done_cb); 733 shared_state_.statistics.video_memory_usage = 0;
734 }
752 735
753 case kInitRenderer: 736 SetState(kSuspended);
754 // When the state_ transfers to kInitRenderer, it means the demuxer has 737 main_task_runner_->PostTask(
755 // finished parsing the init info. It should call ReportMetadata in case 738 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_));
756 // meeting 'decode' error when passing media segment but WebMediaPlayer's
757 // ready_state_ is still ReadyStateHaveNothing. In that case, it will
758 // treat it as NetworkStateFormatError not NetworkStateDecodeError.
759 ReportMetadata();
760 start_timestamp_ = demuxer_->GetStartTime();
761
762 return InitializeRenderer(done_cb);
763
764 case kPlaying:
765 DCHECK(start_timestamp_ >= base::TimeDelta());
766 shared_state_.renderer->StartPlayingFrom(start_timestamp_);
767 {
768 base::AutoLock auto_lock(shared_state_lock_);
769 shared_state_.suspend_timestamp = kNoTimestamp();
770 }
771
772 if (text_renderer_)
773 text_renderer_->StartPlaying();
774
775 main_task_runner_->PostTask(
776 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_,
777 start_timestamp_));
778
779 shared_state_.renderer->SetPlaybackRate(playback_rate_);
780 shared_state_.renderer->SetVolume(volume_);
781 return;
782
783 case kSuspended:
784 DestroyRenderer();
785 {
786 base::AutoLock auto_lock(shared_state_lock_);
787 shared_state_.statistics.audio_memory_usage = 0;
788 shared_state_.statistics.video_memory_usage = 0;
789 }
790 main_task_runner_->PostTask(
791 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_,
792 shared_state_.suspend_timestamp));
793 return;
794
795 case kStopping:
796 case kStopped:
797 case kCreated:
798 case kSeeking:
799 case kSuspending:
800 case kResuming:
801 NOTREACHED() << "State has no transition: " << state_;
802 return;
803 }
804 } 739 }
805 740
806 void PipelineImpl::RendererWrapper::InitializeDemuxer( 741 void PipelineImpl::RendererWrapper::InitializeDemuxer(
807 const PipelineStatusCB& done_cb) { 742 const PipelineStatusCB& done_cb) {
808 DCHECK(media_task_runner_->BelongsToCurrentThread()); 743 DCHECK(media_task_runner_->BelongsToCurrentThread());
809 744
810 demuxer_->Initialize(this, done_cb, !!text_renderer_); 745 demuxer_->Initialize(this, done_cb, !!text_renderer_);
811 } 746 }
812 747
813 void PipelineImpl::RendererWrapper::InitializeRenderer( 748 void PipelineImpl::RendererWrapper::InitializeRenderer(
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
1098 } 1033 }
1099 1034
1100 #define RETURN_STRING(state) \ 1035 #define RETURN_STRING(state) \
1101 case state: \ 1036 case state: \
1102 return #state; 1037 return #state;
1103 1038
1104 // static 1039 // static
1105 const char* PipelineImpl::GetStateString(State state) { 1040 const char* PipelineImpl::GetStateString(State state) {
1106 switch (state) { 1041 switch (state) {
1107 RETURN_STRING(kCreated); 1042 RETURN_STRING(kCreated);
1108 RETURN_STRING(kInitDemuxer); 1043 RETURN_STRING(kStarting);
1109 RETURN_STRING(kInitRenderer);
1110 RETURN_STRING(kSeeking); 1044 RETURN_STRING(kSeeking);
1111 RETURN_STRING(kPlaying); 1045 RETURN_STRING(kPlaying);
1112 RETURN_STRING(kStopping); 1046 RETURN_STRING(kStopping);
1113 RETURN_STRING(kStopped); 1047 RETURN_STRING(kStopped);
1114 RETURN_STRING(kSuspending); 1048 RETURN_STRING(kSuspending);
1115 RETURN_STRING(kSuspended); 1049 RETURN_STRING(kSuspended);
1116 RETURN_STRING(kResuming); 1050 RETURN_STRING(kResuming);
1117 } 1051 }
1118 NOTREACHED(); 1052 NOTREACHED();
1119 return "INVALID"; 1053 return "INVALID";
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1211 1145
1212 void PipelineImpl::OnVideoOpacityChange(bool opaque) { 1146 void PipelineImpl::OnVideoOpacityChange(bool opaque) {
1213 DVLOG(2) << __FUNCTION__; 1147 DVLOG(2) << __FUNCTION__;
1214 DCHECK(thread_checker_.CalledOnValidThread()); 1148 DCHECK(thread_checker_.CalledOnValidThread());
1215 DCHECK(IsRunning()); 1149 DCHECK(IsRunning());
1216 1150
1217 DCHECK(client_); 1151 DCHECK(client_);
1218 client_->OnVideoOpacityChange(opaque); 1152 client_->OnVideoOpacityChange(opaque);
1219 } 1153 }
1220 1154
1221 void PipelineImpl::OnSeekDone(base::TimeDelta start_time) { 1155 void PipelineImpl::OnSeekDone() {
1222 DVLOG(3) << __FUNCTION__ << "(" << start_time.InMicroseconds() << ")"; 1156 DVLOG(3) << __FUNCTION__;
1223 DCHECK(thread_checker_.CalledOnValidThread()); 1157 DCHECK(thread_checker_.CalledOnValidThread());
1224 DCHECK(IsRunning()); 1158 DCHECK(IsRunning());
1225 1159
1226 DCHECK(!seek_cb_.is_null()); 1160 DCHECK(!seek_cb_.is_null());
1227 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 1161 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1228 } 1162 }
1229 1163
1230 void PipelineImpl::OnSuspendDone(base::TimeDelta suspend_time) { 1164 void PipelineImpl::OnSuspendDone() {
1231 DVLOG(3) << __FUNCTION__ << "(" << suspend_time.InMicroseconds() << ")"; 1165 DVLOG(3) << __FUNCTION__;
1232 DCHECK(thread_checker_.CalledOnValidThread()); 1166 DCHECK(thread_checker_.CalledOnValidThread());
1233 DCHECK(IsRunning()); 1167 DCHECK(IsRunning());
1234 1168
1235 DCHECK(!suspend_cb_.is_null()); 1169 DCHECK(!suspend_cb_.is_null());
1236 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK); 1170 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK);
1237 } 1171 }
1238 1172
1239 } // namespace media 1173 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/base/pipeline_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698