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

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

Issue 159246: Merged PipelineInternal into PipelineImpl, eliminating a ton of thread-UNsafeness and confusion. (Closed)
Patch Set: Fixed error logging Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/base/pipeline_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2008-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2008-2009 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 // TODO(scherkus): clean up PipelineImpl... too many crazy function names, 5 // TODO(scherkus): clean up PipelineImpl... too many crazy function names,
6 // potential deadlocks, etc... 6 // potential deadlocks, etc...
7 7
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/condition_variable.h" 9 #include "base/condition_variable.h"
10 #include "base/stl_util-inl.h" 10 #include "base/stl_util-inl.h"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 --(*count); 65 --(*count);
66 CHECK(*count >= 0); 66 CHECK(*count >= 0);
67 if (*count == 0) { 67 if (*count == 0) {
68 cond_var->Signal(); 68 cond_var->Signal();
69 } 69 }
70 } 70 }
71 71
72 } // namespace 72 } // namespace
73 73
74 PipelineImpl::PipelineImpl(MessageLoop* message_loop) 74 PipelineImpl::PipelineImpl(MessageLoop* message_loop)
75 : message_loop_(message_loop) { 75 : message_loop_(message_loop),
76 state_(kCreated) {
76 ResetState(); 77 ResetState();
77 } 78 }
78 79
79 PipelineImpl::~PipelineImpl() { 80 PipelineImpl::~PipelineImpl() {
80 DCHECK(!pipeline_internal_) 81 AutoLock auto_lock(lock_);
81 << "Stop() must complete before destroying object"; 82 DCHECK(!running_) << "Stop() must complete before destroying object";
82 } 83 }
83 84
84 // Creates the PipelineInternal and calls it's start method. 85 // Creates the PipelineInternal and calls it's start method.
85 bool PipelineImpl::Start(FilterFactory* factory, 86 bool PipelineImpl::Start(FilterFactory* factory,
86 const std::string& url, 87 const std::string& url,
87 PipelineCallback* start_callback) { 88 PipelineCallback* start_callback) {
88 DCHECK(!pipeline_internal_) << "PipelineInternal already exists"; 89 AutoLock auto_lock(lock_);
90 DCHECK(factory);
89 scoped_ptr<PipelineCallback> callback(start_callback); 91 scoped_ptr<PipelineCallback> callback(start_callback);
90 if (pipeline_internal_ || !factory) { 92 if (running_) {
93 LOG(ERROR) << "Media pipeline is already running";
94 return false;
95 }
96 if (!factory) {
91 return false; 97 return false;
92 } 98 }
93 99
94 // Create and start the PipelineInternal. 100 // Kick off initialization!
95 pipeline_internal_ = new PipelineInternal(this, message_loop_); 101 running_ = true;
96 if (!pipeline_internal_) { 102 message_loop_->PostTask(FROM_HERE,
97 NOTREACHED() << "Could not create PipelineInternal"; 103 NewRunnableMethod(this, &PipelineImpl::StartTask, factory, url,
98 return false; 104 callback.release()));
99 }
100 pipeline_internal_->Start(factory, url, callback.release());
101 return true; 105 return true;
102 } 106 }
103 107
104 // Stop the PipelineInternal who will NULL our reference to it and reset our
105 // state to a newly created PipelineImpl object.
106 void PipelineImpl::Stop(PipelineCallback* stop_callback) { 108 void PipelineImpl::Stop(PipelineCallback* stop_callback) {
109 AutoLock auto_lock(lock_);
107 scoped_ptr<PipelineCallback> callback(stop_callback); 110 scoped_ptr<PipelineCallback> callback(stop_callback);
108 if (pipeline_internal_) { 111 if (!running_) {
109 pipeline_internal_->Stop(callback.release()); 112 LOG(ERROR) << "Media pipeline has already stopped";
113 return;
110 } 114 }
115
116 // Stop the pipeline, which will set |running_| to false on behalf.
117 message_loop_->PostTask(FROM_HERE,
118 NewRunnableMethod(this, &PipelineImpl::StopTask, callback.release()));
111 } 119 }
112 120
113 void PipelineImpl::Seek(base::TimeDelta time, 121 void PipelineImpl::Seek(base::TimeDelta time,
114 PipelineCallback* seek_callback) { 122 PipelineCallback* seek_callback) {
123 AutoLock auto_lock(lock_);
115 scoped_ptr<PipelineCallback> callback(seek_callback); 124 scoped_ptr<PipelineCallback> callback(seek_callback);
116 if (pipeline_internal_) { 125 if (!running_) {
117 pipeline_internal_->Seek(time, callback.release()); 126 LOG(ERROR) << "Media pipeline must be running";
127 return;
118 } 128 }
129
130 message_loop_->PostTask(FROM_HERE,
131 NewRunnableMethod(this, &PipelineImpl::SeekTask, time,
132 callback.release()));
119 } 133 }
120 134
121 bool PipelineImpl::IsRunning() const { 135 bool PipelineImpl::IsRunning() const {
122 AutoLock auto_lock(lock_); 136 AutoLock auto_lock(lock_);
123 return pipeline_internal_ != NULL; 137 return running_;
124 } 138 }
125 139
126 bool PipelineImpl::IsInitialized() const { 140 bool PipelineImpl::IsInitialized() const {
141 // TODO(scherkus): perhaps replace this with a bool that is set/get under the
142 // lock, because this is breaching the contract that |state_| is only accessed
143 // on |message_loop_|.
127 AutoLock auto_lock(lock_); 144 AutoLock auto_lock(lock_);
128 return pipeline_internal_ && pipeline_internal_->IsInitialized(); 145 return state_ == kStarted;
129 } 146 }
130 147
131 bool PipelineImpl::IsRendered(const std::string& major_mime_type) const { 148 bool PipelineImpl::IsRendered(const std::string& major_mime_type) const {
132 AutoLock auto_lock(lock_); 149 AutoLock auto_lock(lock_);
133 bool is_rendered = (rendered_mime_types_.find(major_mime_type) != 150 bool is_rendered = (rendered_mime_types_.find(major_mime_type) !=
134 rendered_mime_types_.end()); 151 rendered_mime_types_.end());
135 return is_rendered; 152 return is_rendered;
136 } 153 }
137 154
138 float PipelineImpl::GetPlaybackRate() const { 155 float PipelineImpl::GetPlaybackRate() const {
139 AutoLock auto_lock(lock_); 156 AutoLock auto_lock(lock_);
140 return playback_rate_; 157 return playback_rate_;
141 } 158 }
142 159
143 void PipelineImpl::SetPlaybackRate(float playback_rate) { 160 void PipelineImpl::SetPlaybackRate(float playback_rate) {
144 if (playback_rate < 0.0f) { 161 if (playback_rate < 0.0f) {
145 return; 162 return;
146 } 163 }
147 164
148 AutoLock auto_lock(lock_); 165 AutoLock auto_lock(lock_);
149 playback_rate_ = playback_rate; 166 playback_rate_ = playback_rate;
150 if (pipeline_internal_) { 167 if (running_) {
151 pipeline_internal_->PlaybackRateChanged(playback_rate); 168 message_loop_->PostTask(FROM_HERE,
169 NewRunnableMethod(this, &PipelineImpl::PlaybackRateChangedTask,
170 playback_rate));
152 } 171 }
153 } 172 }
154 173
155 float PipelineImpl::GetVolume() const { 174 float PipelineImpl::GetVolume() const {
156 AutoLock auto_lock(lock_); 175 AutoLock auto_lock(lock_);
157 return volume_; 176 return volume_;
158 } 177 }
159 178
160 void PipelineImpl::SetVolume(float volume) { 179 void PipelineImpl::SetVolume(float volume) {
161 if (volume < 0.0f || volume > 1.0f) { 180 if (volume < 0.0f || volume > 1.0f) {
162 return; 181 return;
163 } 182 }
164 183
165 AutoLock auto_lock(lock_); 184 AutoLock auto_lock(lock_);
166 volume_ = volume; 185 volume_ = volume;
167 if (pipeline_internal_) { 186 if (running_) {
168 pipeline_internal_->VolumeChanged(volume); 187 message_loop_->PostTask(FROM_HERE,
188 NewRunnableMethod(this, &PipelineImpl::VolumeChangedTask,
189 volume));
169 } 190 }
170 } 191 }
171 192
172 base::TimeDelta PipelineImpl::GetCurrentTime() const { 193 base::TimeDelta PipelineImpl::GetCurrentTime() const {
173 AutoLock auto_lock(lock_); 194 AutoLock auto_lock(lock_);
174 return time_; 195 return time_;
175 } 196 }
176 197
177 base::TimeDelta PipelineImpl::GetBufferedTime() const { 198 base::TimeDelta PipelineImpl::GetBufferedTime() const {
178 AutoLock auto_lock(lock_); 199 AutoLock auto_lock(lock_);
(...skipping 23 matching lines...) Expand all
202 *height_out = video_height_; 223 *height_out = video_height_;
203 } 224 }
204 225
205 PipelineError PipelineImpl::GetError() const { 226 PipelineError PipelineImpl::GetError() const {
206 AutoLock auto_lock(lock_); 227 AutoLock auto_lock(lock_);
207 return error_; 228 return error_;
208 } 229 }
209 230
210 void PipelineImpl::ResetState() { 231 void PipelineImpl::ResetState() {
211 AutoLock auto_lock(lock_); 232 AutoLock auto_lock(lock_);
212 pipeline_internal_ = NULL; 233 running_ = false;
213 duration_ = base::TimeDelta(); 234 duration_ = base::TimeDelta();
214 buffered_time_ = base::TimeDelta(); 235 buffered_time_ = base::TimeDelta();
215 buffered_bytes_ = 0; 236 buffered_bytes_ = 0;
216 total_bytes_ = 0; 237 total_bytes_ = 0;
217 video_width_ = 0; 238 video_width_ = 0;
218 video_height_ = 0; 239 video_height_ = 0;
219 volume_ = 1.0f; 240 volume_ = 1.0f;
220 playback_rate_ = 0.0f; 241 playback_rate_ = 0.0f;
221 error_ = PIPELINE_OK; 242 error_ = PIPELINE_OK;
222 time_ = base::TimeDelta(); 243 time_ = base::TimeDelta();
223 rendered_mime_types_.clear(); 244 rendered_mime_types_.clear();
224 } 245 }
225 246
226 bool PipelineImpl::IsPipelineOk() const { 247 bool PipelineImpl::IsPipelineOk() {
227 return pipeline_internal_ && PIPELINE_OK == error_; 248 return PIPELINE_OK == GetError();
249 }
250
251 bool PipelineImpl::IsPipelineInitializing() {
252 DCHECK_EQ(MessageLoop::current(), message_loop_);
253 return state_ == kInitDataSource ||
254 state_ == kInitDemuxer ||
255 state_ == kInitAudioDecoder ||
256 state_ == kInitAudioRenderer ||
257 state_ == kInitVideoDecoder ||
258 state_ == kInitVideoRenderer;
228 } 259 }
229 260
230 void PipelineImpl::SetError(PipelineError error) { 261 void PipelineImpl::SetError(PipelineError error) {
262 DCHECK(IsRunning());
263 DCHECK(error != PIPELINE_OK) << "PIPELINE_OK isn't an error!";
264 LOG(ERROR) << "Media pipeline error: " << error;
265
231 AutoLock auto_lock(lock_); 266 AutoLock auto_lock(lock_);
232 error_ = error; 267 error_ = error;
268 message_loop_->PostTask(FROM_HERE,
269 NewRunnableMethod(this, &PipelineImpl::ErrorChangedTask, error));
233 } 270 }
234 271
235 base::TimeDelta PipelineImpl::GetTime() const { 272 base::TimeDelta PipelineImpl::GetTime() const {
273 DCHECK(IsRunning());
236 return GetCurrentTime(); 274 return GetCurrentTime();
237 } 275 }
238 276
239 void PipelineImpl::SetTime(base::TimeDelta time) { 277 void PipelineImpl::SetTime(base::TimeDelta time) {
278 DCHECK(IsRunning());
240 AutoLock auto_lock(lock_); 279 AutoLock auto_lock(lock_);
241 time_ = time; 280 time_ = time;
242 } 281 }
243 282
244 void PipelineImpl::SetDuration(base::TimeDelta duration) { 283 void PipelineImpl::SetDuration(base::TimeDelta duration) {
284 DCHECK(IsRunning());
245 AutoLock auto_lock(lock_); 285 AutoLock auto_lock(lock_);
246 duration_ = duration; 286 duration_ = duration;
247 } 287 }
248 288
249 void PipelineImpl::SetBufferedTime(base::TimeDelta buffered_time) { 289 void PipelineImpl::SetBufferedTime(base::TimeDelta buffered_time) {
290 DCHECK(IsRunning());
250 AutoLock auto_lock(lock_); 291 AutoLock auto_lock(lock_);
251 buffered_time_ = buffered_time; 292 buffered_time_ = buffered_time;
252 } 293 }
253 294
254 void PipelineImpl::SetTotalBytes(int64 total_bytes) { 295 void PipelineImpl::SetTotalBytes(int64 total_bytes) {
296 DCHECK(IsRunning());
255 AutoLock auto_lock(lock_); 297 AutoLock auto_lock(lock_);
256 total_bytes_ = total_bytes; 298 total_bytes_ = total_bytes;
257 } 299 }
258 300
259 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) { 301 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) {
302 DCHECK(IsRunning());
260 AutoLock auto_lock(lock_); 303 AutoLock auto_lock(lock_);
261 buffered_bytes_ = buffered_bytes; 304 buffered_bytes_ = buffered_bytes;
262 } 305 }
263 306
264 void PipelineImpl::SetVideoSize(size_t width, size_t height) { 307 void PipelineImpl::SetVideoSize(size_t width, size_t height) {
308 DCHECK(IsRunning());
265 AutoLock auto_lock(lock_); 309 AutoLock auto_lock(lock_);
266 video_width_ = width; 310 video_width_ = width;
267 video_height_ = height; 311 video_height_ = height;
268 } 312 }
269 313
270 void PipelineImpl::InsertRenderedMimeType(const std::string& major_mime_type) { 314 void PipelineImpl::InsertRenderedMimeType(const std::string& major_mime_type) {
315 DCHECK(IsRunning());
271 AutoLock auto_lock(lock_); 316 AutoLock auto_lock(lock_);
272 rendered_mime_types_.insert(major_mime_type); 317 rendered_mime_types_.insert(major_mime_type);
273 } 318 }
274 319
275 320 bool PipelineImpl::HasRenderedMimeTypes() const {
276 //----------------------------------------------------------------------------- 321 DCHECK(IsRunning());
277 322 AutoLock auto_lock(lock_);
278 PipelineInternal::PipelineInternal(PipelineImpl* pipeline, 323 return !rendered_mime_types_.empty();
279 MessageLoop* message_loop)
280 : pipeline_(pipeline),
281 message_loop_(message_loop),
282 state_(kCreated) {
283 }
284
285 PipelineInternal::~PipelineInternal() {
286 DCHECK(state_ == kCreated || state_ == kStopped);
287 }
288
289 // Called on client's thread.
290 void PipelineInternal::Start(FilterFactory* filter_factory,
291 const std::string& url,
292 PipelineCallback* start_callback) {
293 DCHECK(filter_factory);
294 message_loop_->PostTask(FROM_HERE,
295 NewRunnableMethod(this, &PipelineInternal::StartTask, filter_factory, url,
296 start_callback));
297 }
298
299 // Called on client's thread.
300 void PipelineInternal::Stop(PipelineCallback* stop_callback) {
301 message_loop_->PostTask(FROM_HERE,
302 NewRunnableMethod(this, &PipelineInternal::StopTask, stop_callback));
303 }
304
305 // Called on client's thread.
306 void PipelineInternal::Seek(base::TimeDelta time,
307 PipelineCallback* seek_callback) {
308 message_loop_->PostTask(FROM_HERE,
309 NewRunnableMethod(this, &PipelineInternal::SeekTask, time,
310 seek_callback));
311 }
312
313 // Called on client's thread.
314 void PipelineInternal::PlaybackRateChanged(float playback_rate) {
315 message_loop_->PostTask(FROM_HERE,
316 NewRunnableMethod(this, &PipelineInternal::PlaybackRateChangedTask,
317 playback_rate));
318 }
319
320 // Called on client's thread.
321 void PipelineInternal::VolumeChanged(float volume) {
322 message_loop_->PostTask(FROM_HERE,
323 NewRunnableMethod(this, &PipelineInternal::VolumeChangedTask, volume));
324 } 324 }
325 325
326 // Called from any thread. 326 // Called from any thread.
327 void PipelineInternal::SetError(PipelineError error) { 327 void PipelineImpl::OnFilterInitialize() {
328 // Continue the initialize task by proceeding to the next stage.
328 message_loop_->PostTask(FROM_HERE, 329 message_loop_->PostTask(FROM_HERE,
329 NewRunnableMethod(this, &PipelineInternal::ErrorTask, error)); 330 NewRunnableMethod(this, &PipelineImpl::InitializeTask));
330 } 331 }
331 332
332 // Called from any thread. 333 // Called from any thread.
333 base::TimeDelta PipelineInternal::GetTime() const { 334 void PipelineImpl::OnFilterSeek() {
334 return pipeline_->GetCurrentTime();
335 }
336
337 // Called from any thread.
338 void PipelineInternal::SetTime(base::TimeDelta time) {
339 pipeline_->SetTime(time);
340 }
341
342 // Called from any thread.
343 void PipelineInternal::SetDuration(base::TimeDelta duration) {
344 pipeline_->SetDuration(duration);
345 }
346
347 // Called from any thread.
348 void PipelineInternal::SetBufferedTime(base::TimeDelta buffered_time) {
349 pipeline_->SetBufferedTime(buffered_time);
350 }
351
352 // Called from any thread.
353 void PipelineInternal::SetTotalBytes(int64 total_bytes) {
354 pipeline_->SetTotalBytes(total_bytes);
355 }
356
357 // Called from any thread.
358 void PipelineInternal::SetBufferedBytes(int64 buffered_bytes) {
359 pipeline_->SetBufferedBytes(buffered_bytes);
360 }
361
362 // Called from any thread.
363 void PipelineInternal::SetVideoSize(size_t width, size_t height) {
364 pipeline_->SetVideoSize(width, height);
365 }
366
367 // Called from any thread.
368 void PipelineInternal::OnFilterInitialize() {
369 // Continue the initialize task by proceeding to the next stage.
370 message_loop_->PostTask(FROM_HERE,
371 NewRunnableMethod(this, &PipelineInternal::InitializeTask));
372 }
373
374 // Called from any thread.
375 void PipelineInternal::OnFilterSeek() {
376 // TODO(scherkus): have PipelineInternal wait to receive replies from every 335 // TODO(scherkus): have PipelineInternal wait to receive replies from every
377 // filter before calling the client's |seek_callback_|. 336 // filter before calling the client's |seek_callback_|.
378 } 337 }
379 338
380 void PipelineInternal::StartTask(FilterFactory* filter_factory, 339 void PipelineImpl::StartTask(FilterFactory* filter_factory,
381 const std::string& url, 340 const std::string& url,
382 PipelineCallback* start_callback) { 341 PipelineCallback* start_callback) {
383 DCHECK_EQ(MessageLoop::current(), message_loop_); 342 DCHECK_EQ(MessageLoop::current(), message_loop_);
384 DCHECK_EQ(kCreated, state_); 343 DCHECK_EQ(kCreated, state_);
385 filter_factory_ = filter_factory; 344 filter_factory_ = filter_factory;
386 url_ = url; 345 url_ = url;
387 start_callback_.reset(start_callback); 346 start_callback_.reset(start_callback);
388 347
389 // Kick off initialization. 348 // Kick off initialization.
390 InitializeTask(); 349 InitializeTask();
391 } 350 }
392 351
393 // Main initialization method called on the pipeline thread. This code attempts 352 // Main initialization method called on the pipeline thread. This code attempts
394 // to use the specified filter factory to build a pipeline. 353 // to use the specified filter factory to build a pipeline.
395 // Initialization step performed in this method depends on current state of this 354 // Initialization step performed in this method depends on current state of this
396 // object, indicated by |state_|. After each step of initialization, this 355 // object, indicated by |state_|. After each step of initialization, this
397 // object transits to the next stage. It starts by creating a DataSource, 356 // object transits to the next stage. It starts by creating a DataSource,
398 // connects it to a Demuxer, and then connects the Demuxer's audio stream to an 357 // connects it to a Demuxer, and then connects the Demuxer's audio stream to an
399 // AudioDecoder which is then connected to an AudioRenderer. If the media has 358 // AudioDecoder which is then connected to an AudioRenderer. If the media has
400 // video, then it connects a VideoDecoder to the Demuxer's video stream, and 359 // video, then it connects a VideoDecoder to the Demuxer's video stream, and
401 // then connects the VideoDecoder to a VideoRenderer. 360 // then connects the VideoDecoder to a VideoRenderer.
402 // 361 //
403 // When all required filters have been created and have called their 362 // When all required filters have been created and have called their
404 // FilterHost's InitializationComplete() method, the pipeline will update its 363 // FilterHost's InitializationComplete() method, the pipeline will update its
405 // state to kStarted and |init_callback_|, will be executed. 364 // state to kStarted and |init_callback_|, will be executed.
406 // 365 //
407 // TODO(hclam): InitializeTask() is now starting the pipeline asynchronously. It 366 // TODO(hclam): InitializeTask() is now starting the pipeline asynchronously. It
408 // works like a big state change table. If we no longer need to start filters 367 // works like a big state change table. If we no longer need to start filters
409 // in order, we need to get rid of all the state change. 368 // in order, we need to get rid of all the state change.
410 void PipelineInternal::InitializeTask() { 369 void PipelineImpl::InitializeTask() {
411 DCHECK_EQ(MessageLoop::current(), message_loop_); 370 DCHECK_EQ(MessageLoop::current(), message_loop_);
412 371
413 // If we have received the stop or error signal, return immediately. 372 // If we have received the stop or error signal, return immediately.
414 if (state_ == kStopped || state_ == kError) 373 if (state_ == kStopped || state_ == kError)
415 return; 374 return;
416 375
417 DCHECK(state_ == kCreated || IsPipelineInitializing()); 376 DCHECK(state_ == kCreated || IsPipelineInitializing());
418 377
419 // Just created, create data source. 378 // Just created, create data source.
420 if (state_ == kCreated) { 379 if (state_ == kCreated) {
(...skipping 15 matching lines...) Expand all
436 // If this method returns false, then there's no audio stream. 395 // If this method returns false, then there's no audio stream.
437 if (CreateDecoder<AudioDecoder>()) 396 if (CreateDecoder<AudioDecoder>())
438 return; 397 return;
439 } 398 }
440 399
441 // Assuming audio decoder was created, create audio renderer. 400 // Assuming audio decoder was created, create audio renderer.
442 if (state_ == kInitAudioDecoder) { 401 if (state_ == kInitAudioDecoder) {
443 state_ = kInitAudioRenderer; 402 state_ = kInitAudioRenderer;
444 // Returns false if there's no audio stream. 403 // Returns false if there's no audio stream.
445 if (CreateRenderer<AudioDecoder, AudioRenderer>()) { 404 if (CreateRenderer<AudioDecoder, AudioRenderer>()) {
446 pipeline_->InsertRenderedMimeType(AudioDecoder::major_mime_type()); 405 InsertRenderedMimeType(AudioDecoder::major_mime_type());
447 return; 406 return;
448 } 407 }
449 } 408 }
450 409
451 // Assuming audio renderer was created, create video decoder. 410 // Assuming audio renderer was created, create video decoder.
452 if (state_ == kInitAudioRenderer) { 411 if (state_ == kInitAudioRenderer) {
453 // Then perform the stage of initialization, i.e. initialize video decoder. 412 // Then perform the stage of initialization, i.e. initialize video decoder.
454 state_ = kInitVideoDecoder; 413 state_ = kInitVideoDecoder;
455 if (CreateDecoder<VideoDecoder>()) 414 if (CreateDecoder<VideoDecoder>())
456 return; 415 return;
457 } 416 }
458 417
459 // Assuming video decoder was created, create video renderer. 418 // Assuming video decoder was created, create video renderer.
460 if (state_ == kInitVideoDecoder) { 419 if (state_ == kInitVideoDecoder) {
461 state_ = kInitVideoRenderer; 420 state_ = kInitVideoRenderer;
462 if (CreateRenderer<VideoDecoder, VideoRenderer>()) { 421 if (CreateRenderer<VideoDecoder, VideoRenderer>()) {
463 pipeline_->InsertRenderedMimeType(VideoDecoder::major_mime_type()); 422 InsertRenderedMimeType(VideoDecoder::major_mime_type());
464 return; 423 return;
465 } 424 }
466 } 425 }
467 426
468 if (state_ == kInitVideoRenderer) { 427 if (state_ == kInitVideoRenderer) {
469 if (!IsPipelineOk() || pipeline_->rendered_mime_types_.empty()) { 428 if (!IsPipelineOk() || !HasRenderedMimeTypes()) {
470 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); 429 SetError(PIPELINE_ERROR_COULD_NOT_RENDER);
471 return; 430 return;
472 } 431 }
473 432
474 // Initialization was successful, set the volume and playback rate. 433 // Initialization was successful, set the volume and playback rate.
475 PlaybackRateChangedTask(pipeline_->GetPlaybackRate()); 434 PlaybackRateChangedTask(GetPlaybackRate());
476 VolumeChangedTask(pipeline_->GetVolume()); 435 VolumeChangedTask(GetVolume());
477 436
478 state_ = kStarted; 437 state_ = kStarted;
479 filter_factory_ = NULL; 438 filter_factory_ = NULL;
480 if (start_callback_.get()) { 439 if (start_callback_.get()) {
481 start_callback_->Run(); 440 start_callback_->Run();
482 start_callback_.reset(); 441 start_callback_.reset();
483 } 442 }
484 } 443 }
485 } 444 }
486 445
487 // This method is called as a result of the client calling Pipeline::Stop() or 446 // This method is called as a result of the client calling Pipeline::Stop() or
488 // as the result of an error condition. If there is no error, then set the 447 // as the result of an error condition. If there is no error, then set the
489 // pipeline's |error_| member to PIPELINE_STOPPING. We stop the filters in the 448 // pipeline's |error_| member to PIPELINE_STOPPING. We stop the filters in the
490 // reverse order. 449 // reverse order.
491 // 450 //
492 // TODO(scherkus): beware! this can get posted multiple times since we post 451 // TODO(scherkus): beware! this can get posted multiple times since we post
493 // Stop() tasks even if we've already stopped. Perhaps this should no-op for 452 // Stop() tasks even if we've already stopped. Perhaps this should no-op for
494 // additional calls, however most of this logic will be changing. 453 // additional calls, however most of this logic will be changing.
495 void PipelineInternal::StopTask(PipelineCallback* stop_callback) { 454 void PipelineImpl::StopTask(PipelineCallback* stop_callback) {
496 DCHECK_EQ(MessageLoop::current(), message_loop_); 455 DCHECK_EQ(MessageLoop::current(), message_loop_);
497 stop_callback_.reset(stop_callback); 456 stop_callback_.reset(stop_callback);
498 457
499 // If we've already stopped, return immediately. 458 // If we've already stopped, return immediately.
500 if (state_ == kStopped) { 459 if (state_ == kStopped) {
501 return; 460 return;
502 } 461 }
503 462
504 // Carry out setting the error, notifying the client and destroying filters. 463 // Carry out setting the error, notifying the client and destroying filters.
505 ErrorTask(PIPELINE_STOPPING); 464 ErrorChangedTask(PIPELINE_STOPPING);
506 465
507 // We no longer need to examine our previous state, set it to stopped. 466 // We no longer need to examine our previous state, set it to stopped.
508 state_ = kStopped; 467 state_ = kStopped;
509 468
510 // Reset the pipeline and set our reference to NULL so we don't accidentally 469 // Reset the pipeline.
511 // modify the pipeline. Once remaining tasks execute we will be destroyed. 470 ResetState();
512 pipeline_->ResetState();
513 pipeline_ = NULL;
514 471
515 // Notify the client that stopping has finished. 472 // Notify the client that stopping has finished.
516 if (stop_callback_.get()) { 473 if (stop_callback_.get()) {
517 stop_callback_->Run(); 474 stop_callback_->Run();
518 stop_callback_.reset(); 475 stop_callback_.reset();
519 } 476 }
520 } 477 }
521 478
522 void PipelineInternal::ErrorTask(PipelineError error) { 479 void PipelineImpl::ErrorChangedTask(PipelineError error) {
523 DCHECK_EQ(MessageLoop::current(), message_loop_); 480 DCHECK_EQ(MessageLoop::current(), message_loop_);
524 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; 481 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
525 482
526 // Suppress executing additional error logic. 483 // Suppress executing additional error logic.
527 // TODO(hclam): Remove the condition for kStopped. It is there only because 484 // TODO(hclam): Remove the condition for kStopped. It is there only because
528 // FFmpegDemuxer submits a read error while reading after it is called to 485 // FFmpegDemuxer submits a read error while reading after it is called to
529 // stop. After FFmpegDemuxer is cleaned up we should remove this condition 486 // stop. After FFmpegDemuxer is cleaned up we should remove this condition
530 // and add an extra assert. 487 // and add an extra assert.
531 if (state_ == kError || state_ == kStopped) { 488 if (state_ == kError || state_ == kStopped) {
532 return; 489 return;
533 } 490 }
534 491
535 // Update our error code first in case we execute the start callback.
536 pipeline_->SetError(error);
537
538 // Notify the client that starting did not complete, if necessary. 492 // Notify the client that starting did not complete, if necessary.
539 if (IsPipelineInitializing() && start_callback_.get()) { 493 if (IsPipelineInitializing() && start_callback_.get()) {
540 start_callback_->Run(); 494 start_callback_->Run();
541 } 495 }
542 start_callback_.reset(); 496 start_callback_.reset();
543 filter_factory_ = NULL; 497 filter_factory_ = NULL;
544 498
545 // We no longer need to examine our previous state, set it to stopped. 499 // We no longer need to examine our previous state, set it to stopped.
546 state_ = kError; 500 state_ = kError;
547 501
548 // Destroy every filter and reset the pipeline as well. 502 // Destroy every filter and reset the pipeline as well.
549 DestroyFilters(); 503 DestroyFilters();
550 } 504 }
551 505
552 void PipelineInternal::PlaybackRateChangedTask(float playback_rate) { 506 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) {
553 DCHECK_EQ(MessageLoop::current(), message_loop_); 507 DCHECK_EQ(MessageLoop::current(), message_loop_);
554 for (FilterVector::iterator iter = filters_.begin(); 508 for (FilterVector::iterator iter = filters_.begin();
555 iter != filters_.end(); 509 iter != filters_.end();
556 ++iter) { 510 ++iter) {
557 (*iter)->SetPlaybackRate(playback_rate); 511 (*iter)->SetPlaybackRate(playback_rate);
558 } 512 }
559 } 513 }
560 514
561 void PipelineInternal::VolumeChangedTask(float volume) { 515 void PipelineImpl::VolumeChangedTask(float volume) {
562 DCHECK_EQ(MessageLoop::current(), message_loop_); 516 DCHECK_EQ(MessageLoop::current(), message_loop_);
563 517
564 scoped_refptr<AudioRenderer> audio_renderer; 518 scoped_refptr<AudioRenderer> audio_renderer;
565 GetFilter(&audio_renderer); 519 GetFilter(&audio_renderer);
566 if (audio_renderer) { 520 if (audio_renderer) {
567 audio_renderer->SetVolume(volume); 521 audio_renderer->SetVolume(volume);
568 } 522 }
569 } 523 }
570 524
571 void PipelineInternal::SeekTask(base::TimeDelta time, 525 void PipelineImpl::SeekTask(base::TimeDelta time,
572 PipelineCallback* seek_callback) { 526 PipelineCallback* seek_callback) {
573 DCHECK_EQ(MessageLoop::current(), message_loop_); 527 DCHECK_EQ(MessageLoop::current(), message_loop_);
574 seek_callback_.reset(seek_callback); 528 seek_callback_.reset(seek_callback);
575 529
576 // Supress seeking if we haven't fully started. 530 // Supress seeking if we haven't fully started.
577 if (state_ != kStarted) { 531 if (state_ != kStarted) {
578 return; 532 return;
579 } 533 }
580 534
581 for (FilterVector::iterator iter = filters_.begin(); 535 for (FilterVector::iterator iter = filters_.begin();
582 iter != filters_.end(); 536 iter != filters_.end();
583 ++iter) { 537 ++iter) {
584 (*iter)->Seek(time, NewCallback(this, &PipelineInternal::OnFilterSeek)); 538 (*iter)->Seek(time, NewCallback(this, &PipelineImpl::OnFilterSeek));
585 } 539 }
586 540
587 // TODO(hclam): we should set the time when the above seek operations were all 541 // TODO(hclam): we should set the time when the above seek operations were all
588 // successful and first frame/packet at the desired time is decoded. I'm 542 // successful and first frame/packet at the desired time is decoded. I'm
589 // setting the time here because once we do the callback the user can ask for 543 // setting the time here because once we do the callback the user can ask for
590 // current time immediately, which is the old time. In order to get rid this 544 // current time immediately, which is the old time. In order to get rid this
591 // little glitch, we either assume the seek was successful and time is updated 545 // little glitch, we either assume the seek was successful and time is updated
592 // immediately here or we set time and do callback when we have new 546 // immediately here or we set time and do callback when we have new
593 // frames/packets. 547 // frames/packets.
594 SetTime(time); 548 SetTime(time);
595 if (seek_callback_.get()) { 549 if (seek_callback_.get()) {
596 seek_callback_->Run(); 550 seek_callback_->Run();
597 seek_callback_.reset(); 551 seek_callback_.reset();
598 } 552 }
599 } 553 }
600 554
601 template <class Filter, class Source> 555 template <class Filter, class Source>
602 void PipelineInternal::CreateFilter(FilterFactory* filter_factory, 556 void PipelineImpl::CreateFilter(FilterFactory* filter_factory,
603 Source source, 557 Source source,
604 const MediaFormat& media_format) { 558 const MediaFormat& media_format) {
605 DCHECK_EQ(MessageLoop::current(), message_loop_); 559 DCHECK_EQ(MessageLoop::current(), message_loop_);
606 DCHECK(IsPipelineOk()); 560 DCHECK(IsPipelineOk());
607 561
608 // Create the filter. 562 // Create the filter.
609 scoped_refptr<Filter> filter = filter_factory->Create<Filter>(media_format); 563 scoped_refptr<Filter> filter = filter_factory->Create<Filter>(media_format);
610 if (!filter) { 564 if (!filter) {
611 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); 565 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING);
612 return; 566 return;
613 } 567 }
614 568
(...skipping 13 matching lines...) Expand all
628 // Register ourselves as the filter's host. 582 // Register ourselves as the filter's host.
629 DCHECK(IsPipelineOk()); 583 DCHECK(IsPipelineOk());
630 DCHECK(filter_types_.find(Filter::filter_type()) == filter_types_.end()) 584 DCHECK(filter_types_.find(Filter::filter_type()) == filter_types_.end())
631 << "Filter type " << Filter::filter_type() << " already exists"; 585 << "Filter type " << Filter::filter_type() << " already exists";
632 filter->set_host(this); 586 filter->set_host(this);
633 filters_.push_back(filter.get()); 587 filters_.push_back(filter.get());
634 filter_types_[Filter::filter_type()] = filter.get(); 588 filter_types_[Filter::filter_type()] = filter.get();
635 589
636 // Now initialize the filter. 590 // Now initialize the filter.
637 filter->Initialize(source, 591 filter->Initialize(source,
638 NewCallback(this, &PipelineInternal::OnFilterInitialize)); 592 NewCallback(this, &PipelineImpl::OnFilterInitialize));
639 } 593 }
640 594
641 void PipelineInternal::CreateDataSource() { 595 void PipelineImpl::CreateDataSource() {
642 DCHECK_EQ(MessageLoop::current(), message_loop_); 596 DCHECK_EQ(MessageLoop::current(), message_loop_);
643 DCHECK(IsPipelineOk()); 597 DCHECK(IsPipelineOk());
644 598
645 MediaFormat url_format; 599 MediaFormat url_format;
646 url_format.SetAsString(MediaFormat::kMimeType, mime_type::kURL); 600 url_format.SetAsString(MediaFormat::kMimeType, mime_type::kURL);
647 url_format.SetAsString(MediaFormat::kURL, url_); 601 url_format.SetAsString(MediaFormat::kURL, url_);
648 CreateFilter<DataSource>(filter_factory_, url_, url_format); 602 CreateFilter<DataSource>(filter_factory_, url_, url_format);
649 } 603 }
650 604
651 void PipelineInternal::CreateDemuxer() { 605 void PipelineImpl::CreateDemuxer() {
652 DCHECK_EQ(MessageLoop::current(), message_loop_); 606 DCHECK_EQ(MessageLoop::current(), message_loop_);
653 DCHECK(IsPipelineOk()); 607 DCHECK(IsPipelineOk());
654 608
655 scoped_refptr<DataSource> data_source; 609 scoped_refptr<DataSource> data_source;
656 GetFilter(&data_source); 610 GetFilter(&data_source);
657 DCHECK(data_source); 611 DCHECK(data_source);
658 CreateFilter<Demuxer, DataSource>(filter_factory_, data_source); 612 CreateFilter<Demuxer, DataSource>(filter_factory_, data_source);
659 } 613 }
660 614
661 template <class Decoder> 615 template <class Decoder>
662 bool PipelineInternal::CreateDecoder() { 616 bool PipelineImpl::CreateDecoder() {
663 DCHECK_EQ(MessageLoop::current(), message_loop_); 617 DCHECK_EQ(MessageLoop::current(), message_loop_);
664 DCHECK(IsPipelineOk()); 618 DCHECK(IsPipelineOk());
665 619
666 scoped_refptr<Demuxer> demuxer; 620 scoped_refptr<Demuxer> demuxer;
667 GetFilter(&demuxer); 621 GetFilter(&demuxer);
668 DCHECK(demuxer); 622 DCHECK(demuxer);
669 623
670 const std::string major_mime_type = Decoder::major_mime_type(); 624 const std::string major_mime_type = Decoder::major_mime_type();
671 const int num_outputs = demuxer->GetNumberOfStreams(); 625 const int num_outputs = demuxer->GetNumberOfStreams();
672 for (int i = 0; i < num_outputs; ++i) { 626 for (int i = 0; i < num_outputs; ++i) {
673 scoped_refptr<DemuxerStream> stream = demuxer->GetStream(i); 627 scoped_refptr<DemuxerStream> stream = demuxer->GetStream(i);
674 std::string value; 628 std::string value;
675 if (stream->media_format().GetAsString(MediaFormat::kMimeType, &value) && 629 if (stream->media_format().GetAsString(MediaFormat::kMimeType, &value) &&
676 0 == value.compare(0, major_mime_type.length(), major_mime_type)) { 630 0 == value.compare(0, major_mime_type.length(), major_mime_type)) {
677 CreateFilter<Decoder, DemuxerStream>(filter_factory_, stream); 631 CreateFilter<Decoder, DemuxerStream>(filter_factory_, stream);
678 return true; 632 return true;
679 } 633 }
680 } 634 }
681 return false; 635 return false;
682 } 636 }
683 637
684 template <class Decoder, class Renderer> 638 template <class Decoder, class Renderer>
685 bool PipelineInternal::CreateRenderer() { 639 bool PipelineImpl::CreateRenderer() {
686 DCHECK_EQ(MessageLoop::current(), message_loop_); 640 DCHECK_EQ(MessageLoop::current(), message_loop_);
687 DCHECK(IsPipelineOk()); 641 DCHECK(IsPipelineOk());
688 642
689 scoped_refptr<Decoder> decoder; 643 scoped_refptr<Decoder> decoder;
690 GetFilter(&decoder); 644 GetFilter(&decoder);
691 645
692 if (decoder) { 646 if (decoder) {
693 // If the decoder was created. 647 // If the decoder was created.
694 const std::string major_mime_type = Decoder::major_mime_type(); 648 const std::string major_mime_type = Decoder::major_mime_type();
695 CreateFilter<Renderer, Decoder>(filter_factory_, decoder); 649 CreateFilter<Renderer, Decoder>(filter_factory_, decoder);
696 return true; 650 return true;
697 } 651 }
698 return false; 652 return false;
699 } 653 }
700 654
701 template <class Filter> 655 template <class Filter>
702 void PipelineInternal::GetFilter(scoped_refptr<Filter>* filter_out) const { 656 void PipelineImpl::GetFilter(scoped_refptr<Filter>* filter_out) const {
703 DCHECK_EQ(MessageLoop::current(), message_loop_); 657 DCHECK_EQ(MessageLoop::current(), message_loop_);
704 658
705 FilterTypeMap::const_iterator ft = filter_types_.find(Filter::filter_type()); 659 FilterTypeMap::const_iterator ft = filter_types_.find(Filter::filter_type());
706 if (ft == filter_types_.end()) { 660 if (ft == filter_types_.end()) {
707 *filter_out = NULL; 661 *filter_out = NULL;
708 } else { 662 } else {
709 *filter_out = reinterpret_cast<Filter*>(ft->second.get()); 663 *filter_out = reinterpret_cast<Filter*>(ft->second.get());
710 } 664 }
711 } 665 }
712 666
713 void PipelineInternal::DestroyFilters() { 667 void PipelineImpl::DestroyFilters() {
714 // Stop every filter. 668 // Stop every filter.
715 for (FilterVector::iterator iter = filters_.begin(); 669 for (FilterVector::iterator iter = filters_.begin();
716 iter != filters_.end(); 670 iter != filters_.end();
717 ++iter) { 671 ++iter) {
718 (*iter)->Stop(); 672 (*iter)->Stop();
719 } 673 }
720 674
721 // Crude blocking counter implementation. 675 // Crude blocking counter implementation.
722 Lock lock; 676 Lock lock;
723 ConditionVariable wait_for_zero(&lock); 677 ConditionVariable wait_for_zero(&lock);
(...skipping 30 matching lines...) Expand all
754 708
755 // Reset the pipeline, which will decrement a reference to this object. 709 // Reset the pipeline, which will decrement a reference to this object.
756 // We will get destroyed as soon as the remaining tasks finish executing. 710 // We will get destroyed as soon as the remaining tasks finish executing.
757 // To be safe, we'll set our pipeline reference to NULL. 711 // To be safe, we'll set our pipeline reference to NULL.
758 filters_.clear(); 712 filters_.clear();
759 filter_types_.clear(); 713 filter_types_.clear();
760 STLDeleteElements(&filter_threads_); 714 STLDeleteElements(&filter_threads_);
761 } 715 }
762 716
763 } // namespace media 717 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/base/pipeline_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698