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

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

Issue 511323003: media: Remove FilterCollection. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 6 years, 3 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.h ('k') | media/base/pipeline_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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/pipeline.h" 5 #include "media/base/pipeline.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/command_line.h"
12 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
13 #include "base/location.h" 14 #include "base/location.h"
14 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
15 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h" 17 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
19 #include "base/synchronization/condition_variable.h" 20 #include "base/synchronization/condition_variable.h"
20 #include "media/base/filter_collection.h"
21 #include "media/base/media_log.h" 21 #include "media/base/media_log.h"
22 #include "media/base/media_switches.h"
22 #include "media/base/renderer.h" 23 #include "media/base/renderer.h"
23 #include "media/base/text_renderer.h" 24 #include "media/base/text_renderer.h"
24 #include "media/base/text_track_config.h" 25 #include "media/base/text_track_config.h"
25 #include "media/base/video_decoder_config.h" 26 #include "media/base/video_decoder_config.h"
26 27
27 using base::TimeDelta; 28 using base::TimeDelta;
28 29
29 namespace media { 30 namespace media {
30 31
31 Pipeline::Pipeline( 32 Pipeline::Pipeline(
(...skipping 21 matching lines...) Expand all
53 DCHECK(thread_checker_.CalledOnValidThread()) 54 DCHECK(thread_checker_.CalledOnValidThread())
54 << "Pipeline must be destroyed on same thread that created it"; 55 << "Pipeline must be destroyed on same thread that created it";
55 DCHECK(!running_) << "Stop() must complete before destroying object"; 56 DCHECK(!running_) << "Stop() must complete before destroying object";
56 DCHECK(stop_cb_.is_null()); 57 DCHECK(stop_cb_.is_null());
57 DCHECK(seek_cb_.is_null()); 58 DCHECK(seek_cb_.is_null());
58 59
59 media_log_->AddEvent( 60 media_log_->AddEvent(
60 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); 61 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED));
61 } 62 }
62 63
63 void Pipeline::Start(scoped_ptr<FilterCollection> collection, 64 void Pipeline::Start(Demuxer* demuxer,
65 scoped_ptr<Renderer> renderer,
64 const base::Closure& ended_cb, 66 const base::Closure& ended_cb,
65 const PipelineStatusCB& error_cb, 67 const PipelineStatusCB& error_cb,
66 const PipelineStatusCB& seek_cb, 68 const PipelineStatusCB& seek_cb,
67 const PipelineMetadataCB& metadata_cb, 69 const PipelineMetadataCB& metadata_cb,
68 const BufferingStateCB& buffering_state_cb, 70 const BufferingStateCB& buffering_state_cb,
69 const base::Closure& duration_change_cb) { 71 const base::Closure& duration_change_cb,
72 const AddTextTrackCB& add_text_track_cb) {
70 DCHECK(!ended_cb.is_null()); 73 DCHECK(!ended_cb.is_null());
71 DCHECK(!error_cb.is_null()); 74 DCHECK(!error_cb.is_null());
72 DCHECK(!seek_cb.is_null()); 75 DCHECK(!seek_cb.is_null());
73 DCHECK(!metadata_cb.is_null()); 76 DCHECK(!metadata_cb.is_null());
74 DCHECK(!buffering_state_cb.is_null()); 77 DCHECK(!buffering_state_cb.is_null());
75 78
76 base::AutoLock auto_lock(lock_); 79 base::AutoLock auto_lock(lock_);
77 CHECK(!running_) << "Media pipeline is already running"; 80 CHECK(!running_) << "Media pipeline is already running";
78 running_ = true; 81 running_ = true;
79 82
80 filter_collection_ = collection.Pass(); 83 demuxer_ = demuxer;
84 renderer_ = renderer.Pass();
81 ended_cb_ = ended_cb; 85 ended_cb_ = ended_cb;
82 error_cb_ = error_cb; 86 error_cb_ = error_cb;
83 seek_cb_ = seek_cb; 87 seek_cb_ = seek_cb;
84 metadata_cb_ = metadata_cb; 88 metadata_cb_ = metadata_cb;
85 buffering_state_cb_ = buffering_state_cb; 89 buffering_state_cb_ = buffering_state_cb;
86 duration_change_cb_ = duration_change_cb; 90 duration_change_cb_ = duration_change_cb;
91 add_text_track_cb_ = add_text_track_cb;
87 92
88 task_runner_->PostTask( 93 task_runner_->PostTask(
89 FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr())); 94 FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr()));
90 } 95 }
91 96
92 void Pipeline::Stop(const base::Closure& stop_cb) { 97 void Pipeline::Stop(const base::Closure& stop_cb) {
93 DVLOG(2) << __FUNCTION__; 98 DVLOG(2) << __FUNCTION__;
94 task_runner_->PostTask( 99 task_runner_->PostTask(
95 FROM_HERE, 100 FROM_HERE,
96 base::Bind(&Pipeline::StopTask, weak_factory_.GetWeakPtr(), stop_cb)); 101 base::Bind(&Pipeline::StopTask, weak_factory_.GetWeakPtr(), stop_cb));
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 DCHECK(stop_cb_.is_null()) 228 DCHECK(stop_cb_.is_null())
224 << "State transitions don't happen when stopping"; 229 << "State transitions don't happen when stopping";
225 DCHECK_EQ(status_, PIPELINE_OK) 230 DCHECK_EQ(status_, PIPELINE_OK)
226 << "State transitions don't happen when there's an error: " << status_; 231 << "State transitions don't happen when there's an error: " << status_;
227 232
228 switch (state_) { 233 switch (state_) {
229 case kCreated: 234 case kCreated:
230 return kInitDemuxer; 235 return kInitDemuxer;
231 236
232 case kInitDemuxer: 237 case kInitDemuxer:
233 if (demuxer_->GetStream(DemuxerStream::AUDIO) || 238 return kInitRenderer;
234 demuxer_->GetStream(DemuxerStream::VIDEO)) {
235 return kInitRenderer;
236 }
237 return kPlaying;
238 239
239 case kInitRenderer: 240 case kInitRenderer:
240 case kSeeking: 241 case kSeeking:
241 return kPlaying; 242 return kPlaying;
242 243
243 case kPlaying: 244 case kPlaying:
244 case kStopping: 245 case kStopping:
245 case kStopped: 246 case kStopped:
246 break; 247 break;
247 } 248 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 // Switch states, performing any entrance actions for the new state as well. 333 // Switch states, performing any entrance actions for the new state as well.
333 SetState(GetNextState()); 334 SetState(GetNextState());
334 switch (state_) { 335 switch (state_) {
335 case kInitDemuxer: 336 case kInitDemuxer:
336 return InitializeDemuxer(done_cb); 337 return InitializeDemuxer(done_cb);
337 338
338 case kInitRenderer: 339 case kInitRenderer:
339 return InitializeRenderer(done_cb); 340 return InitializeRenderer(done_cb);
340 341
341 case kPlaying: 342 case kPlaying:
342 // Finish initial start sequence the first time we enter the playing 343 // Report metadata the first time we enter the playing state.
343 // state.
344 if (!is_initialized_) { 344 if (!is_initialized_) {
345 if (!renderer_) {
346 ErrorChangedTask(PIPELINE_ERROR_COULD_NOT_RENDER);
347 return;
348 }
349
350 is_initialized_ = true; 345 is_initialized_ = true;
351 346 ReportMetadata();
352 {
353 PipelineMetadata metadata;
354 metadata.has_audio = renderer_->HasAudio();
355 metadata.has_video = renderer_->HasVideo();
356 metadata.timeline_offset = demuxer_->GetTimelineOffset();
357 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
358 if (stream) {
359 metadata.natural_size =
360 stream->video_decoder_config().natural_size();
361 metadata.video_rotation = stream->video_rotation();
362 }
363 metadata_cb_.Run(metadata);
364 }
365 } 347 }
366 348
367 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 349 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
368 350
369 renderer_->StartPlayingFrom(start_timestamp_); 351 renderer_->StartPlayingFrom(start_timestamp_);
370 352
371 if (text_renderer_) 353 if (text_renderer_)
372 text_renderer_->StartPlaying(); 354 text_renderer_->StartPlaying();
373 355
374 PlaybackRateChangedTask(GetPlaybackRate()); 356 PlaybackRateChangedTask(GetPlaybackRate());
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 DCHECK_EQ(state_, kStopping); 423 DCHECK_EQ(state_, kStopping);
442 DCHECK(!renderer_); 424 DCHECK(!renderer_);
443 DCHECK(!text_renderer_); 425 DCHECK(!text_renderer_);
444 426
445 { 427 {
446 base::AutoLock auto_lock(lock_); 428 base::AutoLock auto_lock(lock_);
447 running_ = false; 429 running_ = false;
448 } 430 }
449 431
450 SetState(kStopped); 432 SetState(kStopped);
451 filter_collection_.reset();
452 demuxer_ = NULL; 433 demuxer_ = NULL;
453 434
454 // If we stop during initialization/seeking we want to run |seek_cb_| 435 // If we stop during initialization/seeking we want to run |seek_cb_|
455 // followed by |stop_cb_| so we don't leave outstanding callbacks around. 436 // followed by |stop_cb_| so we don't leave outstanding callbacks around.
456 if (!seek_cb_.is_null()) { 437 if (!seek_cb_.is_null()) {
457 base::ResetAndReturn(&seek_cb_).Run(status_); 438 base::ResetAndReturn(&seek_cb_).Run(status_);
458 error_cb_.Reset(); 439 error_cb_.Reset();
459 } 440 }
460 if (!stop_cb_.is_null()) { 441 if (!stop_cb_.is_null()) {
461 error_cb_.Reset(); 442 error_cb_.Reset();
(...skipping 29 matching lines...) Expand all
491 statistics_.video_frames_decoded += stats.video_frames_decoded; 472 statistics_.video_frames_decoded += stats.video_frames_decoded;
492 statistics_.video_frames_dropped += stats.video_frames_dropped; 473 statistics_.video_frames_dropped += stats.video_frames_dropped;
493 } 474 }
494 475
495 void Pipeline::StartTask() { 476 void Pipeline::StartTask() {
496 DCHECK(task_runner_->BelongsToCurrentThread()); 477 DCHECK(task_runner_->BelongsToCurrentThread());
497 478
498 CHECK_EQ(kCreated, state_) 479 CHECK_EQ(kCreated, state_)
499 << "Media pipeline cannot be started more than once"; 480 << "Media pipeline cannot be started more than once";
500 481
501 text_renderer_ = filter_collection_->GetTextRenderer(); 482 text_renderer_ = CreateTextRenderer();
502
503 if (text_renderer_) { 483 if (text_renderer_) {
504 text_renderer_->Initialize( 484 text_renderer_->Initialize(
505 base::Bind(&Pipeline::OnTextRendererEnded, weak_factory_.GetWeakPtr())); 485 base::Bind(&Pipeline::OnTextRendererEnded, weak_factory_.GetWeakPtr()));
506 } 486 }
507 487
508 StateTransitionTask(PIPELINE_OK); 488 StateTransitionTask(PIPELINE_OK);
509 } 489 }
510 490
511 void Pipeline::StopTask(const base::Closure& stop_cb) { 491 void Pipeline::StopTask(const base::Closure& stop_cb) {
512 DCHECK(task_runner_->BelongsToCurrentThread()); 492 DCHECK(task_runner_->BelongsToCurrentThread());
(...skipping 10 matching lines...) Expand all
523 503
524 return; 504 return;
525 } 505 }
526 506
527 stop_cb_ = stop_cb; 507 stop_cb_ = stop_cb;
528 508
529 // We may already be stopping due to a runtime error. 509 // We may already be stopping due to a runtime error.
530 if (state_ == kStopping) 510 if (state_ == kStopping)
531 return; 511 return;
532 512
533 PipelineStatistics stats = GetStatistics(); 513 // Do not report statistics if the pipeline is not fully initialized.
534 if (renderer_ && renderer_->HasVideo() && stats.video_frames_decoded > 0) 514 if (state_ == kSeeking || state_ == kPlaying) {
535 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", stats.video_frames_dropped); 515 PipelineStatistics stats = GetStatistics();
516 if (renderer_->HasVideo() && stats.video_frames_decoded > 0) {
517 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount",
518 stats.video_frames_dropped);
519 }
520 }
536 521
537 SetState(kStopping); 522 SetState(kStopping);
538 pending_callbacks_.reset(); 523 pending_callbacks_.reset();
539 DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr())); 524 DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr()));
540 } 525 }
541 526
542 void Pipeline::ErrorChangedTask(PipelineStatus error) { 527 void Pipeline::ErrorChangedTask(PipelineStatus error) {
543 DCHECK(task_runner_->BelongsToCurrentThread()); 528 DCHECK(task_runner_->BelongsToCurrentThread());
544 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; 529 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
545 530
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 if (renderer_ && !renderer_ended_) 620 if (renderer_ && !renderer_ended_)
636 return; 621 return;
637 622
638 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) 623 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_)
639 return; 624 return;
640 625
641 DCHECK_EQ(status_, PIPELINE_OK); 626 DCHECK_EQ(status_, PIPELINE_OK);
642 ended_cb_.Run(); 627 ended_cb_.Run();
643 } 628 }
644 629
630 scoped_ptr<TextRenderer> Pipeline::CreateTextRenderer() {
631 DCHECK(task_runner_->BelongsToCurrentThread());
632
633 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
634 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks))
635 return scoped_ptr<media::TextRenderer>();
636
637 return scoped_ptr<media::TextRenderer>(new media::TextRenderer(
638 task_runner_,
639 base::Bind(&Pipeline::OnAddTextTrack, weak_factory_.GetWeakPtr())));
640 }
641
645 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, 642 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream,
646 const TextTrackConfig& config) { 643 const TextTrackConfig& config) {
647 DCHECK(task_runner_->BelongsToCurrentThread()); 644 DCHECK(task_runner_->BelongsToCurrentThread());
648 // TODO(matthewjheaney): fix up text_ended_ when text stream 645 // TODO(matthewjheaney): fix up text_ended_ when text stream
649 // is added (http://crbug.com/321446). 646 // is added (http://crbug.com/321446).
650 text_renderer_->AddTextStream(text_stream, config); 647 if (text_renderer_)
648 text_renderer_->AddTextStream(text_stream, config);
651 } 649 }
652 650
653 void Pipeline::RemoveTextStreamTask(DemuxerStream* text_stream) { 651 void Pipeline::RemoveTextStreamTask(DemuxerStream* text_stream) {
654 DCHECK(task_runner_->BelongsToCurrentThread()); 652 DCHECK(task_runner_->BelongsToCurrentThread());
655 text_renderer_->RemoveTextStream(text_stream); 653 if (text_renderer_)
654 text_renderer_->RemoveTextStream(text_stream);
655 }
656
657 void Pipeline::OnAddTextTrack(const TextTrackConfig& config,
658 const AddTextTrackDoneCB& done_cb) {
659 DCHECK(task_runner_->BelongsToCurrentThread());
660 add_text_track_cb_.Run(config, done_cb);
656 } 661 }
657 662
658 void Pipeline::InitializeDemuxer(const PipelineStatusCB& done_cb) { 663 void Pipeline::InitializeDemuxer(const PipelineStatusCB& done_cb) {
659 DCHECK(task_runner_->BelongsToCurrentThread()); 664 DCHECK(task_runner_->BelongsToCurrentThread());
660
661 demuxer_ = filter_collection_->GetDemuxer();
662 demuxer_->Initialize(this, done_cb, text_renderer_); 665 demuxer_->Initialize(this, done_cb, text_renderer_);
663 } 666 }
664 667
665 void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) { 668 void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) {
666 DCHECK(task_runner_->BelongsToCurrentThread()); 669 DCHECK(task_runner_->BelongsToCurrentThread());
667 670
668 renderer_ = filter_collection_->GetRenderer(); 671 if (!demuxer_->GetStream(DemuxerStream::AUDIO) &&
672 !demuxer_->GetStream(DemuxerStream::VIDEO)) {
673 renderer_.reset();
674 task_runner_->PostTask(
675 FROM_HERE, base::Bind(done_cb, PIPELINE_ERROR_COULD_NOT_RENDER));
676 return;
677 }
669 678
670 base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr(); 679 base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr();
671 renderer_->Initialize( 680 renderer_->Initialize(
672 done_cb, 681 done_cb,
673 base::Bind(&Pipeline::OnUpdateStatistics, weak_this), 682 base::Bind(&Pipeline::OnUpdateStatistics, weak_this),
674 base::Bind(&Pipeline::OnRendererEnded, weak_this), 683 base::Bind(&Pipeline::OnRendererEnded, weak_this),
675 base::Bind(&Pipeline::OnError, weak_this), 684 base::Bind(&Pipeline::OnError, weak_this),
676 base::Bind(&Pipeline::BufferingStateChanged, weak_this), 685 base::Bind(&Pipeline::BufferingStateChanged, weak_this),
677 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); 686 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this)));
678 } 687 }
679 688
689 void Pipeline::ReportMetadata() {
690 DCHECK(task_runner_->BelongsToCurrentThread());
691 PipelineMetadata metadata;
692 metadata.has_audio = renderer_->HasAudio();
693 metadata.has_video = renderer_->HasVideo();
694 metadata.timeline_offset = demuxer_->GetTimelineOffset();
695 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
696 if (stream) {
697 metadata.natural_size = stream->video_decoder_config().natural_size();
698 metadata.video_rotation = stream->video_rotation();
699 }
700 metadata_cb_.Run(metadata);
701 }
702
680 void Pipeline::BufferingStateChanged(BufferingState new_buffering_state) { 703 void Pipeline::BufferingStateChanged(BufferingState new_buffering_state) {
681 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; 704 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") ";
682 DCHECK(task_runner_->BelongsToCurrentThread()); 705 DCHECK(task_runner_->BelongsToCurrentThread());
683 buffering_state_cb_.Run(new_buffering_state); 706 buffering_state_cb_.Run(new_buffering_state);
684 } 707 }
685 708
686 } // namespace media 709 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline.h ('k') | media/base/pipeline_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698