| OLD | NEW |
| 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 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 running_(false), | 40 running_(false), |
| 41 did_loading_progress_(false), | 41 did_loading_progress_(false), |
| 42 volume_(1.0f), | 42 volume_(1.0f), |
| 43 playback_rate_(0.0), | 43 playback_rate_(0.0), |
| 44 status_(PIPELINE_OK), | 44 status_(PIPELINE_OK), |
| 45 state_(kCreated), | 45 state_(kCreated), |
| 46 suspend_timestamp_(kNoTimestamp()), | 46 suspend_timestamp_(kNoTimestamp()), |
| 47 renderer_ended_(false), | 47 renderer_ended_(false), |
| 48 text_renderer_ended_(false), | 48 text_renderer_ended_(false), |
| 49 demuxer_(NULL), | 49 demuxer_(NULL), |
| 50 pending_cdm_context_(nullptr), | 50 cdm_context_(nullptr), |
| 51 weak_factory_(this) { | 51 weak_factory_(this) { |
| 52 weak_this_ = weak_factory_.GetWeakPtr(); |
| 52 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 53 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
| 53 } | 54 } |
| 54 | 55 |
| 55 PipelineImpl::~PipelineImpl() { | 56 PipelineImpl::~PipelineImpl() { |
| 56 DCHECK(thread_checker_.CalledOnValidThread()) | 57 DCHECK(thread_checker_.CalledOnValidThread()) |
| 57 << "Pipeline must be destroyed on same thread that created it"; | 58 << "Pipeline must be destroyed on same thread that created it"; |
| 58 DCHECK(!running_) << "Stop() must complete before destroying object"; | 59 DCHECK(!running_) << "Stop() must complete before destroying object"; |
| 59 DCHECK(stop_cb_.is_null()); | 60 DCHECK(stop_cb_.is_null()); |
| 60 DCHECK(seek_cb_.is_null()); | 61 DCHECK(seek_cb_.is_null()); |
| 61 } | 62 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 84 renderer_ = std::move(renderer); | 85 renderer_ = std::move(renderer); |
| 85 ended_cb_ = ended_cb; | 86 ended_cb_ = ended_cb; |
| 86 error_cb_ = error_cb; | 87 error_cb_ = error_cb; |
| 87 seek_cb_ = seek_cb; | 88 seek_cb_ = seek_cb; |
| 88 metadata_cb_ = metadata_cb; | 89 metadata_cb_ = metadata_cb; |
| 89 buffering_state_cb_ = buffering_state_cb; | 90 buffering_state_cb_ = buffering_state_cb; |
| 90 duration_change_cb_ = duration_change_cb; | 91 duration_change_cb_ = duration_change_cb; |
| 91 add_text_track_cb_ = add_text_track_cb; | 92 add_text_track_cb_ = add_text_track_cb; |
| 92 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; | 93 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; |
| 93 | 94 |
| 94 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::StartTask, | 95 task_runner_->PostTask(FROM_HERE, |
| 95 weak_factory_.GetWeakPtr())); | 96 base::Bind(&PipelineImpl::StartTask, weak_this_)); |
| 96 } | 97 } |
| 97 | 98 |
| 98 void PipelineImpl::Stop(const base::Closure& stop_cb) { | 99 void PipelineImpl::Stop(const base::Closure& stop_cb) { |
| 99 DVLOG(2) << __FUNCTION__; | 100 DVLOG(2) << __FUNCTION__; |
| 100 task_runner_->PostTask( | 101 task_runner_->PostTask( |
| 101 FROM_HERE, | 102 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, stop_cb)); |
| 102 base::Bind(&PipelineImpl::StopTask, weak_factory_.GetWeakPtr(), stop_cb)); | |
| 103 } | 103 } |
| 104 | 104 |
| 105 void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { | 105 void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { |
| 106 base::AutoLock auto_lock(lock_); | 106 base::AutoLock auto_lock(lock_); |
| 107 if (!running_) { | 107 if (!running_) { |
| 108 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; | 108 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; |
| 109 return; | 109 return; |
| 110 } | 110 } |
| 111 | 111 |
| 112 task_runner_->PostTask( | 112 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SeekTask, |
| 113 FROM_HERE, base::Bind(&PipelineImpl::SeekTask, weak_factory_.GetWeakPtr(), | 113 weak_this_, time, seek_cb)); |
| 114 time, seek_cb)); | |
| 115 } | 114 } |
| 116 | 115 |
| 117 bool PipelineImpl::IsRunning() const { | 116 bool PipelineImpl::IsRunning() const { |
| 118 base::AutoLock auto_lock(lock_); | 117 base::AutoLock auto_lock(lock_); |
| 119 return running_; | 118 return running_; |
| 120 } | 119 } |
| 121 | 120 |
| 122 double PipelineImpl::GetPlaybackRate() const { | 121 double PipelineImpl::GetPlaybackRate() const { |
| 123 base::AutoLock auto_lock(lock_); | 122 base::AutoLock auto_lock(lock_); |
| 124 return playback_rate_; | 123 return playback_rate_; |
| 125 } | 124 } |
| 126 | 125 |
| 127 void PipelineImpl::SetPlaybackRate(double playback_rate) { | 126 void PipelineImpl::SetPlaybackRate(double playback_rate) { |
| 128 if (playback_rate < 0.0) | 127 if (playback_rate < 0.0) |
| 129 return; | 128 return; |
| 130 | 129 |
| 131 base::AutoLock auto_lock(lock_); | 130 base::AutoLock auto_lock(lock_); |
| 132 playback_rate_ = playback_rate; | 131 playback_rate_ = playback_rate; |
| 133 if (running_) { | 132 if (running_) { |
| 134 task_runner_->PostTask( | 133 task_runner_->PostTask(FROM_HERE, |
| 135 FROM_HERE, base::Bind(&PipelineImpl::PlaybackRateChangedTask, | 134 base::Bind(&PipelineImpl::PlaybackRateChangedTask, |
| 136 weak_factory_.GetWeakPtr(), playback_rate)); | 135 weak_this_, playback_rate)); |
| 137 } | 136 } |
| 138 } | 137 } |
| 139 | 138 |
| 140 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { | 139 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { |
| 141 task_runner_->PostTask(FROM_HERE, | 140 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SuspendTask, |
| 142 base::Bind(&PipelineImpl::SuspendTask, | 141 weak_this_, suspend_cb)); |
| 143 weak_factory_.GetWeakPtr(), suspend_cb)); | |
| 144 } | 142 } |
| 145 | 143 |
| 146 void PipelineImpl::Resume(scoped_ptr<Renderer> renderer, | 144 void PipelineImpl::Resume(scoped_ptr<Renderer> renderer, |
| 147 base::TimeDelta timestamp, | 145 base::TimeDelta timestamp, |
| 148 const PipelineStatusCB& seek_cb) { | 146 const PipelineStatusCB& seek_cb) { |
| 149 task_runner_->PostTask( | 147 task_runner_->PostTask( |
| 150 FROM_HERE, | 148 FROM_HERE, base::Bind(&PipelineImpl::ResumeTask, weak_this_, |
| 151 base::Bind(&PipelineImpl::ResumeTask, weak_factory_.GetWeakPtr(), | 149 base::Passed(&renderer), timestamp, seek_cb)); |
| 152 base::Passed(&renderer), timestamp, seek_cb)); | |
| 153 } | 150 } |
| 154 | 151 |
| 155 float PipelineImpl::GetVolume() const { | 152 float PipelineImpl::GetVolume() const { |
| 156 base::AutoLock auto_lock(lock_); | 153 base::AutoLock auto_lock(lock_); |
| 157 return volume_; | 154 return volume_; |
| 158 } | 155 } |
| 159 | 156 |
| 160 void PipelineImpl::SetVolume(float volume) { | 157 void PipelineImpl::SetVolume(float volume) { |
| 161 if (volume < 0.0f || volume > 1.0f) | 158 if (volume < 0.0f || volume > 1.0f) |
| 162 return; | 159 return; |
| 163 | 160 |
| 164 base::AutoLock auto_lock(lock_); | 161 base::AutoLock auto_lock(lock_); |
| 165 volume_ = volume; | 162 volume_ = volume; |
| 166 if (running_) { | 163 if (running_) { |
| 167 task_runner_->PostTask(FROM_HERE, | 164 task_runner_->PostTask( |
| 168 base::Bind(&PipelineImpl::VolumeChangedTask, | 165 FROM_HERE, |
| 169 weak_factory_.GetWeakPtr(), volume)); | 166 base::Bind(&PipelineImpl::VolumeChangedTask, weak_this_, volume)); |
| 170 } | 167 } |
| 171 } | 168 } |
| 172 | 169 |
| 173 TimeDelta PipelineImpl::GetMediaTime() const { | 170 TimeDelta PipelineImpl::GetMediaTime() const { |
| 174 base::AutoLock auto_lock(lock_); | 171 base::AutoLock auto_lock(lock_); |
| 175 if (suspend_timestamp_ != kNoTimestamp()) | 172 if (suspend_timestamp_ != kNoTimestamp()) |
| 176 return suspend_timestamp_; | 173 return suspend_timestamp_; |
| 177 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) | 174 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) |
| 178 : TimeDelta(); | 175 : TimeDelta(); |
| 179 } | 176 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 195 return ret; | 192 return ret; |
| 196 } | 193 } |
| 197 | 194 |
| 198 PipelineStatistics PipelineImpl::GetStatistics() const { | 195 PipelineStatistics PipelineImpl::GetStatistics() const { |
| 199 base::AutoLock auto_lock(lock_); | 196 base::AutoLock auto_lock(lock_); |
| 200 return statistics_; | 197 return statistics_; |
| 201 } | 198 } |
| 202 | 199 |
| 203 void PipelineImpl::SetCdm(CdmContext* cdm_context, | 200 void PipelineImpl::SetCdm(CdmContext* cdm_context, |
| 204 const CdmAttachedCB& cdm_attached_cb) { | 201 const CdmAttachedCB& cdm_attached_cb) { |
| 205 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, | 202 task_runner_->PostTask( |
| 206 weak_factory_.GetWeakPtr(), | 203 FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, weak_this_, cdm_context, |
| 207 cdm_context, cdm_attached_cb)); | 204 cdm_attached_cb)); |
| 208 } | 205 } |
| 209 | 206 |
| 210 void PipelineImpl::SetErrorForTesting(PipelineStatus status) { | 207 void PipelineImpl::SetErrorForTesting(PipelineStatus status) { |
| 211 OnError(status); | 208 OnError(status); |
| 212 } | 209 } |
| 213 | 210 |
| 214 bool PipelineImpl::HasWeakPtrsForTesting() const { | 211 bool PipelineImpl::HasWeakPtrsForTesting() const { |
| 215 DCHECK(task_runner_->BelongsToCurrentThread()); | 212 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 216 return weak_factory_.HasWeakPtrs(); | 213 return weak_factory_.HasWeakPtrs(); |
| 217 } | 214 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 case kPlaying: | 272 case kPlaying: |
| 276 case kStopping: | 273 case kStopping: |
| 277 case kStopped: | 274 case kStopped: |
| 278 break; | 275 break; |
| 279 } | 276 } |
| 280 NOTREACHED() << "State has no transition: " << state_; | 277 NOTREACHED() << "State has no transition: " << state_; |
| 281 return state_; | 278 return state_; |
| 282 } | 279 } |
| 283 | 280 |
| 284 void PipelineImpl::OnDemuxerError(PipelineStatus error) { | 281 void PipelineImpl::OnDemuxerError(PipelineStatus error) { |
| 285 task_runner_->PostTask(FROM_HERE, | 282 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::ErrorChangedTask, |
| 286 base::Bind(&PipelineImpl::ErrorChangedTask, | 283 weak_this_, error)); |
| 287 weak_factory_.GetWeakPtr(), error)); | |
| 288 } | 284 } |
| 289 | 285 |
| 290 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, | 286 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, |
| 291 const TextTrackConfig& config) { | 287 const TextTrackConfig& config) { |
| 292 task_runner_->PostTask( | 288 task_runner_->PostTask( |
| 293 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, | 289 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, weak_this_, |
| 294 weak_factory_.GetWeakPtr(), text_stream, config)); | 290 text_stream, config)); |
| 295 } | 291 } |
| 296 | 292 |
| 297 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { | 293 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { |
| 298 task_runner_->PostTask(FROM_HERE, | 294 task_runner_->PostTask( |
| 299 base::Bind(&PipelineImpl::RemoveTextStreamTask, | 295 FROM_HERE, |
| 300 weak_factory_.GetWeakPtr(), text_stream)); | 296 base::Bind(&PipelineImpl::RemoveTextStreamTask, weak_this_, text_stream)); |
| 301 } | 297 } |
| 302 | 298 |
| 303 void PipelineImpl::OnError(PipelineStatus error) { | 299 void PipelineImpl::OnError(PipelineStatus error) { |
| 304 DCHECK(task_runner_->BelongsToCurrentThread()); | 300 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 305 DCHECK(IsRunning()); | 301 DCHECK(IsRunning()); |
| 306 DCHECK_NE(PIPELINE_OK, error); | 302 DCHECK_NE(PIPELINE_OK, error); |
| 307 VLOG(1) << "Media pipeline error: " << error; | 303 VLOG(1) << "Media pipeline error: " << error; |
| 308 | 304 |
| 309 task_runner_->PostTask(FROM_HERE, | 305 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::ErrorChangedTask, |
| 310 base::Bind(&PipelineImpl::ErrorChangedTask, | 306 weak_this_, error)); |
| 311 weak_factory_.GetWeakPtr(), error)); | |
| 312 } | 307 } |
| 313 | 308 |
| 314 void PipelineImpl::SetDuration(TimeDelta duration) { | 309 void PipelineImpl::SetDuration(TimeDelta duration) { |
| 315 DCHECK(IsRunning()); | 310 DCHECK(IsRunning()); |
| 316 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, | 311 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, |
| 317 "duration", duration)); | 312 "duration", duration)); |
| 318 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 313 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
| 319 | 314 |
| 320 base::AutoLock auto_lock(lock_); | 315 base::AutoLock auto_lock(lock_); |
| 321 duration_ = duration; | 316 duration_ = duration; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 339 return; | 334 return; |
| 340 } | 335 } |
| 341 | 336 |
| 342 // Guard against accidentally clearing |pending_callbacks_| for states that | 337 // Guard against accidentally clearing |pending_callbacks_| for states that |
| 343 // use it as well as states that should not be using it. | 338 // use it as well as states that should not be using it. |
| 344 DCHECK_EQ(pending_callbacks_.get() != NULL, | 339 DCHECK_EQ(pending_callbacks_.get() != NULL, |
| 345 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); | 340 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); |
| 346 | 341 |
| 347 pending_callbacks_.reset(); | 342 pending_callbacks_.reset(); |
| 348 | 343 |
| 349 PipelineStatusCB done_cb = base::Bind(&PipelineImpl::StateTransitionTask, | 344 PipelineStatusCB done_cb = |
| 350 weak_factory_.GetWeakPtr()); | 345 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_); |
| 351 | 346 |
| 352 // Switch states, performing any entrance actions for the new state as well. | 347 // Switch states, performing any entrance actions for the new state as well. |
| 353 SetState(GetNextState()); | 348 SetState(GetNextState()); |
| 354 switch (state_) { | 349 switch (state_) { |
| 355 case kInitDemuxer: | 350 case kInitDemuxer: |
| 356 return InitializeDemuxer(done_cb); | 351 return InitializeDemuxer(done_cb); |
| 357 | 352 |
| 358 case kInitRenderer: | 353 case kInitRenderer: |
| 359 // When the state_ transfers to kInitRenderer, it means the demuxer has | 354 // When the state_ transfers to kInitRenderer, it means the demuxer has |
| 360 // finished parsing the init info. It should call ReportMetadata in case | 355 // finished parsing the init info. It should call ReportMetadata in case |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 } | 517 } |
| 523 | 518 |
| 524 void PipelineImpl::StartTask() { | 519 void PipelineImpl::StartTask() { |
| 525 DCHECK(task_runner_->BelongsToCurrentThread()); | 520 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 526 | 521 |
| 527 CHECK_EQ(kCreated, state_) | 522 CHECK_EQ(kCreated, state_) |
| 528 << "Media pipeline cannot be started more than once"; | 523 << "Media pipeline cannot be started more than once"; |
| 529 | 524 |
| 530 text_renderer_ = CreateTextRenderer(); | 525 text_renderer_ = CreateTextRenderer(); |
| 531 if (text_renderer_) { | 526 if (text_renderer_) { |
| 532 text_renderer_->Initialize(base::Bind(&PipelineImpl::OnTextRendererEnded, | 527 text_renderer_->Initialize( |
| 533 weak_factory_.GetWeakPtr())); | 528 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_)); |
| 534 } | |
| 535 | |
| 536 // Set CDM early to avoid unnecessary delay in Renderer::Initialize(). | |
| 537 if (pending_cdm_context_) { | |
| 538 renderer_->SetCdm(pending_cdm_context_, base::Bind(&IgnoreCdmAttached)); | |
| 539 pending_cdm_context_ = nullptr; | |
| 540 } | 529 } |
| 541 | 530 |
| 542 StateTransitionTask(PIPELINE_OK); | 531 StateTransitionTask(PIPELINE_OK); |
| 543 } | 532 } |
| 544 | 533 |
| 545 void PipelineImpl::StopTask(const base::Closure& stop_cb) { | 534 void PipelineImpl::StopTask(const base::Closure& stop_cb) { |
| 546 DCHECK(task_runner_->BelongsToCurrentThread()); | 535 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 547 DCHECK(stop_cb_.is_null()); | 536 DCHECK(stop_cb_.is_null()); |
| 548 | 537 |
| 549 if (state_ == kStopped) { | 538 if (state_ == kStopped) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 569 state_ == kSuspended || state_ == kResuming) { | 558 state_ == kSuspended || state_ == kResuming) { |
| 570 PipelineStatistics stats = GetStatistics(); | 559 PipelineStatistics stats = GetStatistics(); |
| 571 if (stats.video_frames_decoded > 0) { | 560 if (stats.video_frames_decoded > 0) { |
| 572 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", | 561 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", |
| 573 stats.video_frames_dropped); | 562 stats.video_frames_dropped); |
| 574 } | 563 } |
| 575 } | 564 } |
| 576 | 565 |
| 577 SetState(kStopping); | 566 SetState(kStopping); |
| 578 pending_callbacks_.reset(); | 567 pending_callbacks_.reset(); |
| 579 DoStop( | 568 DoStop(base::Bind(&PipelineImpl::OnStopCompleted, weak_this_)); |
| 580 base::Bind(&PipelineImpl::OnStopCompleted, weak_factory_.GetWeakPtr())); | |
| 581 } | 569 } |
| 582 | 570 |
| 583 void PipelineImpl::ErrorChangedTask(PipelineStatus error) { | 571 void PipelineImpl::ErrorChangedTask(PipelineStatus error) { |
| 584 DCHECK(task_runner_->BelongsToCurrentThread()); | 572 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 585 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; | 573 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; |
| 586 | 574 |
| 587 // Don't report pipeline error events to the media log here. The embedder will | 575 // Don't report pipeline error events to the media log here. The embedder will |
| 588 // log this when |error_cb_| is called. If the pipeline is already stopped or | 576 // log this when |error_cb_| is called. If the pipeline is already stopped or |
| 589 // stopping we also don't want to log any event. In case we are suspending or | 577 // stopping we also don't want to log any event. In case we are suspending or |
| 590 // suspended, the error may be recoverable, so don't propagate it now, instead | 578 // suspended, the error may be recoverable, so don't propagate it now, instead |
| 591 // let the subsequent seek during resume propagate it if it's unrecoverable. | 579 // let the subsequent seek during resume propagate it if it's unrecoverable. |
| 592 | 580 |
| 593 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending || | 581 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending || |
| 594 state_ == kSuspended) { | 582 state_ == kSuspended) { |
| 595 return; | 583 return; |
| 596 } | 584 } |
| 597 | 585 |
| 598 SetState(kStopping); | 586 SetState(kStopping); |
| 599 pending_callbacks_.reset(); | 587 pending_callbacks_.reset(); |
| 600 status_ = error; | 588 status_ = error; |
| 601 | 589 |
| 602 DoStop( | 590 DoStop(base::Bind(&PipelineImpl::OnStopCompleted, weak_this_)); |
| 603 base::Bind(&PipelineImpl::OnStopCompleted, weak_factory_.GetWeakPtr())); | |
| 604 } | 591 } |
| 605 | 592 |
| 606 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) { | 593 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) { |
| 607 DCHECK(task_runner_->BelongsToCurrentThread()); | 594 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 608 | 595 |
| 609 // Playback rate changes are only carried out while playing. | 596 // Playback rate changes are only carried out while playing. |
| 610 if (state_ != kPlaying) | 597 if (state_ != kPlaying) |
| 611 return; | 598 return; |
| 612 | 599 |
| 613 renderer_->SetPlaybackRate(playback_rate); | 600 renderer_->SetPlaybackRate(playback_rate); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 639 | 626 |
| 640 const base::TimeDelta seek_timestamp = | 627 const base::TimeDelta seek_timestamp = |
| 641 std::max(time, demuxer_->GetStartTime()); | 628 std::max(time, demuxer_->GetStartTime()); |
| 642 | 629 |
| 643 SetState(kSeeking); | 630 SetState(kSeeking); |
| 644 seek_cb_ = seek_cb; | 631 seek_cb_ = seek_cb; |
| 645 renderer_ended_ = false; | 632 renderer_ended_ = false; |
| 646 text_renderer_ended_ = false; | 633 text_renderer_ended_ = false; |
| 647 start_timestamp_ = seek_timestamp; | 634 start_timestamp_ = seek_timestamp; |
| 648 | 635 |
| 649 DoSeek(seek_timestamp, base::Bind(&PipelineImpl::StateTransitionTask, | 636 DoSeek(seek_timestamp, |
| 650 weak_factory_.GetWeakPtr())); | 637 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); |
| 651 } | 638 } |
| 652 | 639 |
| 653 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) { | 640 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) { |
| 654 DCHECK(task_runner_->BelongsToCurrentThread()); | 641 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 655 | 642 |
| 656 // Suppress suspending if we're not playing. | 643 // Suppress suspending if we're not playing. |
| 657 if (state_ != kPlaying) { | 644 if (state_ != kPlaying) { |
| 658 DCHECK(state_ == kStopping || state_ == kStopped) | 645 DCHECK(state_ == kStopping || state_ == kStopped) |
| 659 << "Receive suspend in unexpected state: " << state_; | 646 << "Receive suspend in unexpected state: " << state_; |
| 660 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); | 647 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 685 base::Unretained(text_renderer_.get()))); | 672 base::Unretained(text_renderer_.get()))); |
| 686 } | 673 } |
| 687 | 674 |
| 688 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); | 675 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); |
| 689 | 676 |
| 690 if (text_renderer_) { | 677 if (text_renderer_) { |
| 691 fns.Push(base::Bind(&TextRenderer::Flush, | 678 fns.Push(base::Bind(&TextRenderer::Flush, |
| 692 base::Unretained(text_renderer_.get()))); | 679 base::Unretained(text_renderer_.get()))); |
| 693 } | 680 } |
| 694 | 681 |
| 695 pending_callbacks_ = | 682 pending_callbacks_ = SerialRunner::Run( |
| 696 SerialRunner::Run(fns, base::Bind(&PipelineImpl::StateTransitionTask, | 683 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); |
| 697 weak_factory_.GetWeakPtr())); | |
| 698 } | 684 } |
| 699 | 685 |
| 700 void PipelineImpl::ResumeTask(scoped_ptr<Renderer> renderer, | 686 void PipelineImpl::ResumeTask(scoped_ptr<Renderer> renderer, |
| 701 base::TimeDelta timestamp, | 687 base::TimeDelta timestamp, |
| 702 const PipelineStatusCB& seek_cb) { | 688 const PipelineStatusCB& seek_cb) { |
| 703 DCHECK(task_runner_->BelongsToCurrentThread()); | 689 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 704 | 690 |
| 705 // Suppress resuming if we're not suspended. | 691 // Suppress resuming if we're not suspended. |
| 706 if (state_ != kSuspended) { | 692 if (state_ != kSuspended) { |
| 707 DCHECK(state_ == kStopping || state_ == kStopped) | 693 DCHECK(state_ == kStopping || state_ == kStopped) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 720 seek_cb_ = seek_cb; | 706 seek_cb_ = seek_cb; |
| 721 renderer_ended_ = false; | 707 renderer_ended_ = false; |
| 722 text_renderer_ended_ = false; | 708 text_renderer_ended_ = false; |
| 723 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime()); | 709 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime()); |
| 724 | 710 |
| 725 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), | 711 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), |
| 726 // we need to initialize the renderer ourselves (we don't want to enter state | 712 // we need to initialize the renderer ourselves (we don't want to enter state |
| 727 // kInitDemuxer, and even if we did the current code would seek to the start | 713 // kInitDemuxer, and even if we did the current code would seek to the start |
| 728 // instead of |timestamp|). | 714 // instead of |timestamp|). |
| 729 SerialRunner::Queue fns; | 715 SerialRunner::Queue fns; |
| 730 base::WeakPtr<PipelineImpl> weak_this = weak_factory_.GetWeakPtr(); | |
| 731 | 716 |
| 732 fns.Push( | 717 fns.Push( |
| 733 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); | 718 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); |
| 734 | 719 |
| 735 fns.Push(base::Bind(&PipelineImpl::InitializeRenderer, weak_this)); | 720 fns.Push(base::Bind(&PipelineImpl::InitializeRenderer, weak_this_)); |
| 736 | 721 |
| 737 pending_callbacks_ = SerialRunner::Run( | 722 pending_callbacks_ = SerialRunner::Run( |
| 738 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this)); | 723 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); |
| 739 } | 724 } |
| 740 | 725 |
| 741 void PipelineImpl::SetCdmTask(CdmContext* cdm_context, | 726 void PipelineImpl::SetCdmTask(CdmContext* cdm_context, |
| 742 const CdmAttachedCB& cdm_attached_cb) { | 727 const CdmAttachedCB& cdm_attached_cb) { |
| 743 base::AutoLock auto_lock(lock_); | 728 base::AutoLock auto_lock(lock_); |
| 744 if (!renderer_) { | 729 if (!renderer_) { |
| 745 pending_cdm_context_ = cdm_context; | 730 cdm_context_ = cdm_context; |
| 746 cdm_attached_cb.Run(true); | 731 cdm_attached_cb.Run(true); |
| 747 return; | 732 return; |
| 748 } | 733 } |
| 749 | 734 |
| 750 renderer_->SetCdm(cdm_context, cdm_attached_cb); | 735 renderer_->SetCdm(cdm_context, |
| 736 base::Bind(&PipelineImpl::OnCdmAttached, weak_this_, |
| 737 cdm_attached_cb, cdm_context)); |
| 738 } |
| 739 |
| 740 void PipelineImpl::OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, |
| 741 CdmContext* cdm_context, |
| 742 bool success) { |
| 743 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 744 if (success) |
| 745 cdm_context_ = cdm_context; |
| 746 cdm_attached_cb.Run(success); |
| 751 } | 747 } |
| 752 | 748 |
| 753 void PipelineImpl::OnRendererEnded() { | 749 void PipelineImpl::OnRendererEnded() { |
| 754 DCHECK(task_runner_->BelongsToCurrentThread()); | 750 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 755 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); | 751 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); |
| 756 | 752 |
| 757 if (state_ != kPlaying) | 753 if (state_ != kPlaying) |
| 758 return; | 754 return; |
| 759 | 755 |
| 760 DCHECK(!renderer_ended_); | 756 DCHECK(!renderer_ended_); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 790 } | 786 } |
| 791 | 787 |
| 792 scoped_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { | 788 scoped_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { |
| 793 DCHECK(task_runner_->BelongsToCurrentThread()); | 789 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 794 | 790 |
| 795 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 791 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 796 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) | 792 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) |
| 797 return scoped_ptr<media::TextRenderer>(); | 793 return scoped_ptr<media::TextRenderer>(); |
| 798 | 794 |
| 799 return scoped_ptr<media::TextRenderer>(new media::TextRenderer( | 795 return scoped_ptr<media::TextRenderer>(new media::TextRenderer( |
| 800 task_runner_, | 796 task_runner_, base::Bind(&PipelineImpl::OnAddTextTrack, weak_this_))); |
| 801 base::Bind(&PipelineImpl::OnAddTextTrack, weak_factory_.GetWeakPtr()))); | |
| 802 } | 797 } |
| 803 | 798 |
| 804 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream, | 799 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream, |
| 805 const TextTrackConfig& config) { | 800 const TextTrackConfig& config) { |
| 806 DCHECK(task_runner_->BelongsToCurrentThread()); | 801 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 807 // TODO(matthewjheaney): fix up text_ended_ when text stream | 802 // TODO(matthewjheaney): fix up text_ended_ when text stream |
| 808 // is added (http://crbug.com/321446). | 803 // is added (http://crbug.com/321446). |
| 809 if (text_renderer_) | 804 if (text_renderer_) |
| 810 text_renderer_->AddTextStream(text_stream, config); | 805 text_renderer_->AddTextStream(text_stream, config); |
| 811 } | 806 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 833 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && | 828 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && |
| 834 !demuxer_->GetStream(DemuxerStream::VIDEO)) { | 829 !demuxer_->GetStream(DemuxerStream::VIDEO)) { |
| 835 { | 830 { |
| 836 base::AutoLock auto_lock(lock_); | 831 base::AutoLock auto_lock(lock_); |
| 837 renderer_.reset(); | 832 renderer_.reset(); |
| 838 } | 833 } |
| 839 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); | 834 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); |
| 840 return; | 835 return; |
| 841 } | 836 } |
| 842 | 837 |
| 843 base::WeakPtr<PipelineImpl> weak_this = weak_factory_.GetWeakPtr(); | 838 if (cdm_context_) |
| 839 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); |
| 840 |
| 844 renderer_->Initialize( | 841 renderer_->Initialize( |
| 845 demuxer_, done_cb, | 842 demuxer_, done_cb, |
| 846 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this), | 843 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this_), |
| 847 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this), | 844 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this_), |
| 848 base::Bind(&PipelineImpl::OnRendererEnded, weak_this), | 845 base::Bind(&PipelineImpl::OnRendererEnded, weak_this_), |
| 849 base::Bind(&PipelineImpl::OnError, weak_this), | 846 base::Bind(&PipelineImpl::OnError, weak_this_), |
| 850 waiting_for_decryption_key_cb_); | 847 waiting_for_decryption_key_cb_); |
| 851 } | 848 } |
| 852 | 849 |
| 853 void PipelineImpl::ReportMetadata() { | 850 void PipelineImpl::ReportMetadata() { |
| 854 DCHECK(task_runner_->BelongsToCurrentThread()); | 851 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 855 PipelineMetadata metadata; | 852 PipelineMetadata metadata; |
| 856 metadata.timeline_offset = demuxer_->GetTimelineOffset(); | 853 metadata.timeline_offset = demuxer_->GetTimelineOffset(); |
| 857 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | 854 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
| 858 if (stream) { | 855 if (stream) { |
| 859 metadata.has_video = true; | 856 metadata.has_video = true; |
| 860 metadata.natural_size = stream->video_decoder_config().natural_size(); | 857 metadata.natural_size = stream->video_decoder_config().natural_size(); |
| 861 metadata.video_rotation = stream->video_rotation(); | 858 metadata.video_rotation = stream->video_rotation(); |
| 862 } | 859 } |
| 863 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { | 860 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { |
| 864 metadata.has_audio = true; | 861 metadata.has_audio = true; |
| 865 } | 862 } |
| 866 metadata_cb_.Run(metadata); | 863 metadata_cb_.Run(metadata); |
| 867 } | 864 } |
| 868 | 865 |
| 869 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { | 866 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { |
| 870 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; | 867 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; |
| 871 DCHECK(task_runner_->BelongsToCurrentThread()); | 868 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 872 buffering_state_cb_.Run(new_buffering_state); | 869 buffering_state_cb_.Run(new_buffering_state); |
| 873 } | 870 } |
| 874 | 871 |
| 875 } // namespace media | 872 } // namespace media |
| OLD | NEW |