| 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.h" | 5 #include "media/base/pipeline.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 14 matching lines...) Expand all Loading... |
| 25 #include "media/base/renderer.h" | 25 #include "media/base/renderer.h" |
| 26 #include "media/base/text_renderer.h" | 26 #include "media/base/text_renderer.h" |
| 27 #include "media/base/text_track_config.h" | 27 #include "media/base/text_track_config.h" |
| 28 #include "media/base/timestamp_constants.h" | 28 #include "media/base/timestamp_constants.h" |
| 29 #include "media/base/video_decoder_config.h" | 29 #include "media/base/video_decoder_config.h" |
| 30 | 30 |
| 31 using base::TimeDelta; | 31 using base::TimeDelta; |
| 32 | 32 |
| 33 namespace media { | 33 namespace media { |
| 34 | 34 |
| 35 Pipeline::Pipeline( | 35 PipelineImpl::PipelineImpl( |
| 36 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 36 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 37 MediaLog* media_log) | 37 MediaLog* media_log) |
| 38 : task_runner_(task_runner), | 38 : task_runner_(task_runner), |
| 39 media_log_(media_log), | 39 media_log_(media_log), |
| 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 pending_cdm_context_(nullptr), |
| 51 weak_factory_(this) { | 51 weak_factory_(this) { |
| 52 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 52 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
| 53 } | 53 } |
| 54 | 54 |
| 55 Pipeline::~Pipeline() { | 55 PipelineImpl::~PipelineImpl() { |
| 56 DCHECK(thread_checker_.CalledOnValidThread()) | 56 DCHECK(thread_checker_.CalledOnValidThread()) |
| 57 << "Pipeline must be destroyed on same thread that created it"; | 57 << "Pipeline must be destroyed on same thread that created it"; |
| 58 DCHECK(!running_) << "Stop() must complete before destroying object"; | 58 DCHECK(!running_) << "Stop() must complete before destroying object"; |
| 59 DCHECK(stop_cb_.is_null()); | 59 DCHECK(stop_cb_.is_null()); |
| 60 DCHECK(seek_cb_.is_null()); | 60 DCHECK(seek_cb_.is_null()); |
| 61 } | 61 } |
| 62 | 62 |
| 63 void Pipeline::Start(Demuxer* demuxer, | 63 void PipelineImpl::Start(Demuxer* demuxer, |
| 64 scoped_ptr<Renderer> renderer, | 64 scoped_ptr<Renderer> renderer, |
| 65 const base::Closure& ended_cb, | 65 const base::Closure& ended_cb, |
| 66 const PipelineStatusCB& error_cb, | 66 const PipelineStatusCB& error_cb, |
| 67 const PipelineStatusCB& seek_cb, | 67 const PipelineStatusCB& seek_cb, |
| 68 const PipelineMetadataCB& metadata_cb, | 68 const PipelineMetadataCB& metadata_cb, |
| 69 const BufferingStateCB& buffering_state_cb, | 69 const BufferingStateCB& buffering_state_cb, |
| 70 const base::Closure& duration_change_cb, | 70 const base::Closure& duration_change_cb, |
| 71 const AddTextTrackCB& add_text_track_cb, | 71 const AddTextTrackCB& add_text_track_cb, |
| 72 const base::Closure& waiting_for_decryption_key_cb) { | 72 const base::Closure& waiting_for_decryption_key_cb) { |
| 73 DCHECK(!ended_cb.is_null()); | 73 DCHECK(!ended_cb.is_null()); |
| 74 DCHECK(!error_cb.is_null()); | 74 DCHECK(!error_cb.is_null()); |
| 75 DCHECK(!seek_cb.is_null()); | 75 DCHECK(!seek_cb.is_null()); |
| 76 DCHECK(!metadata_cb.is_null()); | 76 DCHECK(!metadata_cb.is_null()); |
| 77 DCHECK(!buffering_state_cb.is_null()); | 77 DCHECK(!buffering_state_cb.is_null()); |
| 78 | 78 |
| 79 base::AutoLock auto_lock(lock_); | 79 base::AutoLock auto_lock(lock_); |
| 80 CHECK(!running_) << "Media pipeline is already running"; | 80 CHECK(!running_) << "Media pipeline is already running"; |
| 81 running_ = true; | 81 running_ = true; |
| 82 | 82 |
| 83 demuxer_ = demuxer; | 83 demuxer_ = demuxer; |
| 84 renderer_ = std::move(renderer); | 84 renderer_ = std::move(renderer); |
| 85 ended_cb_ = ended_cb; | 85 ended_cb_ = ended_cb; |
| 86 error_cb_ = error_cb; | 86 error_cb_ = error_cb; |
| 87 seek_cb_ = seek_cb; | 87 seek_cb_ = seek_cb; |
| 88 metadata_cb_ = metadata_cb; | 88 metadata_cb_ = metadata_cb; |
| 89 buffering_state_cb_ = buffering_state_cb; | 89 buffering_state_cb_ = buffering_state_cb; |
| 90 duration_change_cb_ = duration_change_cb; | 90 duration_change_cb_ = duration_change_cb; |
| 91 add_text_track_cb_ = add_text_track_cb; | 91 add_text_track_cb_ = add_text_track_cb; |
| 92 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; | 92 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; |
| 93 | 93 |
| 94 task_runner_->PostTask( | 94 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::StartTask, |
| 95 FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr())); | 95 weak_factory_.GetWeakPtr())); |
| 96 } | 96 } |
| 97 | 97 |
| 98 void Pipeline::Stop(const base::Closure& stop_cb) { | 98 void PipelineImpl::Stop(const base::Closure& stop_cb) { |
| 99 DVLOG(2) << __FUNCTION__; | 99 DVLOG(2) << __FUNCTION__; |
| 100 task_runner_->PostTask( | 100 task_runner_->PostTask( |
| 101 FROM_HERE, | 101 FROM_HERE, |
| 102 base::Bind(&Pipeline::StopTask, weak_factory_.GetWeakPtr(), stop_cb)); | 102 base::Bind(&PipelineImpl::StopTask, weak_factory_.GetWeakPtr(), stop_cb)); |
| 103 } | 103 } |
| 104 | 104 |
| 105 void Pipeline::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( |
| 113 FROM_HERE, | 113 FROM_HERE, base::Bind(&PipelineImpl::SeekTask, weak_factory_.GetWeakPtr(), |
| 114 base::Bind( | 114 time, seek_cb)); |
| 115 &Pipeline::SeekTask, weak_factory_.GetWeakPtr(), time, seek_cb)); | |
| 116 } | 115 } |
| 117 | 116 |
| 118 bool Pipeline::IsRunning() const { | 117 bool PipelineImpl::IsRunning() const { |
| 119 base::AutoLock auto_lock(lock_); | 118 base::AutoLock auto_lock(lock_); |
| 120 return running_; | 119 return running_; |
| 121 } | 120 } |
| 122 | 121 |
| 123 double Pipeline::GetPlaybackRate() const { | 122 double PipelineImpl::GetPlaybackRate() const { |
| 124 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
| 125 return playback_rate_; | 124 return playback_rate_; |
| 126 } | 125 } |
| 127 | 126 |
| 128 void Pipeline::SetPlaybackRate(double playback_rate) { | 127 void PipelineImpl::SetPlaybackRate(double playback_rate) { |
| 129 if (playback_rate < 0.0) | 128 if (playback_rate < 0.0) |
| 130 return; | 129 return; |
| 131 | 130 |
| 132 base::AutoLock auto_lock(lock_); | 131 base::AutoLock auto_lock(lock_); |
| 133 playback_rate_ = playback_rate; | 132 playback_rate_ = playback_rate; |
| 134 if (running_) { | 133 if (running_) { |
| 135 task_runner_->PostTask(FROM_HERE, | 134 task_runner_->PostTask( |
| 136 base::Bind(&Pipeline::PlaybackRateChangedTask, | 135 FROM_HERE, base::Bind(&PipelineImpl::PlaybackRateChangedTask, |
| 137 weak_factory_.GetWeakPtr(), | 136 weak_factory_.GetWeakPtr(), playback_rate)); |
| 138 playback_rate)); | |
| 139 } | 137 } |
| 140 } | 138 } |
| 141 | 139 |
| 142 void Pipeline::Suspend(const PipelineStatusCB& suspend_cb) { | 140 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { |
| 143 task_runner_->PostTask( | 141 task_runner_->PostTask(FROM_HERE, |
| 144 FROM_HERE, base::Bind(&Pipeline::SuspendTask, weak_factory_.GetWeakPtr(), | 142 base::Bind(&PipelineImpl::SuspendTask, |
| 145 suspend_cb)); | 143 weak_factory_.GetWeakPtr(), suspend_cb)); |
| 146 } | 144 } |
| 147 | 145 |
| 148 void Pipeline::Resume(scoped_ptr<Renderer> renderer, | 146 void PipelineImpl::Resume(scoped_ptr<Renderer> renderer, |
| 149 base::TimeDelta timestamp, | 147 base::TimeDelta timestamp, |
| 150 const PipelineStatusCB& seek_cb) { | 148 const PipelineStatusCB& seek_cb) { |
| 151 task_runner_->PostTask( | 149 task_runner_->PostTask( |
| 152 FROM_HERE, | 150 FROM_HERE, |
| 153 base::Bind(&Pipeline::ResumeTask, weak_factory_.GetWeakPtr(), | 151 base::Bind(&PipelineImpl::ResumeTask, weak_factory_.GetWeakPtr(), |
| 154 base::Passed(std::move(renderer)), timestamp, seek_cb)); | 152 base::Passed(&renderer), timestamp, seek_cb)); |
| 155 } | 153 } |
| 156 | 154 |
| 157 float Pipeline::GetVolume() const { | 155 float PipelineImpl::GetVolume() const { |
| 158 base::AutoLock auto_lock(lock_); | 156 base::AutoLock auto_lock(lock_); |
| 159 return volume_; | 157 return volume_; |
| 160 } | 158 } |
| 161 | 159 |
| 162 void Pipeline::SetVolume(float volume) { | 160 void PipelineImpl::SetVolume(float volume) { |
| 163 if (volume < 0.0f || volume > 1.0f) | 161 if (volume < 0.0f || volume > 1.0f) |
| 164 return; | 162 return; |
| 165 | 163 |
| 166 base::AutoLock auto_lock(lock_); | 164 base::AutoLock auto_lock(lock_); |
| 167 volume_ = volume; | 165 volume_ = volume; |
| 168 if (running_) { | 166 if (running_) { |
| 169 task_runner_->PostTask( | 167 task_runner_->PostTask(FROM_HERE, |
| 170 FROM_HERE, | 168 base::Bind(&PipelineImpl::VolumeChangedTask, |
| 171 base::Bind( | 169 weak_factory_.GetWeakPtr(), volume)); |
| 172 &Pipeline::VolumeChangedTask, weak_factory_.GetWeakPtr(), volume)); | |
| 173 } | 170 } |
| 174 } | 171 } |
| 175 | 172 |
| 176 TimeDelta Pipeline::GetMediaTime() const { | 173 TimeDelta PipelineImpl::GetMediaTime() const { |
| 177 base::AutoLock auto_lock(lock_); | 174 base::AutoLock auto_lock(lock_); |
| 178 if (suspend_timestamp_ != kNoTimestamp()) | 175 if (suspend_timestamp_ != kNoTimestamp()) |
| 179 return suspend_timestamp_; | 176 return suspend_timestamp_; |
| 180 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) | 177 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) |
| 181 : TimeDelta(); | 178 : TimeDelta(); |
| 182 } | 179 } |
| 183 | 180 |
| 184 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { | 181 Ranges<TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { |
| 185 base::AutoLock auto_lock(lock_); | 182 base::AutoLock auto_lock(lock_); |
| 186 return buffered_time_ranges_; | 183 return buffered_time_ranges_; |
| 187 } | 184 } |
| 188 | 185 |
| 189 TimeDelta Pipeline::GetMediaDuration() const { | 186 TimeDelta PipelineImpl::GetMediaDuration() const { |
| 190 base::AutoLock auto_lock(lock_); | 187 base::AutoLock auto_lock(lock_); |
| 191 return duration_; | 188 return duration_; |
| 192 } | 189 } |
| 193 | 190 |
| 194 bool Pipeline::DidLoadingProgress() { | 191 bool PipelineImpl::DidLoadingProgress() { |
| 195 base::AutoLock auto_lock(lock_); | 192 base::AutoLock auto_lock(lock_); |
| 196 bool ret = did_loading_progress_; | 193 bool ret = did_loading_progress_; |
| 197 did_loading_progress_ = false; | 194 did_loading_progress_ = false; |
| 198 return ret; | 195 return ret; |
| 199 } | 196 } |
| 200 | 197 |
| 201 PipelineStatistics Pipeline::GetStatistics() const { | 198 PipelineStatistics PipelineImpl::GetStatistics() const { |
| 202 base::AutoLock auto_lock(lock_); | 199 base::AutoLock auto_lock(lock_); |
| 203 return statistics_; | 200 return statistics_; |
| 204 } | 201 } |
| 205 | 202 |
| 206 void Pipeline::SetCdm(CdmContext* cdm_context, | 203 void PipelineImpl::SetCdm(CdmContext* cdm_context, |
| 207 const CdmAttachedCB& cdm_attached_cb) { | 204 const CdmAttachedCB& cdm_attached_cb) { |
| 208 task_runner_->PostTask( | 205 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, |
| 209 FROM_HERE, base::Bind(&Pipeline::SetCdmTask, weak_factory_.GetWeakPtr(), | 206 weak_factory_.GetWeakPtr(), |
| 210 cdm_context, cdm_attached_cb)); | 207 cdm_context, cdm_attached_cb)); |
| 211 } | 208 } |
| 212 | 209 |
| 213 void Pipeline::SetErrorForTesting(PipelineStatus status) { | 210 void PipelineImpl::SetErrorForTesting(PipelineStatus status) { |
| 214 OnError(status); | 211 OnError(status); |
| 215 } | 212 } |
| 216 | 213 |
| 217 bool Pipeline::HasWeakPtrsForTesting() const { | 214 bool PipelineImpl::HasWeakPtrsForTesting() const { |
| 218 DCHECK(task_runner_->BelongsToCurrentThread()); | 215 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 219 return weak_factory_.HasWeakPtrs(); | 216 return weak_factory_.HasWeakPtrs(); |
| 220 } | 217 } |
| 221 | 218 |
| 222 void Pipeline::SetState(State next_state) { | 219 void PipelineImpl::SetState(State next_state) { |
| 223 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); | 220 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); |
| 224 | 221 |
| 225 state_ = next_state; | 222 state_ = next_state; |
| 226 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); | 223 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); |
| 227 } | 224 } |
| 228 | 225 |
| 229 #define RETURN_STRING(state) case state: return #state; | 226 #define RETURN_STRING(state) case state: return #state; |
| 230 | 227 |
| 231 const char* Pipeline::GetStateString(State state) { | 228 const char* PipelineImpl::GetStateString(State state) { |
| 232 switch (state) { | 229 switch (state) { |
| 233 RETURN_STRING(kCreated); | 230 RETURN_STRING(kCreated); |
| 234 RETURN_STRING(kInitDemuxer); | 231 RETURN_STRING(kInitDemuxer); |
| 235 RETURN_STRING(kInitRenderer); | 232 RETURN_STRING(kInitRenderer); |
| 236 RETURN_STRING(kSeeking); | 233 RETURN_STRING(kSeeking); |
| 237 RETURN_STRING(kPlaying); | 234 RETURN_STRING(kPlaying); |
| 238 RETURN_STRING(kStopping); | 235 RETURN_STRING(kStopping); |
| 239 RETURN_STRING(kStopped); | 236 RETURN_STRING(kStopped); |
| 240 RETURN_STRING(kSuspending); | 237 RETURN_STRING(kSuspending); |
| 241 RETURN_STRING(kSuspended); | 238 RETURN_STRING(kSuspended); |
| 242 RETURN_STRING(kResuming); | 239 RETURN_STRING(kResuming); |
| 243 } | 240 } |
| 244 NOTREACHED(); | 241 NOTREACHED(); |
| 245 return "INVALID"; | 242 return "INVALID"; |
| 246 } | 243 } |
| 247 | 244 |
| 248 #undef RETURN_STRING | 245 #undef RETURN_STRING |
| 249 | 246 |
| 250 Pipeline::State Pipeline::GetNextState() const { | 247 PipelineImpl::State PipelineImpl::GetNextState() const { |
| 251 DCHECK(task_runner_->BelongsToCurrentThread()); | 248 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 252 DCHECK(stop_cb_.is_null()) | 249 DCHECK(stop_cb_.is_null()) |
| 253 << "State transitions don't happen when stopping"; | 250 << "State transitions don't happen when stopping"; |
| 254 DCHECK_EQ(status_, PIPELINE_OK) | 251 DCHECK_EQ(status_, PIPELINE_OK) |
| 255 << "State transitions don't happen when there's an error: " << status_; | 252 << "State transitions don't happen when there's an error: " << status_; |
| 256 | 253 |
| 257 switch (state_) { | 254 switch (state_) { |
| 258 case kCreated: | 255 case kCreated: |
| 259 return kInitDemuxer; | 256 return kInitDemuxer; |
| 260 | 257 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 276 | 273 |
| 277 case kPlaying: | 274 case kPlaying: |
| 278 case kStopping: | 275 case kStopping: |
| 279 case kStopped: | 276 case kStopped: |
| 280 break; | 277 break; |
| 281 } | 278 } |
| 282 NOTREACHED() << "State has no transition: " << state_; | 279 NOTREACHED() << "State has no transition: " << state_; |
| 283 return state_; | 280 return state_; |
| 284 } | 281 } |
| 285 | 282 |
| 286 void Pipeline::OnDemuxerError(PipelineStatus error) { | 283 void PipelineImpl::OnDemuxerError(PipelineStatus error) { |
| 287 task_runner_->PostTask(FROM_HERE, | 284 task_runner_->PostTask(FROM_HERE, |
| 288 base::Bind(&Pipeline::ErrorChangedTask, | 285 base::Bind(&PipelineImpl::ErrorChangedTask, |
| 289 weak_factory_.GetWeakPtr(), | 286 weak_factory_.GetWeakPtr(), error)); |
| 290 error)); | |
| 291 } | 287 } |
| 292 | 288 |
| 293 void Pipeline::AddTextStream(DemuxerStream* text_stream, | 289 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, |
| 294 const TextTrackConfig& config) { | 290 const TextTrackConfig& config) { |
| 295 task_runner_->PostTask(FROM_HERE, | 291 task_runner_->PostTask( |
| 296 base::Bind(&Pipeline::AddTextStreamTask, | 292 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, |
| 297 weak_factory_.GetWeakPtr(), | 293 weak_factory_.GetWeakPtr(), text_stream, config)); |
| 298 text_stream, | |
| 299 config)); | |
| 300 } | 294 } |
| 301 | 295 |
| 302 void Pipeline::RemoveTextStream(DemuxerStream* text_stream) { | 296 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { |
| 303 task_runner_->PostTask(FROM_HERE, | 297 task_runner_->PostTask(FROM_HERE, |
| 304 base::Bind(&Pipeline::RemoveTextStreamTask, | 298 base::Bind(&PipelineImpl::RemoveTextStreamTask, |
| 305 weak_factory_.GetWeakPtr(), | 299 weak_factory_.GetWeakPtr(), text_stream)); |
| 306 text_stream)); | |
| 307 } | 300 } |
| 308 | 301 |
| 309 void Pipeline::OnError(PipelineStatus error) { | 302 void PipelineImpl::OnError(PipelineStatus error) { |
| 310 DCHECK(task_runner_->BelongsToCurrentThread()); | 303 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 311 DCHECK(IsRunning()); | 304 DCHECK(IsRunning()); |
| 312 DCHECK_NE(PIPELINE_OK, error); | 305 DCHECK_NE(PIPELINE_OK, error); |
| 313 VLOG(1) << "Media pipeline error: " << error; | 306 VLOG(1) << "Media pipeline error: " << error; |
| 314 | 307 |
| 315 task_runner_->PostTask(FROM_HERE, base::Bind( | 308 task_runner_->PostTask(FROM_HERE, |
| 316 &Pipeline::ErrorChangedTask, weak_factory_.GetWeakPtr(), error)); | 309 base::Bind(&PipelineImpl::ErrorChangedTask, |
| 310 weak_factory_.GetWeakPtr(), error)); |
| 317 } | 311 } |
| 318 | 312 |
| 319 void Pipeline::SetDuration(TimeDelta duration) { | 313 void PipelineImpl::SetDuration(TimeDelta duration) { |
| 320 DCHECK(IsRunning()); | 314 DCHECK(IsRunning()); |
| 321 media_log_->AddEvent( | 315 media_log_->AddEvent( |
| 322 media_log_->CreateTimeEvent( | 316 media_log_->CreateTimeEvent( |
| 323 MediaLogEvent::DURATION_SET, "duration", duration)); | 317 MediaLogEvent::DURATION_SET, "duration", duration)); |
| 324 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 318 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
| 325 | 319 |
| 326 base::AutoLock auto_lock(lock_); | 320 base::AutoLock auto_lock(lock_); |
| 327 duration_ = duration; | 321 duration_ = duration; |
| 328 if (!duration_change_cb_.is_null()) | 322 if (!duration_change_cb_.is_null()) |
| 329 duration_change_cb_.Run(); | 323 duration_change_cb_.Run(); |
| 330 } | 324 } |
| 331 | 325 |
| 332 void Pipeline::StateTransitionTask(PipelineStatus status) { | 326 void PipelineImpl::StateTransitionTask(PipelineStatus status) { |
| 333 DCHECK(task_runner_->BelongsToCurrentThread()); | 327 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 334 | 328 |
| 335 // No-op any state transitions if we're stopping. | 329 // No-op any state transitions if we're stopping. |
| 336 if (state_ == kStopping || state_ == kStopped) | 330 if (state_ == kStopping || state_ == kStopped) |
| 337 return; | 331 return; |
| 338 | 332 |
| 339 // Preserve existing abnormal status, otherwise update based on the result of | 333 // Preserve existing abnormal status, otherwise update based on the result of |
| 340 // the previous operation. | 334 // the previous operation. |
| 341 status_ = (status_ != PIPELINE_OK ? status_ : status); | 335 status_ = (status_ != PIPELINE_OK ? status_ : status); |
| 342 | 336 |
| 343 if (status_ != PIPELINE_OK) { | 337 if (status_ != PIPELINE_OK) { |
| 344 ErrorChangedTask(status_); | 338 ErrorChangedTask(status_); |
| 345 return; | 339 return; |
| 346 } | 340 } |
| 347 | 341 |
| 348 // Guard against accidentally clearing |pending_callbacks_| for states that | 342 // Guard against accidentally clearing |pending_callbacks_| for states that |
| 349 // use it as well as states that should not be using it. | 343 // use it as well as states that should not be using it. |
| 350 DCHECK_EQ(pending_callbacks_.get() != NULL, | 344 DCHECK_EQ(pending_callbacks_.get() != NULL, |
| 351 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); | 345 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); |
| 352 | 346 |
| 353 pending_callbacks_.reset(); | 347 pending_callbacks_.reset(); |
| 354 | 348 |
| 355 PipelineStatusCB done_cb = | 349 PipelineStatusCB done_cb = base::Bind(&PipelineImpl::StateTransitionTask, |
| 356 base::Bind(&Pipeline::StateTransitionTask, weak_factory_.GetWeakPtr()); | 350 weak_factory_.GetWeakPtr()); |
| 357 | 351 |
| 358 // Switch states, performing any entrance actions for the new state as well. | 352 // Switch states, performing any entrance actions for the new state as well. |
| 359 SetState(GetNextState()); | 353 SetState(GetNextState()); |
| 360 switch (state_) { | 354 switch (state_) { |
| 361 case kInitDemuxer: | 355 case kInitDemuxer: |
| 362 return InitializeDemuxer(done_cb); | 356 return InitializeDemuxer(done_cb); |
| 363 | 357 |
| 364 case kInitRenderer: | 358 case kInitRenderer: |
| 365 // When the state_ transfers to kInitRenderer, it means the demuxer has | 359 // When the state_ transfers to kInitRenderer, it means the demuxer has |
| 366 // finished parsing the init info. It should call ReportMetadata in case | 360 // finished parsing the init info. It should call ReportMetadata in case |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 NOTREACHED() << "State has no transition: " << state_; | 397 NOTREACHED() << "State has no transition: " << state_; |
| 404 return; | 398 return; |
| 405 } | 399 } |
| 406 } | 400 } |
| 407 | 401 |
| 408 // Note that the usage of base::Unretained() with the renderers is considered | 402 // Note that the usage of base::Unretained() with the renderers is considered |
| 409 // safe as they are owned by |pending_callbacks_| and share the same lifetime. | 403 // safe as they are owned by |pending_callbacks_| and share the same lifetime. |
| 410 // | 404 // |
| 411 // That being said, deleting the renderers while keeping |pending_callbacks_| | 405 // That being said, deleting the renderers while keeping |pending_callbacks_| |
| 412 // running on the media thread would result in crashes. | 406 // running on the media thread would result in crashes. |
| 413 void Pipeline::DoSeek(TimeDelta seek_timestamp, | 407 void PipelineImpl::DoSeek(TimeDelta seek_timestamp, |
| 414 const PipelineStatusCB& done_cb) { | 408 const PipelineStatusCB& done_cb) { |
| 415 DCHECK(task_runner_->BelongsToCurrentThread()); | 409 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 416 DCHECK(!pending_callbacks_.get()); | 410 DCHECK(!pending_callbacks_.get()); |
| 417 DCHECK_EQ(state_, kSeeking); | 411 DCHECK_EQ(state_, kSeeking); |
| 418 SerialRunner::Queue bound_fns; | 412 SerialRunner::Queue bound_fns; |
| 419 | 413 |
| 420 // Pause. | 414 // Pause. |
| 421 if (text_renderer_) { | 415 if (text_renderer_) { |
| 422 bound_fns.Push(base::Bind( | 416 bound_fns.Push(base::Bind( |
| 423 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); | 417 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); |
| 424 } | 418 } |
| 425 | 419 |
| 426 // Flush. | 420 // Flush. |
| 427 DCHECK(renderer_); | 421 DCHECK(renderer_); |
| 428 bound_fns.Push( | 422 bound_fns.Push( |
| 429 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); | 423 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); |
| 430 | 424 |
| 431 if (text_renderer_) { | 425 if (text_renderer_) { |
| 432 bound_fns.Push(base::Bind( | 426 bound_fns.Push(base::Bind( |
| 433 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); | 427 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); |
| 434 } | 428 } |
| 435 | 429 |
| 436 // Seek demuxer. | 430 // Seek demuxer. |
| 437 bound_fns.Push(base::Bind( | 431 bound_fns.Push(base::Bind( |
| 438 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); | 432 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); |
| 439 | 433 |
| 440 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); | 434 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); |
| 441 } | 435 } |
| 442 | 436 |
| 443 void Pipeline::DoStop(const PipelineStatusCB& done_cb) { | 437 void PipelineImpl::DoStop(const PipelineStatusCB& done_cb) { |
| 444 DVLOG(2) << __FUNCTION__; | 438 DVLOG(2) << __FUNCTION__; |
| 445 DCHECK(task_runner_->BelongsToCurrentThread()); | 439 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 446 DCHECK(!pending_callbacks_.get()); | 440 DCHECK(!pending_callbacks_.get()); |
| 447 | 441 |
| 448 // TODO(scherkus): Enforce that Renderer is only called on a single thread, | 442 // TODO(scherkus): Enforce that Renderer is only called on a single thread, |
| 449 // even for accessing media time http://crbug.com/370634 | 443 // even for accessing media time http://crbug.com/370634 |
| 450 scoped_ptr<Renderer> renderer; | 444 scoped_ptr<Renderer> renderer; |
| 451 { | 445 { |
| 452 base::AutoLock auto_lock(lock_); | 446 base::AutoLock auto_lock(lock_); |
| 453 renderer.swap(renderer_); | 447 renderer.swap(renderer_); |
| 454 } | 448 } |
| 455 renderer.reset(); | 449 renderer.reset(); |
| 456 text_renderer_.reset(); | 450 text_renderer_.reset(); |
| 457 | 451 |
| 458 if (demuxer_) { | 452 if (demuxer_) { |
| 459 demuxer_->Stop(); | 453 demuxer_->Stop(); |
| 460 demuxer_ = NULL; | 454 demuxer_ = NULL; |
| 461 } | 455 } |
| 462 | 456 |
| 463 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 457 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); |
| 464 } | 458 } |
| 465 | 459 |
| 466 void Pipeline::OnStopCompleted(PipelineStatus status) { | 460 void PipelineImpl::OnStopCompleted(PipelineStatus status) { |
| 467 DVLOG(2) << __FUNCTION__; | 461 DVLOG(2) << __FUNCTION__; |
| 468 DCHECK(task_runner_->BelongsToCurrentThread()); | 462 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 469 DCHECK_EQ(state_, kStopping); | 463 DCHECK_EQ(state_, kStopping); |
| 470 DCHECK(!renderer_); | 464 DCHECK(!renderer_); |
| 471 DCHECK(!text_renderer_); | 465 DCHECK(!text_renderer_); |
| 472 | 466 |
| 473 { | 467 { |
| 474 base::AutoLock auto_lock(lock_); | 468 base::AutoLock auto_lock(lock_); |
| 475 running_ = false; | 469 running_ = false; |
| 476 } | 470 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 500 // NOTE: pipeline may be deleted at this point in time as a result of | 494 // NOTE: pipeline may be deleted at this point in time as a result of |
| 501 // executing |stop_cb_|. | 495 // executing |stop_cb_|. |
| 502 return; | 496 return; |
| 503 } | 497 } |
| 504 if (!error_cb_.is_null()) { | 498 if (!error_cb_.is_null()) { |
| 505 DCHECK_NE(status_, PIPELINE_OK); | 499 DCHECK_NE(status_, PIPELINE_OK); |
| 506 base::ResetAndReturn(&error_cb_).Run(status_); | 500 base::ResetAndReturn(&error_cb_).Run(status_); |
| 507 } | 501 } |
| 508 } | 502 } |
| 509 | 503 |
| 510 void Pipeline::OnBufferedTimeRangesChanged( | 504 void PipelineImpl::OnBufferedTimeRangesChanged( |
| 511 const Ranges<base::TimeDelta>& ranges) { | 505 const Ranges<base::TimeDelta>& ranges) { |
| 512 DCHECK(IsRunning()); | 506 DCHECK(IsRunning()); |
| 513 base::AutoLock auto_lock(lock_); | 507 base::AutoLock auto_lock(lock_); |
| 514 buffered_time_ranges_ = ranges; | 508 buffered_time_ranges_ = ranges; |
| 515 did_loading_progress_ = true; | 509 did_loading_progress_ = true; |
| 516 } | 510 } |
| 517 | 511 |
| 518 // Called from any thread. | 512 // Called from any thread. |
| 519 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats_delta) { | 513 void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) { |
| 520 base::AutoLock auto_lock(lock_); | 514 base::AutoLock auto_lock(lock_); |
| 521 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded; | 515 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded; |
| 522 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded; | 516 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded; |
| 523 statistics_.video_frames_decoded += stats_delta.video_frames_decoded; | 517 statistics_.video_frames_decoded += stats_delta.video_frames_decoded; |
| 524 statistics_.video_frames_dropped += stats_delta.video_frames_dropped; | 518 statistics_.video_frames_dropped += stats_delta.video_frames_dropped; |
| 525 statistics_.audio_memory_usage += stats_delta.audio_memory_usage; | 519 statistics_.audio_memory_usage += stats_delta.audio_memory_usage; |
| 526 statistics_.video_memory_usage += stats_delta.video_memory_usage; | 520 statistics_.video_memory_usage += stats_delta.video_memory_usage; |
| 527 } | 521 } |
| 528 | 522 |
| 529 void Pipeline::StartTask() { | 523 void PipelineImpl::StartTask() { |
| 530 DCHECK(task_runner_->BelongsToCurrentThread()); | 524 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 531 | 525 |
| 532 CHECK_EQ(kCreated, state_) | 526 CHECK_EQ(kCreated, state_) |
| 533 << "Media pipeline cannot be started more than once"; | 527 << "Media pipeline cannot be started more than once"; |
| 534 | 528 |
| 535 text_renderer_ = CreateTextRenderer(); | 529 text_renderer_ = CreateTextRenderer(); |
| 536 if (text_renderer_) { | 530 if (text_renderer_) { |
| 537 text_renderer_->Initialize( | 531 text_renderer_->Initialize(base::Bind(&PipelineImpl::OnTextRendererEnded, |
| 538 base::Bind(&Pipeline::OnTextRendererEnded, weak_factory_.GetWeakPtr())); | 532 weak_factory_.GetWeakPtr())); |
| 539 } | 533 } |
| 540 | 534 |
| 541 // Set CDM early to avoid unnecessary delay in Renderer::Initialize(). | 535 // Set CDM early to avoid unnecessary delay in Renderer::Initialize(). |
| 542 if (pending_cdm_context_) { | 536 if (pending_cdm_context_) { |
| 543 renderer_->SetCdm(pending_cdm_context_, base::Bind(&IgnoreCdmAttached)); | 537 renderer_->SetCdm(pending_cdm_context_, base::Bind(&IgnoreCdmAttached)); |
| 544 pending_cdm_context_ = nullptr; | 538 pending_cdm_context_ = nullptr; |
| 545 } | 539 } |
| 546 | 540 |
| 547 StateTransitionTask(PIPELINE_OK); | 541 StateTransitionTask(PIPELINE_OK); |
| 548 } | 542 } |
| 549 | 543 |
| 550 void Pipeline::StopTask(const base::Closure& stop_cb) { | 544 void PipelineImpl::StopTask(const base::Closure& stop_cb) { |
| 551 DCHECK(task_runner_->BelongsToCurrentThread()); | 545 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 552 DCHECK(stop_cb_.is_null()); | 546 DCHECK(stop_cb_.is_null()); |
| 553 | 547 |
| 554 if (state_ == kStopped) { | 548 if (state_ == kStopped) { |
| 555 // Invalid all weak pointers so it's safe to destroy |this| on the render | 549 // Invalid all weak pointers so it's safe to destroy |this| on the render |
| 556 // main thread. | 550 // main thread. |
| 557 weak_factory_.InvalidateWeakPtrs(); | 551 weak_factory_.InvalidateWeakPtrs(); |
| 558 | 552 |
| 559 // NOTE: pipeline may be deleted at this point in time as a result of | 553 // NOTE: pipeline may be deleted at this point in time as a result of |
| 560 // executing |stop_cb|. | 554 // executing |stop_cb|. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 574 state_ == kSuspended || state_ == kResuming) { | 568 state_ == kSuspended || state_ == kResuming) { |
| 575 PipelineStatistics stats = GetStatistics(); | 569 PipelineStatistics stats = GetStatistics(); |
| 576 if (stats.video_frames_decoded > 0) { | 570 if (stats.video_frames_decoded > 0) { |
| 577 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", | 571 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", |
| 578 stats.video_frames_dropped); | 572 stats.video_frames_dropped); |
| 579 } | 573 } |
| 580 } | 574 } |
| 581 | 575 |
| 582 SetState(kStopping); | 576 SetState(kStopping); |
| 583 pending_callbacks_.reset(); | 577 pending_callbacks_.reset(); |
| 584 DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr())); | 578 DoStop( |
| 579 base::Bind(&PipelineImpl::OnStopCompleted, weak_factory_.GetWeakPtr())); |
| 585 } | 580 } |
| 586 | 581 |
| 587 void Pipeline::ErrorChangedTask(PipelineStatus error) { | 582 void PipelineImpl::ErrorChangedTask(PipelineStatus error) { |
| 588 DCHECK(task_runner_->BelongsToCurrentThread()); | 583 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 589 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; | 584 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; |
| 590 | 585 |
| 591 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); | 586 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); |
| 592 | 587 |
| 593 if (state_ == kStopping || state_ == kStopped) | 588 if (state_ == kStopping || state_ == kStopped) |
| 594 return; | 589 return; |
| 595 | 590 |
| 596 SetState(kStopping); | 591 SetState(kStopping); |
| 597 pending_callbacks_.reset(); | 592 pending_callbacks_.reset(); |
| 598 status_ = error; | 593 status_ = error; |
| 599 | 594 |
| 600 DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr())); | 595 DoStop( |
| 596 base::Bind(&PipelineImpl::OnStopCompleted, weak_factory_.GetWeakPtr())); |
| 601 } | 597 } |
| 602 | 598 |
| 603 void Pipeline::PlaybackRateChangedTask(double playback_rate) { | 599 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) { |
| 604 DCHECK(task_runner_->BelongsToCurrentThread()); | 600 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 605 | 601 |
| 606 // Playback rate changes are only carried out while playing. | 602 // Playback rate changes are only carried out while playing. |
| 607 if (state_ != kPlaying) | 603 if (state_ != kPlaying) |
| 608 return; | 604 return; |
| 609 | 605 |
| 610 renderer_->SetPlaybackRate(playback_rate); | 606 renderer_->SetPlaybackRate(playback_rate); |
| 611 } | 607 } |
| 612 | 608 |
| 613 void Pipeline::VolumeChangedTask(float volume) { | 609 void PipelineImpl::VolumeChangedTask(float volume) { |
| 614 DCHECK(task_runner_->BelongsToCurrentThread()); | 610 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 615 | 611 |
| 616 // Volume changes are only carried out while playing. | 612 // Volume changes are only carried out while playing. |
| 617 if (state_ != kPlaying) | 613 if (state_ != kPlaying) |
| 618 return; | 614 return; |
| 619 | 615 |
| 620 renderer_->SetVolume(volume); | 616 renderer_->SetVolume(volume); |
| 621 } | 617 } |
| 622 | 618 |
| 623 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { | 619 void PipelineImpl::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
| 624 DCHECK(task_runner_->BelongsToCurrentThread()); | 620 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 625 DCHECK(stop_cb_.is_null()); | 621 DCHECK(stop_cb_.is_null()); |
| 626 | 622 |
| 627 // Suppress seeking if we're not fully started. | 623 // Suppress seeking if we're not fully started. |
| 628 if (state_ != kPlaying) { | 624 if (state_ != kPlaying) { |
| 629 DCHECK(state_ == kStopping || state_ == kStopped) | 625 DCHECK(state_ == kStopping || state_ == kStopped) |
| 630 << "Receive seek in unexpected state: " << state_; | 626 << "Receive seek in unexpected state: " << state_; |
| 631 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); | 627 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); |
| 632 return; | 628 return; |
| 633 } | 629 } |
| 634 | 630 |
| 635 DCHECK(seek_cb_.is_null()); | 631 DCHECK(seek_cb_.is_null()); |
| 636 | 632 |
| 637 const base::TimeDelta seek_timestamp = | 633 const base::TimeDelta seek_timestamp = |
| 638 std::max(time, demuxer_->GetStartTime()); | 634 std::max(time, demuxer_->GetStartTime()); |
| 639 | 635 |
| 640 SetState(kSeeking); | 636 SetState(kSeeking); |
| 641 seek_cb_ = seek_cb; | 637 seek_cb_ = seek_cb; |
| 642 renderer_ended_ = false; | 638 renderer_ended_ = false; |
| 643 text_renderer_ended_ = false; | 639 text_renderer_ended_ = false; |
| 644 start_timestamp_ = seek_timestamp; | 640 start_timestamp_ = seek_timestamp; |
| 645 | 641 |
| 646 DoSeek(seek_timestamp, base::Bind(&Pipeline::StateTransitionTask, | 642 DoSeek(seek_timestamp, base::Bind(&PipelineImpl::StateTransitionTask, |
| 647 weak_factory_.GetWeakPtr())); | 643 weak_factory_.GetWeakPtr())); |
| 648 } | 644 } |
| 649 | 645 |
| 650 void Pipeline::SuspendTask(const PipelineStatusCB& suspend_cb) { | 646 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) { |
| 651 DCHECK(task_runner_->BelongsToCurrentThread()); | 647 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 652 | 648 |
| 653 // Suppress suspending if we're not playing. | 649 // Suppress suspending if we're not playing. |
| 654 if (state_ != kPlaying) { | 650 if (state_ != kPlaying) { |
| 655 DCHECK(state_ == kStopping || state_ == kStopped) | 651 DCHECK(state_ == kStopping || state_ == kStopped) |
| 656 << "Receive suspend in unexpected state: " << state_; | 652 << "Receive suspend in unexpected state: " << state_; |
| 657 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); | 653 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); |
| 658 return; | 654 return; |
| 659 } | 655 } |
| 660 DCHECK(renderer_); | 656 DCHECK(renderer_); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 682 base::Unretained(text_renderer_.get()))); | 678 base::Unretained(text_renderer_.get()))); |
| 683 } | 679 } |
| 684 | 680 |
| 685 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); | 681 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); |
| 686 | 682 |
| 687 if (text_renderer_) { | 683 if (text_renderer_) { |
| 688 fns.Push(base::Bind(&TextRenderer::Flush, | 684 fns.Push(base::Bind(&TextRenderer::Flush, |
| 689 base::Unretained(text_renderer_.get()))); | 685 base::Unretained(text_renderer_.get()))); |
| 690 } | 686 } |
| 691 | 687 |
| 692 pending_callbacks_ = SerialRunner::Run( | 688 pending_callbacks_ = |
| 693 fns, | 689 SerialRunner::Run(fns, base::Bind(&PipelineImpl::StateTransitionTask, |
| 694 base::Bind(&Pipeline::StateTransitionTask, weak_factory_.GetWeakPtr())); | 690 weak_factory_.GetWeakPtr())); |
| 695 } | 691 } |
| 696 | 692 |
| 697 void Pipeline::ResumeTask(scoped_ptr<Renderer> renderer, | 693 void PipelineImpl::ResumeTask(scoped_ptr<Renderer> renderer, |
| 698 base::TimeDelta timestamp, | 694 base::TimeDelta timestamp, |
| 699 const PipelineStatusCB& seek_cb) { | 695 const PipelineStatusCB& seek_cb) { |
| 700 DCHECK(task_runner_->BelongsToCurrentThread()); | 696 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 701 | 697 |
| 702 // Suppress resuming if we're not suspended. | 698 // Suppress resuming if we're not suspended. |
| 703 if (state_ != kSuspended) { | 699 if (state_ != kSuspended) { |
| 704 DCHECK(state_ == kStopping || state_ == kStopped) | 700 DCHECK(state_ == kStopping || state_ == kStopped) |
| 705 << "Receive resume in unexpected state: " << state_; | 701 << "Receive resume in unexpected state: " << state_; |
| 706 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); | 702 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); |
| 707 return; | 703 return; |
| 708 } | 704 } |
| 709 DCHECK(!renderer_); | 705 DCHECK(!renderer_); |
| 710 DCHECK(!pending_callbacks_.get()); | 706 DCHECK(!pending_callbacks_.get()); |
| 711 | 707 |
| 712 SetState(kResuming); | 708 SetState(kResuming); |
| 713 renderer_ = std::move(renderer); | 709 renderer_ = std::move(renderer); |
| 714 | 710 |
| 715 // Set up for a seek. (Matches setup in SeekTask().) | 711 // Set up for a seek. (Matches setup in SeekTask().) |
| 716 // TODO(sandersd): Share implementation with SeekTask(). | 712 // TODO(sandersd): Share implementation with SeekTask(). |
| 717 seek_cb_ = seek_cb; | 713 seek_cb_ = seek_cb; |
| 718 renderer_ended_ = false; | 714 renderer_ended_ = false; |
| 719 text_renderer_ended_ = false; | 715 text_renderer_ended_ = false; |
| 720 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime()); | 716 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime()); |
| 721 | 717 |
| 722 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), | 718 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), |
| 723 // we need to initialize the renderer ourselves (we don't want to enter state | 719 // we need to initialize the renderer ourselves (we don't want to enter state |
| 724 // kInitDemuxer, and even if we did the current code would seek to the start | 720 // kInitDemuxer, and even if we did the current code would seek to the start |
| 725 // instead of |timestamp|). | 721 // instead of |timestamp|). |
| 726 SerialRunner::Queue fns; | 722 SerialRunner::Queue fns; |
| 727 base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr(); | 723 base::WeakPtr<PipelineImpl> weak_this = weak_factory_.GetWeakPtr(); |
| 728 | 724 |
| 729 fns.Push( | 725 fns.Push( |
| 730 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); | 726 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); |
| 731 | 727 |
| 732 fns.Push(base::Bind(&Pipeline::InitializeRenderer, weak_this)); | 728 fns.Push(base::Bind(&PipelineImpl::InitializeRenderer, weak_this)); |
| 733 | 729 |
| 734 pending_callbacks_ = SerialRunner::Run( | 730 pending_callbacks_ = SerialRunner::Run( |
| 735 fns, base::Bind(&Pipeline::StateTransitionTask, weak_this)); | 731 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this)); |
| 736 } | 732 } |
| 737 | 733 |
| 738 void Pipeline::SetCdmTask(CdmContext* cdm_context, | 734 void PipelineImpl::SetCdmTask(CdmContext* cdm_context, |
| 739 const CdmAttachedCB& cdm_attached_cb) { | 735 const CdmAttachedCB& cdm_attached_cb) { |
| 740 base::AutoLock auto_lock(lock_); | 736 base::AutoLock auto_lock(lock_); |
| 741 if (!renderer_) { | 737 if (!renderer_) { |
| 742 pending_cdm_context_ = cdm_context; | 738 pending_cdm_context_ = cdm_context; |
| 743 cdm_attached_cb.Run(true); | 739 cdm_attached_cb.Run(true); |
| 744 return; | 740 return; |
| 745 } | 741 } |
| 746 | 742 |
| 747 renderer_->SetCdm(cdm_context, cdm_attached_cb); | 743 renderer_->SetCdm(cdm_context, cdm_attached_cb); |
| 748 } | 744 } |
| 749 | 745 |
| 750 void Pipeline::OnRendererEnded() { | 746 void PipelineImpl::OnRendererEnded() { |
| 751 DCHECK(task_runner_->BelongsToCurrentThread()); | 747 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 752 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); | 748 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); |
| 753 | 749 |
| 754 if (state_ != kPlaying) | 750 if (state_ != kPlaying) |
| 755 return; | 751 return; |
| 756 | 752 |
| 757 DCHECK(!renderer_ended_); | 753 DCHECK(!renderer_ended_); |
| 758 renderer_ended_ = true; | 754 renderer_ended_ = true; |
| 759 | 755 |
| 760 RunEndedCallbackIfNeeded(); | 756 RunEndedCallbackIfNeeded(); |
| 761 } | 757 } |
| 762 | 758 |
| 763 void Pipeline::OnTextRendererEnded() { | 759 void PipelineImpl::OnTextRendererEnded() { |
| 764 DCHECK(task_runner_->BelongsToCurrentThread()); | 760 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 765 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); | 761 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); |
| 766 | 762 |
| 767 if (state_ != kPlaying) | 763 if (state_ != kPlaying) |
| 768 return; | 764 return; |
| 769 | 765 |
| 770 DCHECK(!text_renderer_ended_); | 766 DCHECK(!text_renderer_ended_); |
| 771 text_renderer_ended_ = true; | 767 text_renderer_ended_ = true; |
| 772 | 768 |
| 773 RunEndedCallbackIfNeeded(); | 769 RunEndedCallbackIfNeeded(); |
| 774 } | 770 } |
| 775 | 771 |
| 776 void Pipeline::RunEndedCallbackIfNeeded() { | 772 void PipelineImpl::RunEndedCallbackIfNeeded() { |
| 777 DCHECK(task_runner_->BelongsToCurrentThread()); | 773 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 778 | 774 |
| 779 if (renderer_ && !renderer_ended_) | 775 if (renderer_ && !renderer_ended_) |
| 780 return; | 776 return; |
| 781 | 777 |
| 782 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) | 778 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) |
| 783 return; | 779 return; |
| 784 | 780 |
| 785 DCHECK_EQ(status_, PIPELINE_OK); | 781 DCHECK_EQ(status_, PIPELINE_OK); |
| 786 ended_cb_.Run(); | 782 ended_cb_.Run(); |
| 787 } | 783 } |
| 788 | 784 |
| 789 scoped_ptr<TextRenderer> Pipeline::CreateTextRenderer() { | 785 scoped_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { |
| 790 DCHECK(task_runner_->BelongsToCurrentThread()); | 786 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 791 | 787 |
| 792 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 788 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 793 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) | 789 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) |
| 794 return scoped_ptr<media::TextRenderer>(); | 790 return scoped_ptr<media::TextRenderer>(); |
| 795 | 791 |
| 796 return scoped_ptr<media::TextRenderer>(new media::TextRenderer( | 792 return scoped_ptr<media::TextRenderer>(new media::TextRenderer( |
| 797 task_runner_, | 793 task_runner_, |
| 798 base::Bind(&Pipeline::OnAddTextTrack, weak_factory_.GetWeakPtr()))); | 794 base::Bind(&PipelineImpl::OnAddTextTrack, weak_factory_.GetWeakPtr()))); |
| 799 } | 795 } |
| 800 | 796 |
| 801 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, | 797 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream, |
| 802 const TextTrackConfig& config) { | 798 const TextTrackConfig& config) { |
| 803 DCHECK(task_runner_->BelongsToCurrentThread()); | 799 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 804 // TODO(matthewjheaney): fix up text_ended_ when text stream | 800 // TODO(matthewjheaney): fix up text_ended_ when text stream |
| 805 // is added (http://crbug.com/321446). | 801 // is added (http://crbug.com/321446). |
| 806 if (text_renderer_) | 802 if (text_renderer_) |
| 807 text_renderer_->AddTextStream(text_stream, config); | 803 text_renderer_->AddTextStream(text_stream, config); |
| 808 } | 804 } |
| 809 | 805 |
| 810 void Pipeline::RemoveTextStreamTask(DemuxerStream* text_stream) { | 806 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) { |
| 811 DCHECK(task_runner_->BelongsToCurrentThread()); | 807 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 812 if (text_renderer_) | 808 if (text_renderer_) |
| 813 text_renderer_->RemoveTextStream(text_stream); | 809 text_renderer_->RemoveTextStream(text_stream); |
| 814 } | 810 } |
| 815 | 811 |
| 816 void Pipeline::OnAddTextTrack(const TextTrackConfig& config, | 812 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, |
| 817 const AddTextTrackDoneCB& done_cb) { | 813 const AddTextTrackDoneCB& done_cb) { |
| 818 DCHECK(task_runner_->BelongsToCurrentThread()); | 814 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 819 add_text_track_cb_.Run(config, done_cb); | 815 add_text_track_cb_.Run(config, done_cb); |
| 820 } | 816 } |
| 821 | 817 |
| 822 void Pipeline::InitializeDemuxer(const PipelineStatusCB& done_cb) { | 818 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) { |
| 823 DCHECK(task_runner_->BelongsToCurrentThread()); | 819 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 824 demuxer_->Initialize(this, done_cb, !!text_renderer_); | 820 demuxer_->Initialize(this, done_cb, !!text_renderer_); |
| 825 } | 821 } |
| 826 | 822 |
| 827 void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) { | 823 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) { |
| 828 DCHECK(task_runner_->BelongsToCurrentThread()); | 824 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 829 | 825 |
| 830 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && | 826 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && |
| 831 !demuxer_->GetStream(DemuxerStream::VIDEO)) { | 827 !demuxer_->GetStream(DemuxerStream::VIDEO)) { |
| 832 { | 828 { |
| 833 base::AutoLock auto_lock(lock_); | 829 base::AutoLock auto_lock(lock_); |
| 834 renderer_.reset(); | 830 renderer_.reset(); |
| 835 } | 831 } |
| 836 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); | 832 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); |
| 837 return; | 833 return; |
| 838 } | 834 } |
| 839 | 835 |
| 840 base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr(); | 836 base::WeakPtr<PipelineImpl> weak_this = weak_factory_.GetWeakPtr(); |
| 841 renderer_->Initialize( | 837 renderer_->Initialize( |
| 842 demuxer_, | 838 demuxer_, done_cb, |
| 843 done_cb, | 839 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this), |
| 844 base::Bind(&Pipeline::OnUpdateStatistics, weak_this), | 840 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this), |
| 845 base::Bind(&Pipeline::BufferingStateChanged, weak_this), | 841 base::Bind(&PipelineImpl::OnRendererEnded, weak_this), |
| 846 base::Bind(&Pipeline::OnRendererEnded, weak_this), | 842 base::Bind(&PipelineImpl::OnError, weak_this), |
| 847 base::Bind(&Pipeline::OnError, weak_this), | |
| 848 waiting_for_decryption_key_cb_); | 843 waiting_for_decryption_key_cb_); |
| 849 } | 844 } |
| 850 | 845 |
| 851 void Pipeline::ReportMetadata() { | 846 void PipelineImpl::ReportMetadata() { |
| 852 DCHECK(task_runner_->BelongsToCurrentThread()); | 847 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 853 PipelineMetadata metadata; | 848 PipelineMetadata metadata; |
| 854 metadata.timeline_offset = demuxer_->GetTimelineOffset(); | 849 metadata.timeline_offset = demuxer_->GetTimelineOffset(); |
| 855 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | 850 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
| 856 if (stream) { | 851 if (stream) { |
| 857 metadata.has_video = true; | 852 metadata.has_video = true; |
| 858 metadata.natural_size = stream->video_decoder_config().natural_size(); | 853 metadata.natural_size = stream->video_decoder_config().natural_size(); |
| 859 metadata.video_rotation = stream->video_rotation(); | 854 metadata.video_rotation = stream->video_rotation(); |
| 860 } | 855 } |
| 861 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { | 856 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { |
| 862 metadata.has_audio = true; | 857 metadata.has_audio = true; |
| 863 } | 858 } |
| 864 metadata_cb_.Run(metadata); | 859 metadata_cb_.Run(metadata); |
| 865 } | 860 } |
| 866 | 861 |
| 867 void Pipeline::BufferingStateChanged(BufferingState new_buffering_state) { | 862 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { |
| 868 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; | 863 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; |
| 869 DCHECK(task_runner_->BelongsToCurrentThread()); | 864 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 870 buffering_state_cb_.Run(new_buffering_state); | 865 buffering_state_cb_.Run(new_buffering_state); |
| 871 } | 866 } |
| 872 | 867 |
| 873 } // namespace media | 868 } // namespace media |
| OLD | NEW |