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

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 10545066: Implement support for 2 source ids (1 for audio and 1 for video). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 6 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
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_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/filters/chunk_demuxer.h" 5 #include "media/filters/chunk_demuxer.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "media/base/audio_decoder_config.h" 10 #include "media/base/audio_decoder_config.h"
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 return; 408 return;
409 closures->push_back(base::Bind(read_cbs_.front(), buffer)); 409 closures->push_back(base::Bind(read_cbs_.front(), buffer));
410 read_cbs_.pop_front(); 410 read_cbs_.pop_front();
411 } 411 }
412 } 412 }
413 413
414 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) 414 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
415 : state_(WAITING_FOR_INIT), 415 : state_(WAITING_FOR_INIT),
416 host_(NULL), 416 host_(NULL),
417 client_(client), 417 client_(client),
418 buffered_bytes_(0), 418 buffered_bytes_(0) {
419 has_audio_(false),
420 has_video_(false) {
421 DCHECK(client); 419 DCHECK(client);
422 } 420 }
423 421
424 void ChunkDemuxer::Initialize(DemuxerHost* host, 422 void ChunkDemuxer::Initialize(DemuxerHost* host,
425 const PipelineStatusCB& cb) { 423 const PipelineStatusCB& cb) {
426 DVLOG(1) << "Init()"; 424 DVLOG(1) << "Init()";
427 { 425 {
428 base::AutoLock auto_lock(lock_); 426 base::AutoLock auto_lock(lock_);
429 DCHECK_EQ(state_, WAITING_FOR_INIT); 427 DCHECK_EQ(state_, WAITING_FOR_INIT);
430 host_ = host; 428 host_ = host;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 if (video_) 509 if (video_)
512 video_->StartWaitingForSeek(); 510 video_->StartWaitingForSeek();
513 511
514 ChangeState_Locked(INITIALIZED); 512 ChangeState_Locked(INITIALIZED);
515 } 513 }
516 514
517 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, 515 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
518 const std::string& type, 516 const std::string& type,
519 std::vector<std::string>& codecs) { 517 std::vector<std::string>& codecs) {
520 DCHECK_GT(codecs.size(), 0u); 518 DCHECK_GT(codecs.size(), 0u);
519 base::AutoLock auto_lock(lock_);
520
521 if (state_ != WAITING_FOR_INIT && state_ != INITIALIZING)
522 return kReachedIdLimit;
521 523
522 bool has_audio = false; 524 bool has_audio = false;
523 bool has_video = false; 525 bool has_video = false;
524 ParserFactoryFunction factory_function = NULL; 526 ParserFactoryFunction factory_function = NULL;
525 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video)) 527 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video))
526 return kNotSupported; 528 return kNotSupported;
527 529
528 // TODO(acolwell): Support for more than one ID 530 if ((has_audio && !source_id_audio_.empty()) ||
529 // will be added as part of http://crbug.com/122909 531 (has_video && !source_id_video_.empty()))
530 if (!source_id_.empty() ||
531 (has_audio && has_audio_) ||
532 (has_video && has_video_))
533 return kReachedIdLimit; 532 return kReachedIdLimit;
534 533
535 source_id_ = id;
536
537 StreamParser::NewBuffersCB audio_cb; 534 StreamParser::NewBuffersCB audio_cb;
538 StreamParser::NewBuffersCB video_cb; 535 StreamParser::NewBuffersCB video_cb;
539 536
540 if (has_audio) { 537 if (has_audio) {
541 has_audio_ = true; 538 source_id_audio_ = id;
542 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, 539 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers,
543 base::Unretained(this)); 540 base::Unretained(this));
544 } 541 }
545 542
546 if (has_video) { 543 if (has_video) {
547 has_video_ = true; 544 source_id_video_ = id;
548 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, 545 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers,
549 base::Unretained(this)); 546 base::Unretained(this));
550 } 547 }
551 548
552 stream_parser_.reset(factory_function()); 549 scoped_ptr<StreamParser> stream_parser(factory_function());
553 CHECK(stream_parser_.get()); 550 CHECK(stream_parser.get());
554 551
555 stream_parser_->Init( 552 stream_parser->Init(
556 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), 553 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this),
557 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this)), 554 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this),
555 has_audio, has_video),
558 audio_cb, 556 audio_cb,
559 video_cb, 557 video_cb,
560 base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this))); 558 base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this)));
561 559
560 stream_parser_map_[id] = stream_parser.release();
561
562 return kOk; 562 return kOk;
563 } 563 }
564 564
565 void ChunkDemuxer::RemoveId(const std::string& id) { 565 void ChunkDemuxer::RemoveId(const std::string& id) {
566 CHECK(!source_id_.empty()); 566 CHECK_GT(stream_parser_map_.count(id), 0u);
567 CHECK_EQ(source_id_, id); 567 base::AutoLock auto_lock(lock_);
568 source_id_ = ""; 568
569 has_audio_ = false; 569 delete stream_parser_map_[id];
570 has_video_ = false; 570 stream_parser_map_.erase(id);
571
572 if (source_id_audio_ == id && audio_)
573 audio_->Shutdown();
574
575 if (source_id_video_ == id && video_)
576 video_->Shutdown();
571 } 577 }
572 578
573 bool ChunkDemuxer::GetBufferedRanges(const std::string& id, 579 bool ChunkDemuxer::GetBufferedRanges(const std::string& id,
574 Ranges* ranges_out) const { 580 Ranges* ranges_out) const {
575 DCHECK(!id.empty()); 581 DCHECK(!id.empty());
576 DCHECK_EQ(source_id_, id); 582 DCHECK_GT(stream_parser_map_.count(id), 0u);
577 DCHECK(ranges_out); 583 DCHECK(ranges_out);
578 584
579 base::AutoLock auto_lock(lock_); 585 base::AutoLock auto_lock(lock_);
580 586
581 // TODO(annacc): Calculate buffered ranges (http://crbug.com/129852 ). 587 // TODO(annacc): Calculate buffered ranges (http://crbug.com/129852 ).
582 return false; 588 return false;
583 } 589 }
584 590
585 bool ChunkDemuxer::AppendData(const std::string& id, 591 bool ChunkDemuxer::AppendData(const std::string& id,
586 const uint8* data, 592 const uint8* data,
587 size_t length) { 593 size_t length) {
588 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; 594 DVLOG(1) << "AppendData(" << id << ", " << length << ")";
589 595
590 // TODO(acolwell): Remove when http://webk.it/83788 fix lands.
591 if (source_id_.empty()) {
592 std::vector<std::string> codecs(2);
593 codecs[0] = "vp8";
594 codecs[1] = "vorbis";
595 AddId(id, "video/webm", codecs);
596 }
597
598 DCHECK(!source_id_.empty());
599 DCHECK_EQ(source_id_, id);
600 DCHECK(!id.empty()); 596 DCHECK(!id.empty());
601 DCHECK(data); 597 DCHECK(data);
602 DCHECK_GT(length, 0u); 598 DCHECK_GT(length, 0u);
603 599
604 int64 buffered_bytes = 0; 600 int64 buffered_bytes = 0;
605 601
606 PipelineStatusCB cb; 602 PipelineStatusCB cb;
607 { 603 {
608 base::AutoLock auto_lock(lock_); 604 base::AutoLock auto_lock(lock_);
609 605
610 // Capture if the SourceBuffer has a pending seek before we start parsing. 606 // Capture if the SourceBuffer has a pending seek before we start parsing.
611 bool old_seek_pending = IsSeekPending_Locked(); 607 bool old_seek_pending = IsSeekPending_Locked();
612 608
613 switch (state_) { 609 switch (state_) {
614 case INITIALIZING: 610 case INITIALIZING:
615 if (!stream_parser_->Parse(data, length)) { 611 DCHECK_GT(stream_parser_map_.count(id), 0u);
612 if (!stream_parser_map_[id]->Parse(data, length)) {
616 DCHECK_EQ(state_, INITIALIZING); 613 DCHECK_EQ(state_, INITIALIZING);
617 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 614 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
618 return true; 615 return true;
619 } 616 }
620 break; 617 break;
621 618
622 case INITIALIZED: { 619 case INITIALIZED: {
623 if (!stream_parser_->Parse(data, length)) { 620 DCHECK_GT(stream_parser_map_.count(id), 0u);
621 if (!stream_parser_map_[id]->Parse(data, length)) {
624 ReportError_Locked(PIPELINE_ERROR_DECODE); 622 ReportError_Locked(PIPELINE_ERROR_DECODE);
625 return true; 623 return true;
626 } 624 }
627 } break; 625 } break;
628 626
629 case WAITING_FOR_INIT: 627 case WAITING_FOR_INIT:
630 case ENDED: 628 case ENDED:
631 case PARSE_ERROR: 629 case PARSE_ERROR:
632 case SHUTDOWN: 630 case SHUTDOWN:
633 DVLOG(1) << "AppendData(): called in unexpected state " << state_; 631 DVLOG(1) << "AppendData(): called in unexpected state " << state_;
(...skipping 16 matching lines...) Expand all
650 648
651 if (!cb.is_null()) 649 if (!cb.is_null())
652 cb.Run(PIPELINE_OK); 650 cb.Run(PIPELINE_OK);
653 651
654 return true; 652 return true;
655 } 653 }
656 654
657 void ChunkDemuxer::Abort(const std::string& id) { 655 void ChunkDemuxer::Abort(const std::string& id) {
658 DVLOG(1) << "Abort(" << id << ")"; 656 DVLOG(1) << "Abort(" << id << ")";
659 DCHECK(!id.empty()); 657 DCHECK(!id.empty());
660 DCHECK_EQ(source_id_, id); 658 DCHECK_GT(stream_parser_map_.count(id), 0u);
661 659
662 stream_parser_->Flush(); 660 stream_parser_map_[id]->Flush();
663 } 661 }
664 662
665 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { 663 bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
666 DVLOG(1) << "EndOfStream(" << status << ")"; 664 DVLOG(1) << "EndOfStream(" << status << ")";
667 base::AutoLock auto_lock(lock_); 665 base::AutoLock auto_lock(lock_);
668 DCHECK_NE(state_, WAITING_FOR_INIT); 666 DCHECK_NE(state_, WAITING_FOR_INIT);
669 DCHECK_NE(state_, ENDED); 667 DCHECK_NE(state_, ENDED);
670 668
671 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 669 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
672 return true; 670 return true;
(...skipping 30 matching lines...) Expand all
703 return; 701 return;
704 702
705 std::swap(cb, seek_cb_); 703 std::swap(cb, seek_cb_);
706 704
707 if (audio_) 705 if (audio_)
708 audio_->Shutdown(); 706 audio_->Shutdown();
709 707
710 if (video_) 708 if (video_)
711 video_->Shutdown(); 709 video_->Shutdown();
712 710
713 stream_parser_.reset(); 711 for (StreamParserMap::iterator it = stream_parser_map_.begin();
712 it != stream_parser_map_.end(); ++it) {
713 delete it->second;
714 }
715 stream_parser_map_.clear();
714 716
715 ChangeState_Locked(SHUTDOWN); 717 ChangeState_Locked(SHUTDOWN);
716 } 718 }
717 719
718 if (!cb.is_null()) 720 if (!cb.is_null())
719 cb.Run(PIPELINE_ERROR_ABORT); 721 cb.Run(PIPELINE_ERROR_ABORT);
720 722
721 client_->DemuxerClosed(); 723 client_->DemuxerClosed();
722 } 724 }
723 725
724 void ChunkDemuxer::ChangeState_Locked(State new_state) { 726 void ChunkDemuxer::ChangeState_Locked(State new_state) {
725 lock_.AssertAcquired(); 727 lock_.AssertAcquired();
726 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " 728 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
727 << state_ << " -> " << new_state; 729 << state_ << " -> " << new_state;
728 state_ = new_state; 730 state_ = new_state;
729 } 731 }
730 732
731 ChunkDemuxer::~ChunkDemuxer() { 733 ChunkDemuxer::~ChunkDemuxer() {
732 DCHECK_NE(state_, INITIALIZED); 734 DCHECK_NE(state_, INITIALIZED);
735 for (StreamParserMap::iterator it = stream_parser_map_.begin();
736 it != stream_parser_map_.end(); ++it) {
737 delete it->second;
738 }
739 stream_parser_map_.clear();
733 } 740 }
734 741
735 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { 742 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
736 DVLOG(1) << "ReportError_Locked(" << error << ")"; 743 DVLOG(1) << "ReportError_Locked(" << error << ")";
737 lock_.AssertAcquired(); 744 lock_.AssertAcquired();
738 DCHECK_NE(error, PIPELINE_OK); 745 DCHECK_NE(error, PIPELINE_OK);
739 746
740 ChangeState_Locked(PARSE_ERROR); 747 ChangeState_Locked(PARSE_ERROR);
741 748
742 PipelineStatusCB cb; 749 PipelineStatusCB cb;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 base::TimeDelta duration) { 794 base::TimeDelta duration) {
788 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", " 795 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", "
789 << duration.InSecondsF() << ")"; 796 << duration.InSecondsF() << ")";
790 lock_.AssertAcquired(); 797 lock_.AssertAcquired();
791 DCHECK_EQ(state_, INITIALIZING); 798 DCHECK_EQ(state_, INITIALIZING);
792 if (!success || (!audio_ && !video_)) { 799 if (!success || (!audio_ && !video_)) {
793 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 800 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
794 return; 801 return;
795 } 802 }
796 803
797 duration_ = duration; 804 if (duration > duration_)
805 duration_ = duration;
806
807 // Wait until all streams have initialized.
808 if ((!source_id_audio_.empty() && !audio_) ||
809 (!source_id_video_.empty() && !video_))
810 return;
811
798 host_->SetDuration(duration_); 812 host_->SetDuration(duration_);
799 813
800 ChangeState_Locked(INITIALIZED); 814 ChangeState_Locked(INITIALIZED);
801 PipelineStatusCB cb; 815 PipelineStatusCB cb;
802 std::swap(cb, init_cb_); 816 std::swap(cb, init_cb_);
803 cb.Run(PIPELINE_OK); 817 cb.Run(PIPELINE_OK);
804 } 818 }
805 819
806 bool ChunkDemuxer::OnNewConfigs(const AudioDecoderConfig& audio_config, 820 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video,
821 const AudioDecoderConfig& audio_config,
807 const VideoDecoderConfig& video_config) { 822 const VideoDecoderConfig& video_config) {
808 DVLOG(1) << "OnNewConfigs(" << audio_config.IsValidConfig() 823 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video
824 << ", " << audio_config.IsValidConfig()
809 << ", " << video_config.IsValidConfig() << ")"; 825 << ", " << video_config.IsValidConfig() << ")";
810 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig()); 826 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig());
811 lock_.AssertAcquired(); 827 lock_.AssertAcquired();
812 828
813 // Signal an error if we get configuration info for stream types that weren't 829 // Signal an error if we get configuration info for stream types that weren't
814 // specified in AddId() or more configs after a stream is initialized. 830 // specified in AddId() or more configs after a stream is initialized.
815 // Only allow a single audio config for now. 831 // Only allow a single audio config for now.
816 if (audio_config.IsValidConfig() && !has_audio_) { 832 if (has_audio != audio_config.IsValidConfig()) {
817 DVLOG(1) << "OnNewConfigs() : Got unexpected audio config."; 833 DVLOG(1) << "OnNewConfigs() : Got unexpected audio config.";
818 return false; 834 return false;
819 } 835 }
820 836
821 // Only allow a single video config for now. 837 // Only allow a single video config for now.
822 if (video_config.IsValidConfig() && !has_video_) { 838 if (has_video != video_config.IsValidConfig()) {
823 DVLOG(1) << "OnNewConfigs() : Got unexpected video config."; 839 DVLOG(1) << "OnNewConfigs() : Got unexpected video config.";
824 return false; 840 return false;
825 } 841 }
826 842
827 bool success = true; 843 bool success = true;
828 if (audio_config.IsValidConfig()) { 844 if (audio_config.IsValidConfig()) {
829 if (audio_) { 845 if (audio_) {
830 success &= audio_->UpdateAudioConfig(audio_config); 846 success &= audio_->UpdateAudioConfig(audio_config);
831 } else { 847 } else {
832 audio_ = new ChunkDemuxerStream(audio_config); 848 audio_ = new ChunkDemuxerStream(audio_config);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 return true; 885 return true;
870 } 886 }
871 887
872 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data, 888 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data,
873 int init_data_size) { 889 int init_data_size) {
874 client_->KeyNeeded(init_data.Pass(), init_data_size); 890 client_->KeyNeeded(init_data.Pass(), init_data_size);
875 return true; 891 return true;
876 } 892 }
877 893
878 } // namespace media 894 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698