| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |