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

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

Issue 39170: Pipeline_Impl was modified to properly render a stream that has video but no ... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-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 #include "base/compiler_specific.h" 5 #include "base/compiler_specific.h"
6 #include "media/base/filter_host_impl.h" 6 #include "media/base/filter_host_impl.h"
7 #include "media/base/media_format.h" 7 #include "media/base/media_format.h"
8 #include "media/base/pipeline_impl.h" 8 #include "media/base/pipeline_impl.h"
9 9
10 namespace media { 10 namespace media {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 } 88 }
89 89
90 void PipelineImpl::InternalSetPlaybackRate(float rate) { 90 void PipelineImpl::InternalSetPlaybackRate(float rate) {
91 AutoLock auto_lock(lock_); 91 AutoLock auto_lock(lock_);
92 if (playback_rate_ == 0.0f && rate > 0.0f) { 92 if (playback_rate_ == 0.0f && rate > 0.0f) {
93 ticks_at_last_set_time_ = base::TimeTicks::Now(); 93 ticks_at_last_set_time_ = base::TimeTicks::Now();
94 } 94 }
95 playback_rate_ = rate; 95 playback_rate_ = rate;
96 } 96 }
97 97
98
99 PipelineError PipelineImpl::GetError() const { 98 PipelineError PipelineImpl::GetError() const {
100 AutoLock auto_lock(const_cast<Lock&>(lock_)); 99 AutoLock auto_lock(const_cast<Lock&>(lock_));
101 return error_; 100 return error_;
102 } 101 }
103 102
103 bool PipelineImpl::IsRendered(const std::string& major_mime_type) const {
104 AutoLock auto_lock(const_cast<Lock&>(lock_));
105 bool is_rendered = (rendered_mime_types_.find(major_mime_type) !=
106 rendered_mime_types_.end());
107 return is_rendered;
108 }
109
110
104 bool PipelineImpl::InternalSetError(PipelineError error) { 111 bool PipelineImpl::InternalSetError(PipelineError error) {
112 // Don't want callers to set an error of "OK". STOPPING is a special value
113 // that should only be used internally by the StopTask() method.
114 DCHECK(PIPELINE_OK != error && PIPELINE_STOPPING != error);
115 LOG(WARNING) << "media::Pipeline error: " << error;
105 AutoLock auto_lock(lock_); 116 AutoLock auto_lock(lock_);
106 bool changed_error = false; 117 bool changed_error = false;
107 DCHECK(PIPELINE_OK != error);
108 if (PIPELINE_OK == error_) { 118 if (PIPELINE_OK == error_) {
109 error_ = error; 119 error_ = error;
110 changed_error = true; 120 changed_error = true;
111 } 121 }
112 return changed_error; 122 return changed_error;
113 } 123 }
114 124
115 // Creates the PipelineThread and calls it's start method. 125 // Creates the PipelineThread and calls it's start method.
116 bool PipelineImpl::Start(FilterFactory* factory, 126 bool PipelineImpl::Start(FilterFactory* factory,
117 const std::string& url, 127 const std::string& url,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 buffered_time_ = base::TimeDelta(); 187 buffered_time_ = base::TimeDelta();
178 buffered_bytes_ = 0; 188 buffered_bytes_ = 0;
179 total_bytes_ = 0; 189 total_bytes_ = 0;
180 video_width_ = 0; 190 video_width_ = 0;
181 video_height_ = 0; 191 video_height_ = 0;
182 volume_ = 0.0f; 192 volume_ = 0.0f;
183 playback_rate_ = 0.0f; 193 playback_rate_ = 0.0f;
184 error_ = PIPELINE_OK; 194 error_ = PIPELINE_OK;
185 time_ = base::TimeDelta(); 195 time_ = base::TimeDelta();
186 ticks_at_last_set_time_ = base::TimeTicks::Now(); 196 ticks_at_last_set_time_ = base::TimeTicks::Now();
197 rendered_mime_types_.clear();
187 } 198 }
188 199
189 void PipelineImpl::SetDuration(base::TimeDelta duration) { 200 void PipelineImpl::SetDuration(base::TimeDelta duration) {
190 AutoLock auto_lock(lock_); 201 AutoLock auto_lock(lock_);
191 duration_ = duration; 202 duration_ = duration;
192 } 203 }
193 204
194 void PipelineImpl::SetBufferedTime(base::TimeDelta buffered_time) { 205 void PipelineImpl::SetBufferedTime(base::TimeDelta buffered_time) {
195 AutoLock auto_lock(lock_); 206 AutoLock auto_lock(lock_);
196 buffered_time_ = buffered_time; 207 buffered_time_ = buffered_time;
197 } 208 }
198 209
199 void PipelineImpl::SetTotalBytes(int64 total_bytes) { 210 void PipelineImpl::SetTotalBytes(int64 total_bytes) {
200 AutoLock auto_lock(lock_); 211 AutoLock auto_lock(lock_);
201 total_bytes_ = total_bytes; 212 total_bytes_ = total_bytes;
202 } 213 }
203 214
204 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) { 215 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) {
205 AutoLock auto_lock(lock_); 216 AutoLock auto_lock(lock_);
206 buffered_bytes_ = buffered_bytes; 217 buffered_bytes_ = buffered_bytes;
207 } 218 }
208 219
209 void PipelineImpl::SetVideoSize(size_t width, size_t height) { 220 void PipelineImpl::SetVideoSize(size_t width, size_t height) {
210 AutoLock auto_lock(lock_); 221 AutoLock auto_lock(lock_);
211 video_width_ = width; 222 video_width_ = width;
212 video_height_ = height; 223 video_height_ = height;
213 } 224 }
214 225
226 void PipelineImpl::InsertRenderedMimeType(const std::string& major_mime_type) {
227 AutoLock auto_lock(lock_);
228 rendered_mime_types_.insert(major_mime_type);
229 }
230
231
215 //----------------------------------------------------------------------------- 232 //-----------------------------------------------------------------------------
216 233
217 PipelineThread::PipelineThread(PipelineImpl* pipeline) 234 PipelineThread::PipelineThread(PipelineImpl* pipeline)
218 : pipeline_(pipeline), 235 : pipeline_(pipeline),
219 thread_("PipelineThread"), 236 thread_("PipelineThread"),
220 time_update_callback_scheduled_(false), 237 time_update_callback_scheduled_(false),
221 host_initializing_(NULL) { 238 host_initializing_(NULL) {
222 } 239 }
223 240
224 PipelineThread::~PipelineThread() { 241 PipelineThread::~PipelineThread() {
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 // init_complete_callback, it is called with "true". 349 // init_complete_callback, it is called with "true".
333 // If initializatoin fails, the client's callback will still be called, but 350 // If initializatoin fails, the client's callback will still be called, but
334 // the bool parameter passed to it will be false. 351 // the bool parameter passed to it will be false.
335 // 352 //
336 // Note that at each step in this process, the initialization of any filter 353 // Note that at each step in this process, the initialization of any filter
337 // may require running the pipeline thread's message loop recursively. This is 354 // may require running the pipeline thread's message loop recursively. This is
338 // handled by the CreateFilter method. 355 // handled by the CreateFilter method.
339 void PipelineThread::StartTask(FilterFactory* filter_factory, 356 void PipelineThread::StartTask(FilterFactory* filter_factory,
340 const std::string& url, 357 const std::string& url,
341 Callback1<bool>::Type* init_complete_callback) { 358 Callback1<bool>::Type* init_complete_callback) {
342 bool success = true;
343
344 // During the entire StartTask we hold the initialization_lock_ so that 359 // During the entire StartTask we hold the initialization_lock_ so that
345 // if the client calls the Pipeline::Stop method while we are running a 360 // if the client calls the Pipeline::Stop method while we are running a
346 // nested message loop, we can correctly unwind out of it before calling 361 // nested message loop, we can correctly unwind out of it before calling
347 // the Thread::Stop method. 362 // the Thread::Stop method.
348 AutoLock auto_lock(initialization_lock_); 363 AutoLock auto_lock(initialization_lock_);
349 364
350 // Add ourselves as a destruction observer of the thread's message loop so 365 // Add ourselves as a destruction observer of the thread's message loop so
351 // we can delete filters at an appropriate time (when all tasks have been 366 // we can delete filters at an appropriate time (when all tasks have been
352 // processed and the thread is about to be destroyed). 367 // processed and the thread is about to be destroyed).
353 message_loop()->AddDestructionObserver(this); 368 message_loop()->AddDestructionObserver(this);
354 success = CreateDataSource(filter_factory, url); 369
355 if (success) { 370 scoped_refptr<DataSource> data_source = CreateDataSource(filter_factory, url);
356 success = CreateAndConnect<Demuxer, DataSource>(filter_factory); 371 if (PipelineOk()) {
357 } 372 scoped_refptr<Demuxer> demuxer =
358 if (success) { 373 CreateFilter<Demuxer, DataSource>(filter_factory, data_source);
359 success = CreateDecoder<AudioDecoder>(filter_factory); 374 if (PipelineOk()) {
360 } 375 Render<AudioDecoder, AudioRenderer>(filter_factory, demuxer);
361 if (success) { 376 }
362 success = CreateAndConnect<AudioRenderer, AudioDecoder>(filter_factory); 377 if (PipelineOk()) {
363 } 378 Render<VideoDecoder, VideoRenderer>(filter_factory, demuxer);
364 if (success && HasVideo()) {
365 success = CreateDecoder<VideoDecoder>(filter_factory);
366 if (success) {
367 success = CreateAndConnect<VideoRenderer, VideoDecoder>(filter_factory);
368 } 379 }
369 } 380 }
370 if (success) { 381
371 pipeline_->initialized_ = true; 382 if (PipelineOk() && pipeline_->rendered_mime_types_.empty()) {
372 } else { 383 Error(PIPELINE_ERROR_COULD_NOT_RENDER);
373 Error(PIPELINE_ERROR_INITIALIZATION_FAILED);
374 } 384 }
375 385
386 pipeline_->initialized_ = PipelineOk();
387
376 // No matter what, we're done with the filter factory, and 388 // No matter what, we're done with the filter factory, and
377 // client callback so get rid of them. 389 // client callback so get rid of them.
378 filter_factory->Release(); 390 filter_factory->Release();
379 if (init_complete_callback) { 391 if (init_complete_callback) {
380 init_complete_callback->Run(success); 392 init_complete_callback->Run(pipeline_->initialized_);
381 delete init_complete_callback; 393 delete init_complete_callback;
382 } 394 }
383 } 395 }
384 396
385 // This method is called as a result of the client calling Pipeline::Stop() or 397 // This method is called as a result of the client calling Pipeline::Stop() or
386 // as the result of an error condition. If there is no error, then set the 398 // as the result of an error condition. If there is no error, then set the
387 // pipeline's error_ member to PIPELINE_STOPPING. We stop the filters in the 399 // pipeline's error_ member to PIPELINE_STOPPING. We stop the filters in the
388 // reverse order. 400 // reverse order.
389 void PipelineThread::StopTask() { 401 void PipelineThread::StopTask() {
390 if (PIPELINE_OK == pipeline_->error_) { 402 if (PipelineOk()) {
391 pipeline_->error_ = PIPELINE_STOPPING; 403 pipeline_->error_ = PIPELINE_STOPPING;
392 } 404 }
393 FilterHostVector::reverse_iterator riter = filter_hosts_.rbegin(); 405 FilterHostVector::reverse_iterator riter = filter_hosts_.rbegin();
394 while (riter != filter_hosts_.rend()) { 406 while (riter != filter_hosts_.rend()) {
395 (*riter)->Stop(); 407 (*riter)->Stop();
396 ++riter; 408 ++riter;
397 } 409 }
398 if (host_initializing_) { 410 if (host_initializing_) {
399 host_initializing_ = NULL; 411 host_initializing_ = NULL;
400 message_loop()->Quit(); 412 message_loop()->Quit();
401 } 413 }
402 } 414 }
403 415
416 template <class Decoder, class Renderer>
417 void PipelineThread::Render(FilterFactory* filter_factory, Demuxer* demuxer) {
418 DCHECK(PipelineOk());
419 const std::string major_mime_type = Decoder::major_mime_type();
420 const int num_outputs = demuxer->GetNumberOfStreams();
421 for (int i = 0; i < num_outputs; ++i) {
422 DemuxerStream* demuxer_stream = demuxer->GetStream(i);
423 const MediaFormat* stream_format = demuxer_stream->GetMediaFormat();
424 std::string value;
425 if (stream_format->GetAsString(MediaFormat::kMimeType, &value) &&
426 0 == value.compare(0, major_mime_type.length(), major_mime_type)) {
427 scoped_refptr<Decoder> decoder =
428 CreateFilter<Decoder, DemuxerStream>(filter_factory, demuxer_stream);
429 if (PipelineOk()) {
430 DCHECK(decoder);
431 CreateFilter<Renderer, Decoder>(filter_factory, decoder);
432 }
433 if (PipelineOk()) {
434 pipeline_->InsertRenderedMimeType(major_mime_type);
435 }
436 break;
437 }
438 }
439 }
440
441
404 // Task runs as a result of a filter calling InitializationComplete. If for 442 // Task runs as a result of a filter calling InitializationComplete. If for
405 // some reason StopTask has been executed prior to this, the host_initializing_ 443 // some reason StopTask has been executed prior to this, the host_initializing_
406 // member will be NULL, and the message loop will have been quit already, so 444 // member will be NULL, and the message loop will have been quit already, so
407 // we don't want to do it again. 445 // we don't want to do it again.
408 void PipelineThread::InitializationCompleteTask(FilterHostImpl* host) { 446 void PipelineThread::InitializationCompleteTask(FilterHostImpl* host) {
409 if (host == host_initializing_) { 447 if (host == host_initializing_) {
410 host_initializing_ = NULL; 448 host_initializing_ = NULL;
411 message_loop()->Quit(); 449 message_loop()->Quit();
412 } else { 450 } else {
413 DCHECK(!host_initializing_); 451 DCHECK(!host_initializing_);
(...skipping 12 matching lines...) Expand all
426 void PipelineThread::SeekTask(base::TimeDelta time) { 464 void PipelineThread::SeekTask(base::TimeDelta time) {
427 FilterHostVector::iterator iter = filter_hosts_.begin(); 465 FilterHostVector::iterator iter = filter_hosts_.begin();
428 while (iter != filter_hosts_.end()) { 466 while (iter != filter_hosts_.end()) {
429 (*iter)->media_filter()->Seek(time); 467 (*iter)->media_filter()->Seek(time);
430 ++iter; 468 ++iter;
431 } 469 }
432 } 470 }
433 471
434 void PipelineThread::SetVolumeTask(float volume) { 472 void PipelineThread::SetVolumeTask(float volume) {
435 pipeline_->volume_ = volume; 473 pipeline_->volume_ = volume;
436 AudioRenderer* audio_renderer = GetFilter<AudioRenderer>(); 474 scoped_refptr<AudioRenderer> audio_renderer;
475 GetFilter(&audio_renderer);
437 if (audio_renderer) { 476 if (audio_renderer) {
438 audio_renderer->SetVolume(volume); 477 audio_renderer->SetVolume(volume);
439 } 478 }
440 } 479 }
441 480
442 void PipelineThread::SetTimeTask() { 481 void PipelineThread::SetTimeTask() {
443 time_update_callback_scheduled_ = false; 482 time_update_callback_scheduled_ = false;
444 FilterHostVector::iterator iter = filter_hosts_.begin(); 483 FilterHostVector::iterator iter = filter_hosts_.begin();
445 while (iter != filter_hosts_.end()) { 484 while (iter != filter_hosts_.end()) {
446 (*iter)->RunTimeUpdateCallback(pipeline_->time_); 485 (*iter)->RunTimeUpdateCallback(pipeline_->time_);
447 ++iter; 486 ++iter;
448 } 487 }
449 } 488 }
450 489
451 template <class Filter> 490 template <class Filter>
452 Filter* PipelineThread::GetFilter() const { 491 void PipelineThread::GetFilter(scoped_refptr<Filter>* filter_out) const {
453 Filter* filter = NULL; 492 *filter_out = NULL;
454 FilterHostVector::const_iterator iter = filter_hosts_.begin(); 493 for (FilterHostVector::const_iterator iter = filter_hosts_.begin();
455 while (iter != filter_hosts_.end() && NULL == filter) { 494 iter != filter_hosts_.end() && NULL == *filter_out;
456 filter = (*iter)->GetFilter<Filter>(); 495 iter++) {
457 ++iter; 496 (*iter)->GetFilter(filter_out);
458 } 497 }
459 return filter;
460 } 498 }
461 499
462 template <class Filter, class Source> 500 template <class Filter, class Source>
463 bool PipelineThread::CreateFilter(FilterFactory* filter_factory, 501 scoped_refptr<Filter> PipelineThread::CreateFilter(
464 Source source, 502 FilterFactory* filter_factory,
465 const MediaFormat* media_format) { 503 Source source,
504 const MediaFormat* media_format) {
505 DCHECK(PipelineOk());
466 scoped_refptr<Filter> filter = filter_factory->Create<Filter>(media_format); 506 scoped_refptr<Filter> filter = filter_factory->Create<Filter>(media_format);
467 bool success = (NULL != filter); 507 if (!filter) {
468 if (success) { 508 Error(PIPELINE_ERROR_REQUIRED_FILTER_MISSING);
509 } else {
469 DCHECK(!host_initializing_); 510 DCHECK(!host_initializing_);
470 host_initializing_ = new FilterHostImpl(this, filter.get()); 511 host_initializing_ = new FilterHostImpl(this, filter.get());
471 success = (NULL != host_initializing_); 512 if (NULL == host_initializing_) {
513 Error(PIPELINE_ERROR_OUT_OF_MEMORY);
514 } else {
515 filter_hosts_.push_back(host_initializing_);
516 filter->SetFilterHost(host_initializing_);
517 if (!filter->Initialize(source)) {
518 Error(PIPELINE_ERROR_INITIALIZATION_FAILED);
519 }
520 }
472 } 521 }
473 if (success) { 522 if (PipelineOk()) {
474 filter_hosts_.push_back(host_initializing_);
475 filter->SetFilterHost(host_initializing_);
476
477 // The filter must return true from initialize and there must still not
478 // be an error or it's not successful.
479 success = (filter->Initialize(source) &&
480 PIPELINE_OK == pipeline_->error_);
481 }
482 if (success) {
483 // Now we run the thread's message loop recursively. We want all 523 // Now we run the thread's message loop recursively. We want all
484 // pending tasks to be processed, so we set nestable tasks to be allowed 524 // pending tasks to be processed, so we set nestable tasks to be allowed
485 // and then run the loop. The only way we exit the loop is as the result 525 // and then run the loop. The only way we exit the loop is as the result
486 // of a call to FilterHost::InitializationComplete, FilterHost::Error, or 526 // of a call to FilterHost::InitializationComplete, FilterHost::Error, or
487 // Pipeline::Stop. In each of these cases, the corresponding task method 527 // Pipeline::Stop. In each of these cases, the corresponding task method
488 // sets host_initializing_ to NULL to signal that the message loop's Quit 528 // sets host_initializing_ to NULL to signal that the message loop's Quit
489 // method has already been called, and then calls message_loop()->Quit(). 529 // method has already been called, and then calls message_loop()->Quit().
490 // The setting of |host_initializing_| to NULL in the task prevents a 530 // The setting of |host_initializing_| to NULL in the task prevents a
491 // subsequent task from accidentally quitting the wrong (non-nested) loop. 531 // subsequent task from accidentally quitting the wrong (non-nested) loop.
492 message_loop()->SetNestableTasksAllowed(true); 532 message_loop()->SetNestableTasksAllowed(true);
493 message_loop()->Run(); 533 message_loop()->Run();
494 message_loop()->SetNestableTasksAllowed(false); 534 message_loop()->SetNestableTasksAllowed(false);
495 DCHECK(!host_initializing_); 535 DCHECK(!host_initializing_);
496 536 } else {
497 // If an error occurred while we were in the nested Run state, then 537 // This could still be set if we never ran the message loop (for example,
498 // not successful. When stopping, the |error_| member is set to a value of 538 // if the fiter returned false from it's Initialize() method), so make sure
499 // PIPELINE_STOPPING so we will exit in that case also with false. 539 // to reset it.
500 success = (PIPELINE_OK == pipeline_->error_); 540 host_initializing_ = NULL;
501 } 541 }
502 542 if (!PipelineOk()) {
503 // This could still be set if we never ran the message loop (for example, 543 filter = NULL;
504 // if the fiter returned false from it's Initialize method), so make sure
505 // to reset it.
506 host_initializing_ = NULL;
507
508 // If this method fails, but no error set, then indicate a general
509 // initialization failure.
510 if (!success) {
511 Error(PIPELINE_ERROR_INITIALIZATION_FAILED);
512 } 544 }
513 return success; 545 return filter;
514 } 546 }
515 547
516 bool PipelineThread::CreateDataSource(FilterFactory* filter_factory, 548 scoped_refptr<DataSource> PipelineThread::CreateDataSource(
517 const std::string& url) { 549 FilterFactory* filter_factory, const std::string& url) {
518 MediaFormat url_format; 550 MediaFormat url_format;
519 url_format.SetAsString(MediaFormat::kMimeType, mime_type::kURL); 551 url_format.SetAsString(MediaFormat::kMimeType, mime_type::kURL);
520 url_format.SetAsString(MediaFormat::kURL, url); 552 url_format.SetAsString(MediaFormat::kURL, url);
521 return CreateFilter<DataSource>(filter_factory, url, &url_format); 553 return CreateFilter<DataSource>(filter_factory, url, &url_format);
522 } 554 }
523 555
524 template <class Decoder>
525 bool PipelineThread::CreateDecoder(FilterFactory* filter_factory) {
526 Demuxer* demuxer = GetFilter<Demuxer>();
527 if (demuxer) {
528 int num_outputs = demuxer->GetNumberOfStreams();
529 for (int i = 0; i < num_outputs; ++i) {
530 DemuxerStream* stream = demuxer->GetStream(i);
531 const MediaFormat* stream_format = stream->GetMediaFormat();
532 if (IsMajorMimeType(stream_format, Decoder::major_mime_type())) {
533 return CreateFilter<Decoder>(filter_factory, stream, stream_format);
534 }
535 }
536 }
537 return false;
538 }
539
540 template <class NewFilter, class SourceFilter>
541 bool PipelineThread::CreateAndConnect(FilterFactory* filter_factory) {
542 SourceFilter* source_filter = GetFilter<SourceFilter>();
543 bool success = (source_filter &&
544 CreateFilter<NewFilter>(filter_factory,
545 source_filter,
546 source_filter->GetMediaFormat()));
547 return success;
548 }
549
550 // TODO(ralphl): Consider making this part of the demuxer interface.
551 bool PipelineThread::HasVideo() const {
552 Demuxer* demuxer = GetFilter<Demuxer>();
553 if (demuxer) {
554 int num_outputs = demuxer->GetNumberOfStreams();
555 for (int i = 0; i < num_outputs; ++i) {
556 if (IsMajorMimeType(demuxer->GetStream(i)->GetMediaFormat(),
557 mime_type::kMajorTypeVideo)) {
558 return true;
559 }
560 }
561 }
562 return false;
563 }
564
565 bool PipelineThread::IsMajorMimeType(const MediaFormat* media_format,
566 const std::string& major_mime_type) const {
567 std::string value;
568 if (media_format->GetAsString(MediaFormat::kMimeType, &value)) {
569 return (0 == value.compare(0, major_mime_type.length(), major_mime_type));
570 }
571 return false;
572 }
573
574 // Called as a result of destruction of the thread. 556 // Called as a result of destruction of the thread.
575 void PipelineThread::WillDestroyCurrentMessageLoop() { 557 void PipelineThread::WillDestroyCurrentMessageLoop() {
576 while (!filter_hosts_.empty()) { 558 while (!filter_hosts_.empty()) {
577 delete filter_hosts_.back(); 559 delete filter_hosts_.back();
578 filter_hosts_.pop_back(); 560 filter_hosts_.pop_back();
579 } 561 }
580 } 562 }
581 563
582 } // namespace media 564 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698