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

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: acolwell's suggestions 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 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 return; 355 return;
356 closures->push_back(base::Bind(read_cbs_.front(), buffer)); 356 closures->push_back(base::Bind(read_cbs_.front(), buffer));
357 read_cbs_.pop_front(); 357 read_cbs_.pop_front();
358 } 358 }
359 } 359 }
360 360
361 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) 361 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
362 : state_(WAITING_FOR_INIT), 362 : state_(WAITING_FOR_INIT),
363 host_(NULL), 363 host_(NULL),
364 client_(client), 364 client_(client),
365 buffered_bytes_(0), 365 buffered_bytes_(0) {
366 has_audio_(false),
367 has_video_(false) {
368 DCHECK(client); 366 DCHECK(client);
369 } 367 }
370 368
371 void ChunkDemuxer::Initialize(DemuxerHost* host, 369 void ChunkDemuxer::Initialize(DemuxerHost* host,
372 const PipelineStatusCB& cb) { 370 const PipelineStatusCB& cb) {
373 DVLOG(1) << "Init()"; 371 DVLOG(1) << "Init()";
374 { 372 {
375 base::AutoLock auto_lock(lock_); 373 base::AutoLock auto_lock(lock_);
376 DCHECK_EQ(state_, WAITING_FOR_INIT); 374 DCHECK_EQ(state_, WAITING_FOR_INIT);
377 host_ = host; 375 host_ = host;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 if (video_) 456 if (video_)
459 video_->StartWaitingForSeek(); 457 video_->StartWaitingForSeek();
460 458
461 ChangeState_Locked(INITIALIZED); 459 ChangeState_Locked(INITIALIZED);
462 } 460 }
463 461
464 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, 462 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
465 const std::string& type, 463 const std::string& type,
466 std::vector<std::string>& codecs) { 464 std::vector<std::string>& codecs) {
467 DCHECK_GT(codecs.size(), 0u); 465 DCHECK_GT(codecs.size(), 0u);
466 base::AutoLock auto_lock(lock_);
467
468 if (state_ != WAITING_FOR_INIT && state_ != INITIALIZING)
469 return kReachedIdLimit;
468 470
469 bool has_audio = false; 471 bool has_audio = false;
470 bool has_video = false; 472 bool has_video = false;
471 ParserFactoryFunction factory_function = NULL; 473 ParserFactoryFunction factory_function = NULL;
472 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video)) 474 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video))
473 return kNotSupported; 475 return kNotSupported;
474 476
475 // TODO(acolwell): Support for more than one ID 477 if ((has_audio && !source_id_audio_.empty()) ||
476 // will be added as part of http://crbug.com/122909 478 (has_video && !source_id_video_.empty()))
477 if (!source_id_.empty() ||
478 (has_audio && has_audio_) ||
479 (has_video && has_video_))
480 return kReachedIdLimit; 479 return kReachedIdLimit;
481 480
482 source_id_ = id;
483
484 StreamParser::NewBuffersCB audio_cb; 481 StreamParser::NewBuffersCB audio_cb;
485 StreamParser::NewBuffersCB video_cb; 482 StreamParser::NewBuffersCB video_cb;
486 483
487 if (has_audio) { 484 if (has_audio) {
488 has_audio_ = true; 485 source_id_audio_ = id;
489 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, 486 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers,
490 base::Unretained(this)); 487 base::Unretained(this));
491 } 488 }
492 489
493 if (has_video) { 490 if (has_video) {
494 has_video_ = true; 491 source_id_video_ = id;
495 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, 492 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers,
496 base::Unretained(this)); 493 base::Unretained(this));
497 } 494 }
498 495
499 stream_parser_.reset(factory_function()); 496 scoped_ptr<StreamParser> stream_parser(factory_function());
500 CHECK(stream_parser_.get()); 497 CHECK(stream_parser.get());
501 498
502 stream_parser_->Init( 499 stream_parser->Init(
503 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), 500 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this),
504 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this)), 501 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this),
502 has_audio, has_video),
505 audio_cb, 503 audio_cb,
506 video_cb, 504 video_cb,
507 base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this))); 505 base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this)));
508 506
507 stream_parser_map_[id] = stream_parser.release();
508
509 return kOk; 509 return kOk;
510 } 510 }
511 511
512 void ChunkDemuxer::RemoveId(const std::string& id) { 512 void ChunkDemuxer::RemoveId(const std::string& id) {
513 CHECK(!source_id_.empty()); 513 CHECK_GT(stream_parser_map_.count(id), 0u);
514 CHECK_EQ(source_id_, id); 514 base::AutoLock auto_lock(lock_);
515 source_id_ = ""; 515
516 has_audio_ = false; 516 delete stream_parser_map_[id];
517 has_video_ = false; 517 stream_parser_map_.erase(id);
518
519 if (source_id_audio_ == id && audio_)
520 audio_->Shutdown();
521
522 if (source_id_video_ == id && video_)
523 video_->Shutdown();
518 } 524 }
519 525
520 bool ChunkDemuxer::GetBufferedRanges(const std::string& id, 526 bool ChunkDemuxer::GetBufferedRanges(const std::string& id,
521 Ranges* ranges_out) const { 527 Ranges* ranges_out) const {
522 DCHECK(!id.empty()); 528 DCHECK(!id.empty());
523 DCHECK_EQ(source_id_, id); 529 DCHECK_GT(stream_parser_map_.count(id), 0u);
524 DCHECK(ranges_out); 530 DCHECK(ranges_out);
525 531
526 base::AutoLock auto_lock(lock_); 532 base::AutoLock auto_lock(lock_);
527 533
528 // TODO(annacc): Calculate buffered ranges (http://crbug.com/129852 ). 534 // TODO(annacc): Calculate buffered ranges (http://crbug.com/129852 ).
529 return false; 535 return false;
530 } 536 }
531 537
532 bool ChunkDemuxer::AppendData(const std::string& id, 538 bool ChunkDemuxer::AppendData(const std::string& id,
533 const uint8* data, 539 const uint8* data,
534 size_t length) { 540 size_t length) {
535 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; 541 DVLOG(1) << "AppendData(" << id << ", " << length << ")";
536 542
537 // TODO(acolwell): Remove when http://webk.it/83788 fix lands. 543 // TODO(acolwell): Remove when http://webk.it/83788 fix lands.
538 if (source_id_.empty()) { 544 if (stream_parser_map_.count(id) == 0) {
539 std::vector<std::string> codecs(2); 545 std::vector<std::string> codecs(2);
540 codecs[0] = "vp8"; 546 codecs[0] = "vp8";
541 codecs[1] = "vorbis"; 547 codecs[1] = "vorbis";
542 AddId(id, "video/webm", codecs); 548 AddId(id, "video/webm", codecs);
543 } 549 }
544 550
545 DCHECK(!source_id_.empty()); 551 DCHECK_GT(stream_parser_map_.count(id), 0u);
546 DCHECK_EQ(source_id_, id);
547 DCHECK(!id.empty()); 552 DCHECK(!id.empty());
548 DCHECK(data); 553 DCHECK(data);
549 DCHECK_GT(length, 0u); 554 DCHECK_GT(length, 0u);
550 555
551 int64 buffered_bytes = 0; 556 int64 buffered_bytes = 0;
552 557
553 PipelineStatusCB cb; 558 PipelineStatusCB cb;
554 { 559 {
555 base::AutoLock auto_lock(lock_); 560 base::AutoLock auto_lock(lock_);
556 561
557 // Capture if the SourceBuffer has a pending seek before we start parsing. 562 // Capture if the SourceBuffer has a pending seek before we start parsing.
558 bool old_seek_pending = IsSeekPending_Locked(); 563 bool old_seek_pending = IsSeekPending_Locked();
559 564
560 switch (state_) { 565 switch (state_) {
561 case INITIALIZING: 566 case INITIALIZING:
562 if (!stream_parser_->Parse(data, length)) { 567 if (!stream_parser_map_[id]->Parse(data, length)) {
563 DCHECK_EQ(state_, INITIALIZING); 568 DCHECK_EQ(state_, INITIALIZING);
564 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 569 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
565 return true; 570 return true;
566 } 571 }
567 break; 572 break;
568 573
569 case INITIALIZED: { 574 case INITIALIZED: {
570 if (!stream_parser_->Parse(data, length)) { 575 if (!stream_parser_map_[id]->Parse(data, length)) {
571 ReportError_Locked(PIPELINE_ERROR_DECODE); 576 ReportError_Locked(PIPELINE_ERROR_DECODE);
572 return true; 577 return true;
573 } 578 }
574 } break; 579 } break;
575 580
576 case WAITING_FOR_INIT: 581 case WAITING_FOR_INIT:
577 case ENDED: 582 case ENDED:
578 case PARSE_ERROR: 583 case PARSE_ERROR:
579 case SHUTDOWN: 584 case SHUTDOWN:
580 DVLOG(1) << "AppendData(): called in unexpected state " << state_; 585 DVLOG(1) << "AppendData(): called in unexpected state " << state_;
(...skipping 18 matching lines...) Expand all
599 604
600 if (!cb.is_null()) 605 if (!cb.is_null())
601 cb.Run(PIPELINE_OK); 606 cb.Run(PIPELINE_OK);
602 607
603 return true; 608 return true;
604 } 609 }
605 610
606 void ChunkDemuxer::Abort(const std::string& id) { 611 void ChunkDemuxer::Abort(const std::string& id) {
607 DVLOG(1) << "Abort(" << id << ")"; 612 DVLOG(1) << "Abort(" << id << ")";
608 DCHECK(!id.empty()); 613 DCHECK(!id.empty());
609 DCHECK_EQ(source_id_, id); 614 DCHECK_GT(stream_parser_map_.count(id), 0u);
610 615
611 stream_parser_->Flush(); 616 stream_parser_map_[id]->Flush();
612 } 617 }
613 618
614 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { 619 bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
615 DVLOG(1) << "EndOfStream(" << status << ")"; 620 DVLOG(1) << "EndOfStream(" << status << ")";
616 base::AutoLock auto_lock(lock_); 621 base::AutoLock auto_lock(lock_);
617 DCHECK_NE(state_, WAITING_FOR_INIT); 622 DCHECK_NE(state_, WAITING_FOR_INIT);
618 DCHECK_NE(state_, ENDED); 623 DCHECK_NE(state_, ENDED);
619 624
620 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 625 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
621 return true; 626 return true;
(...skipping 30 matching lines...) Expand all
652 return; 657 return;
653 658
654 std::swap(cb, seek_cb_); 659 std::swap(cb, seek_cb_);
655 660
656 if (audio_) 661 if (audio_)
657 audio_->Shutdown(); 662 audio_->Shutdown();
658 663
659 if (video_) 664 if (video_)
660 video_->Shutdown(); 665 video_->Shutdown();
661 666
662 stream_parser_.reset(); 667 for (StreamParserMap::iterator it = stream_parser_map_.begin();
668 it != stream_parser_map_.end(); ++it)
669 delete it->second;
acolwell GONE FROM CHROMIUM 2012/06/11 16:09:33 nit: Add {} since this spans multiple lines.
annacc 2012/06/11 19:23:08 Done.
670 stream_parser_map_.clear();
663 671
664 ChangeState_Locked(SHUTDOWN); 672 ChangeState_Locked(SHUTDOWN);
665 } 673 }
666 674
667 if (!cb.is_null()) 675 if (!cb.is_null())
668 cb.Run(PIPELINE_ERROR_ABORT); 676 cb.Run(PIPELINE_ERROR_ABORT);
669 677
670 client_->DemuxerClosed(); 678 client_->DemuxerClosed();
671 } 679 }
672 680
673 void ChunkDemuxer::ChangeState_Locked(State new_state) { 681 void ChunkDemuxer::ChangeState_Locked(State new_state) {
674 lock_.AssertAcquired(); 682 lock_.AssertAcquired();
675 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " 683 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
676 << state_ << " -> " << new_state; 684 << state_ << " -> " << new_state;
677 state_ = new_state; 685 state_ = new_state;
678 } 686 }
679 687
680 ChunkDemuxer::~ChunkDemuxer() { 688 ChunkDemuxer::~ChunkDemuxer() {
681 DCHECK_NE(state_, INITIALIZED); 689 DCHECK_NE(state_, INITIALIZED);
690 for (StreamParserMap::iterator it = stream_parser_map_.begin();
691 it != stream_parser_map_.end(); ++it)
692 delete it->second;
acolwell GONE FROM CHROMIUM 2012/06/11 16:09:33 nit: Add {} since this spans multiple lines.
annacc 2012/06/11 19:23:08 Done.
693 stream_parser_map_.clear();
682 } 694 }
683 695
684 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { 696 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
685 DVLOG(1) << "ReportError_Locked(" << error << ")"; 697 DVLOG(1) << "ReportError_Locked(" << error << ")";
686 lock_.AssertAcquired(); 698 lock_.AssertAcquired();
687 DCHECK_NE(error, PIPELINE_OK); 699 DCHECK_NE(error, PIPELINE_OK);
688 700
689 ChangeState_Locked(PARSE_ERROR); 701 ChangeState_Locked(PARSE_ERROR);
690 702
691 PipelineStatusCB cb; 703 PipelineStatusCB cb;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 base::TimeDelta duration) { 748 base::TimeDelta duration) {
737 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", " 749 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", "
738 << duration.InSecondsF() << ")"; 750 << duration.InSecondsF() << ")";
739 lock_.AssertAcquired(); 751 lock_.AssertAcquired();
740 DCHECK_EQ(state_, INITIALIZING); 752 DCHECK_EQ(state_, INITIALIZING);
741 if (!success || (!audio_ && !video_)) { 753 if (!success || (!audio_ && !video_)) {
742 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 754 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
743 return; 755 return;
744 } 756 }
745 757
746 duration_ = duration; 758 if (duration > duration_)
759 duration_ = duration;
760
761 // Wait until all streams have initialized.
762 if ((!source_id_audio_.empty() && !audio_) ||
763 (!source_id_video_.empty() && !video_))
764 return;
765
747 host_->SetDuration(duration_); 766 host_->SetDuration(duration_);
748 767
749 ChangeState_Locked(INITIALIZED); 768 ChangeState_Locked(INITIALIZED);
750 PipelineStatusCB cb; 769 PipelineStatusCB cb;
751 std::swap(cb, init_cb_); 770 std::swap(cb, init_cb_);
752 cb.Run(PIPELINE_OK); 771 cb.Run(PIPELINE_OK);
753 } 772 }
754 773
755 bool ChunkDemuxer::OnNewConfigs(const AudioDecoderConfig& audio_config, 774 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video,
775 const AudioDecoderConfig& audio_config,
756 const VideoDecoderConfig& video_config) { 776 const VideoDecoderConfig& video_config) {
757 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig()); 777 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig());
758 lock_.AssertAcquired(); 778 lock_.AssertAcquired();
759 779
760 // Signal an error if we get configuration info for stream types that weren't 780 // Signal an error if we get configuration info for stream types that weren't
761 // specified in AddId() or more configs after a stream is initialized. 781 // specified in AddId() or more configs after a stream is initialized.
762 // Only allow a single audio config for now. 782 // Only allow a single audio config for now.
763 if (audio_config.IsValidConfig() && (!has_audio_ || audio_)) 783 if (audio_config.IsValidConfig() && (!has_audio || audio_))
764 return false; 784 return false;
765 785
766 // Only allow a single video config for now. 786 // Only allow a single video config for now.
767 if (video_config.IsValidConfig() && (!has_video_ || video_)) 787 if (video_config.IsValidConfig() && (!has_video || video_))
768 return false; 788 return false;
769 789
770 if (audio_config.IsValidConfig()) 790 if (audio_config.IsValidConfig())
771 audio_ = new ChunkDemuxerStream(audio_config); 791 audio_ = new ChunkDemuxerStream(audio_config);
772 792
773 if (video_config.IsValidConfig()) 793 if (video_config.IsValidConfig())
774 video_ = new ChunkDemuxerStream(video_config); 794 video_ = new ChunkDemuxerStream(video_config);
775 795
776 return true; 796 return true;
777 } 797 }
(...skipping 22 matching lines...) Expand all
800 return true; 820 return true;
801 } 821 }
802 822
803 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data, 823 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data,
804 int init_data_size) { 824 int init_data_size) {
805 client_->KeyNeeded(init_data.Pass(), init_data_size); 825 client_->KeyNeeded(init_data.Pass(), init_data_size);
806 return true; 826 return true;
807 } 827 }
808 828
809 } // namespace media 829 } // 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