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_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" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/callback.h" | 12 #include "base/callback.h" |
13 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
15 #include "base/compiler_specific.h" | 15 #include "base/compiler_specific.h" |
16 #include "base/location.h" | 16 #include "base/location.h" |
17 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
18 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
19 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
20 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
21 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
22 #include "base/synchronization/condition_variable.h" | 22 #include "base/synchronization/condition_variable.h" |
23 #include "media/base/media_log.h" | 23 #include "media/base/media_log.h" |
24 #include "media/base/media_switches.h" | 24 #include "media/base/media_switches.h" |
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) \ |
| 227 case state: \ |
| 228 return #state; |
230 | 229 |
231 const char* Pipeline::GetStateString(State state) { | 230 const char* PipelineImpl::GetStateString(State state) { |
232 switch (state) { | 231 switch (state) { |
233 RETURN_STRING(kCreated); | 232 RETURN_STRING(kCreated); |
234 RETURN_STRING(kInitDemuxer); | 233 RETURN_STRING(kInitDemuxer); |
235 RETURN_STRING(kInitRenderer); | 234 RETURN_STRING(kInitRenderer); |
236 RETURN_STRING(kSeeking); | 235 RETURN_STRING(kSeeking); |
237 RETURN_STRING(kPlaying); | 236 RETURN_STRING(kPlaying); |
238 RETURN_STRING(kStopping); | 237 RETURN_STRING(kStopping); |
239 RETURN_STRING(kStopped); | 238 RETURN_STRING(kStopped); |
240 RETURN_STRING(kSuspending); | 239 RETURN_STRING(kSuspending); |
241 RETURN_STRING(kSuspended); | 240 RETURN_STRING(kSuspended); |
242 RETURN_STRING(kResuming); | 241 RETURN_STRING(kResuming); |
243 } | 242 } |
244 NOTREACHED(); | 243 NOTREACHED(); |
245 return "INVALID"; | 244 return "INVALID"; |
246 } | 245 } |
247 | 246 |
248 #undef RETURN_STRING | 247 #undef RETURN_STRING |
249 | 248 |
250 Pipeline::State Pipeline::GetNextState() const { | 249 PipelineImpl::State PipelineImpl::GetNextState() const { |
251 DCHECK(task_runner_->BelongsToCurrentThread()); | 250 DCHECK(task_runner_->BelongsToCurrentThread()); |
252 DCHECK(stop_cb_.is_null()) | 251 DCHECK(stop_cb_.is_null()) << "State transitions don't happen when stopping"; |
253 << "State transitions don't happen when stopping"; | |
254 DCHECK_EQ(status_, PIPELINE_OK) | 252 DCHECK_EQ(status_, PIPELINE_OK) |
255 << "State transitions don't happen when there's an error: " << status_; | 253 << "State transitions don't happen when there's an error: " << status_; |
256 | 254 |
257 switch (state_) { | 255 switch (state_) { |
258 case kCreated: | 256 case kCreated: |
259 return kInitDemuxer; | 257 return kInitDemuxer; |
260 | 258 |
261 case kInitDemuxer: | 259 case kInitDemuxer: |
262 return kInitRenderer; | 260 return kInitRenderer; |
263 | 261 |
(...skipping 12 matching lines...) Expand all Loading... |
276 | 274 |
277 case kPlaying: | 275 case kPlaying: |
278 case kStopping: | 276 case kStopping: |
279 case kStopped: | 277 case kStopped: |
280 break; | 278 break; |
281 } | 279 } |
282 NOTREACHED() << "State has no transition: " << state_; | 280 NOTREACHED() << "State has no transition: " << state_; |
283 return state_; | 281 return state_; |
284 } | 282 } |
285 | 283 |
286 void Pipeline::OnDemuxerError(PipelineStatus error) { | 284 void PipelineImpl::OnDemuxerError(PipelineStatus error) { |
287 task_runner_->PostTask(FROM_HERE, | 285 task_runner_->PostTask(FROM_HERE, |
288 base::Bind(&Pipeline::ErrorChangedTask, | 286 base::Bind(&PipelineImpl::ErrorChangedTask, |
289 weak_factory_.GetWeakPtr(), | 287 weak_factory_.GetWeakPtr(), error)); |
290 error)); | |
291 } | 288 } |
292 | 289 |
293 void Pipeline::AddTextStream(DemuxerStream* text_stream, | 290 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, |
294 const TextTrackConfig& config) { | 291 const TextTrackConfig& config) { |
295 task_runner_->PostTask(FROM_HERE, | 292 task_runner_->PostTask( |
296 base::Bind(&Pipeline::AddTextStreamTask, | 293 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, |
297 weak_factory_.GetWeakPtr(), | 294 weak_factory_.GetWeakPtr(), text_stream, config)); |
298 text_stream, | |
299 config)); | |
300 } | 295 } |
301 | 296 |
302 void Pipeline::RemoveTextStream(DemuxerStream* text_stream) { | 297 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { |
303 task_runner_->PostTask(FROM_HERE, | 298 task_runner_->PostTask(FROM_HERE, |
304 base::Bind(&Pipeline::RemoveTextStreamTask, | 299 base::Bind(&PipelineImpl::RemoveTextStreamTask, |
305 weak_factory_.GetWeakPtr(), | 300 weak_factory_.GetWeakPtr(), text_stream)); |
306 text_stream)); | |
307 } | 301 } |
308 | 302 |
309 void Pipeline::OnError(PipelineStatus error) { | 303 void PipelineImpl::OnError(PipelineStatus error) { |
310 DCHECK(task_runner_->BelongsToCurrentThread()); | 304 DCHECK(task_runner_->BelongsToCurrentThread()); |
311 DCHECK(IsRunning()); | 305 DCHECK(IsRunning()); |
312 DCHECK_NE(PIPELINE_OK, error); | 306 DCHECK_NE(PIPELINE_OK, error); |
313 VLOG(1) << "Media pipeline error: " << error; | 307 VLOG(1) << "Media pipeline error: " << error; |
314 | 308 |
315 task_runner_->PostTask(FROM_HERE, base::Bind( | 309 task_runner_->PostTask(FROM_HERE, |
316 &Pipeline::ErrorChangedTask, weak_factory_.GetWeakPtr(), error)); | 310 base::Bind(&PipelineImpl::ErrorChangedTask, |
| 311 weak_factory_.GetWeakPtr(), error)); |
317 } | 312 } |
318 | 313 |
319 void Pipeline::SetDuration(TimeDelta duration) { | 314 void PipelineImpl::SetDuration(TimeDelta duration) { |
320 DCHECK(IsRunning()); | 315 DCHECK(IsRunning()); |
321 media_log_->AddEvent( | 316 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, |
322 media_log_->CreateTimeEvent( | 317 "duration", duration)); |
323 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(&TextRenderer::Pause, |
423 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); | 417 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(&TextRenderer::Flush, |
433 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); | 427 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( |
438 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); | 432 base::Bind(&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 |