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

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: 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
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 {
467 base::AutoLock auto_lock(lock_);
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 I think we should apply the lock to the whole meth
annacc 2012/06/08 22:12:23 Done.
468 if (state_ != WAITING_FOR_INIT && state_ != INITIALIZING)
469 return kReachedIdLimit;
470 }
468 471
469 bool has_audio = false; 472 bool has_audio = false;
470 bool has_video = false; 473 bool has_video = false;
471 ParserFactoryFunction factory_function = NULL; 474 ParserFactoryFunction factory_function = NULL;
472 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video)) 475 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video))
473 return kNotSupported; 476 return kNotSupported;
474 477
475 // TODO(acolwell): Support for more than one ID 478 if ((has_audio && !source_id_audio_.empty()) ||
476 // will be added as part of http://crbug.com/122909 479 (has_video && !source_id_video_.empty()))
477 if (!source_id_.empty() ||
478 (has_audio && has_audio_) ||
479 (has_video && has_video_))
480 return kReachedIdLimit; 480 return kReachedIdLimit;
481 481
482 source_id_ = id;
483
484 StreamParser::NewBuffersCB audio_cb; 482 StreamParser::NewBuffersCB audio_cb;
485 StreamParser::NewBuffersCB video_cb; 483 StreamParser::NewBuffersCB video_cb;
486 484
487 if (has_audio) { 485 if (has_audio) {
488 has_audio_ = true; 486 source_id_audio_ = id;
489 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, 487 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers,
490 base::Unretained(this)); 488 base::Unretained(this));
491 } 489 }
492 490
493 if (has_video) { 491 if (has_video) {
494 has_video_ = true; 492 source_id_video_ = id;
495 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, 493 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers,
496 base::Unretained(this)); 494 base::Unretained(this));
497 } 495 }
498 496
499 stream_parser_.reset(factory_function()); 497 scoped_ptr<StreamParser> stream_parser(factory_function());
500 CHECK(stream_parser_.get()); 498 CHECK(stream_parser.get());
501 499
502 stream_parser_->Init( 500 stream_parser->Init(
503 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), 501 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this),
504 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this)), 502 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this),
503 has_audio, has_video),
505 audio_cb, 504 audio_cb,
506 video_cb, 505 video_cb,
507 base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this))); 506 base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this)));
508 507
508 stream_parser_map_[id] = stream_parser.release();
509
509 return kOk; 510 return kOk;
510 } 511 }
511 512
512 void ChunkDemuxer::RemoveId(const std::string& id) { 513 void ChunkDemuxer::RemoveId(const std::string& id) {
513 CHECK(!source_id_.empty()); 514 CHECK_GT(stream_parser_map_.count(id), 0u);
514 CHECK_EQ(source_id_, id); 515 stream_parser_map_.erase(id);
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 I think this leaks the parser.
annacc 2012/06/08 22:12:23 Good catch, thanks!
515 source_id_ = ""; 516
516 has_audio_ = false; 517 if (source_id_audio_ == id && audio_)
517 has_video_ = false; 518 audio_->Shutdown();
519
520 if (source_id_video_ == id && video_)
521 video_->Shutdown();
518 } 522 }
519 523
520 bool ChunkDemuxer::GetBufferedRanges(const std::string& id, 524 bool ChunkDemuxer::GetBufferedRanges(const std::string& id,
521 Ranges* ranges_out) const { 525 Ranges* ranges_out) const {
522 DCHECK(!id.empty()); 526 DCHECK(!id.empty());
523 DCHECK_EQ(source_id_, id); 527 DCHECK_GT(stream_parser_map_.count(id), 0u);
524 DCHECK(ranges_out); 528 DCHECK(ranges_out);
525 529
526 base::AutoLock auto_lock(lock_); 530 base::AutoLock auto_lock(lock_);
527 531
528 // TODO(annacc): Calculate buffered ranges (http://crbug.com/129852 ). 532 // TODO(annacc): Calculate buffered ranges (http://crbug.com/129852 ).
529 return false; 533 return false;
530 } 534 }
531 535
532 bool ChunkDemuxer::AppendData(const std::string& id, 536 bool ChunkDemuxer::AppendData(const std::string& id,
533 const uint8* data, 537 const uint8* data,
534 size_t length) { 538 size_t length) {
535 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; 539 DVLOG(1) << "AppendData(" << id << ", " << length << ")";
536 540
537 // TODO(acolwell): Remove when http://webk.it/83788 fix lands. 541 // TODO(acolwell): Remove when http://webk.it/83788 fix lands.
538 if (source_id_.empty()) { 542 if (stream_parser_map_.count(id) == 0) {
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 This whole block & the comment can be remove. The
annacc 2012/06/08 22:12:23 Hmm, seems like it is still needed. Are you sure
acolwell GONE FROM CHROMIUM 2012/06/11 16:09:33 Yes. The only test that I saw break when I removed
539 std::vector<std::string> codecs(2); 543 std::vector<std::string> codecs(2);
540 codecs[0] = "vp8"; 544 codecs[0] = "vp8";
541 codecs[1] = "vorbis"; 545 codecs[1] = "vorbis";
542 AddId(id, "video/webm", codecs); 546 AddId(id, "video/webm", codecs);
543 } 547 }
544 548
545 DCHECK(!source_id_.empty()); 549 DCHECK_GT(stream_parser_map_.count(id), 0u);
546 DCHECK_EQ(source_id_, id);
547 DCHECK(!id.empty()); 550 DCHECK(!id.empty());
548 DCHECK(data); 551 DCHECK(data);
549 DCHECK_GT(length, 0u); 552 DCHECK_GT(length, 0u);
550 553
551 int64 buffered_bytes = 0; 554 int64 buffered_bytes = 0;
552 555
553 PipelineStatusCB cb; 556 PipelineStatusCB cb;
554 { 557 {
555 base::AutoLock auto_lock(lock_); 558 base::AutoLock auto_lock(lock_);
556 559
557 // Capture if the SourceBuffer has a pending seek before we start parsing. 560 // Capture if the SourceBuffer has a pending seek before we start parsing.
558 bool old_seek_pending = IsSeekPending_Locked(); 561 bool old_seek_pending = IsSeekPending_Locked();
559 562
560 switch (state_) { 563 switch (state_) {
561 case INITIALIZING: 564 case INITIALIZING:
562 if (!stream_parser_->Parse(data, length)) { 565 if (!stream_parser_map_[id]->Parse(data, length)) {
563 DCHECK_EQ(state_, INITIALIZING); 566 DCHECK_EQ(state_, INITIALIZING);
564 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 567 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
565 return true; 568 return true;
566 } 569 }
567 break; 570 break;
568 571
569 case INITIALIZED: { 572 case INITIALIZED: {
570 if (!stream_parser_->Parse(data, length)) { 573 if (!stream_parser_map_[id]->Parse(data, length)) {
571 ReportError_Locked(PIPELINE_ERROR_DECODE); 574 ReportError_Locked(PIPELINE_ERROR_DECODE);
572 return true; 575 return true;
573 } 576 }
574 } break; 577 } break;
575 578
576 case WAITING_FOR_INIT: 579 case WAITING_FOR_INIT:
577 case ENDED: 580 case ENDED:
578 case PARSE_ERROR: 581 case PARSE_ERROR:
579 case SHUTDOWN: 582 case SHUTDOWN:
580 DVLOG(1) << "AppendData(): called in unexpected state " << state_; 583 DVLOG(1) << "AppendData(): called in unexpected state " << state_;
(...skipping 18 matching lines...) Expand all
599 602
600 if (!cb.is_null()) 603 if (!cb.is_null())
601 cb.Run(PIPELINE_OK); 604 cb.Run(PIPELINE_OK);
602 605
603 return true; 606 return true;
604 } 607 }
605 608
606 void ChunkDemuxer::Abort(const std::string& id) { 609 void ChunkDemuxer::Abort(const std::string& id) {
607 DVLOG(1) << "Abort(" << id << ")"; 610 DVLOG(1) << "Abort(" << id << ")";
608 DCHECK(!id.empty()); 611 DCHECK(!id.empty());
609 DCHECK_EQ(source_id_, id); 612 DCHECK_GT(stream_parser_map_.count(id), 0u);
610 613
611 stream_parser_->Flush(); 614 stream_parser_map_[id]->Flush();
612 } 615 }
613 616
614 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { 617 bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
615 DVLOG(1) << "EndOfStream(" << status << ")"; 618 DVLOG(1) << "EndOfStream(" << status << ")";
616 base::AutoLock auto_lock(lock_); 619 base::AutoLock auto_lock(lock_);
617 DCHECK_NE(state_, WAITING_FOR_INIT); 620 DCHECK_NE(state_, WAITING_FOR_INIT);
618 DCHECK_NE(state_, ENDED); 621 DCHECK_NE(state_, ENDED);
619 622
620 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 623 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
621 return true; 624 return true;
(...skipping 30 matching lines...) Expand all
652 return; 655 return;
653 656
654 std::swap(cb, seek_cb_); 657 std::swap(cb, seek_cb_);
655 658
656 if (audio_) 659 if (audio_)
657 audio_->Shutdown(); 660 audio_->Shutdown();
658 661
659 if (video_) 662 if (video_)
660 video_->Shutdown(); 663 video_->Shutdown();
661 664
662 stream_parser_.reset(); 665 stream_parser_map_.clear();
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 This is a memory leak. You need to iterate over th
annacc 2012/06/08 22:12:23 Whoops. Done.
663 666
664 ChangeState_Locked(SHUTDOWN); 667 ChangeState_Locked(SHUTDOWN);
665 } 668 }
666 669
667 if (!cb.is_null()) 670 if (!cb.is_null())
668 cb.Run(PIPELINE_ERROR_ABORT); 671 cb.Run(PIPELINE_ERROR_ABORT);
669 672
670 client_->DemuxerClosed(); 673 client_->DemuxerClosed();
671 } 674 }
672 675
673 void ChunkDemuxer::ChangeState_Locked(State new_state) { 676 void ChunkDemuxer::ChangeState_Locked(State new_state) {
674 lock_.AssertAcquired(); 677 lock_.AssertAcquired();
675 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " 678 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
676 << state_ << " -> " << new_state; 679 << state_ << " -> " << new_state;
677 state_ = new_state; 680 state_ = new_state;
678 } 681 }
679 682
680 ChunkDemuxer::~ChunkDemuxer() { 683 ChunkDemuxer::~ChunkDemuxer() {
681 DCHECK_NE(state_, INITIALIZED); 684 DCHECK_NE(state_, INITIALIZED);
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 You need a loop here that deletes all the parsers
annacc 2012/06/08 22:12:23 Done.
682 } 685 }
683 686
684 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { 687 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
685 DVLOG(1) << "ReportError_Locked(" << error << ")"; 688 DVLOG(1) << "ReportError_Locked(" << error << ")";
686 lock_.AssertAcquired(); 689 lock_.AssertAcquired();
687 DCHECK_NE(error, PIPELINE_OK); 690 DCHECK_NE(error, PIPELINE_OK);
688 691
689 ChangeState_Locked(PARSE_ERROR); 692 ChangeState_Locked(PARSE_ERROR);
690 693
691 PipelineStatusCB cb; 694 PipelineStatusCB cb;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 base::TimeDelta duration) { 739 base::TimeDelta duration) {
737 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", " 740 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", "
738 << duration.InSecondsF() << ")"; 741 << duration.InSecondsF() << ")";
739 lock_.AssertAcquired(); 742 lock_.AssertAcquired();
740 DCHECK_EQ(state_, INITIALIZING); 743 DCHECK_EQ(state_, INITIALIZING);
741 if (!success || (!audio_ && !video_)) { 744 if (!success || (!audio_ && !video_)) {
742 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 745 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
743 return; 746 return;
744 } 747 }
745 748
749 // Wait until all streams have initialized.
750 if ((!source_id_audio_.empty() && !audio_) ||
751 (!source_id_video_.empty() && !video_))
752 return;
annacc 2012/06/07 22:42:07 This check is the source of a lot of the AddId() c
753
746 duration_ = duration; 754 duration_ = duration;
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 I wonder if we should move the duration_ assignmen
annacc 2012/06/08 22:12:23 Oh, good idea.
747 host_->SetDuration(duration_); 755 host_->SetDuration(duration_);
748 756
749 ChangeState_Locked(INITIALIZED); 757 ChangeState_Locked(INITIALIZED);
750 PipelineStatusCB cb; 758 PipelineStatusCB cb;
751 std::swap(cb, init_cb_); 759 std::swap(cb, init_cb_);
752 cb.Run(PIPELINE_OK); 760 cb.Run(PIPELINE_OK);
753 } 761 }
754 762
755 bool ChunkDemuxer::OnNewConfigs(const AudioDecoderConfig& audio_config, 763 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video,
764 const AudioDecoderConfig& audio_config,
756 const VideoDecoderConfig& video_config) { 765 const VideoDecoderConfig& video_config) {
757 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig()); 766 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig());
758 lock_.AssertAcquired(); 767 lock_.AssertAcquired();
759 768
760 // Signal an error if we get configuration info for stream types that weren't 769 // 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. 770 // specified in AddId() or more configs after a stream is initialized.
762 // Only allow a single audio config for now. 771 // Only allow a single audio config for now.
763 if (audio_config.IsValidConfig() && (!has_audio_ || audio_)) 772 if (audio_config.IsValidConfig() && (!has_audio || audio_))
764 return false; 773 return false;
765 774
766 // Only allow a single video config for now. 775 // Only allow a single video config for now.
767 if (video_config.IsValidConfig() && (!has_video_ || video_)) 776 if (video_config.IsValidConfig() && (!has_video || video_))
768 return false; 777 return false;
769 778
770 if (audio_config.IsValidConfig()) 779 if (audio_config.IsValidConfig())
771 audio_ = new ChunkDemuxerStream(audio_config); 780 audio_ = new ChunkDemuxerStream(audio_config);
772 781
773 if (video_config.IsValidConfig()) 782 if (video_config.IsValidConfig())
774 video_ = new ChunkDemuxerStream(video_config); 783 video_ = new ChunkDemuxerStream(video_config);
775 784
776 return true; 785 return true;
777 } 786 }
(...skipping 22 matching lines...) Expand all
800 return true; 809 return true;
801 } 810 }
802 811
803 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data, 812 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data,
804 int init_data_size) { 813 int init_data_size) {
805 client_->KeyNeeded(init_data.Pass(), init_data_size); 814 client_->KeyNeeded(init_data.Pass(), init_data_size);
806 return true; 815 return true;
807 } 816 }
808 817
809 } // namespace media 818 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698