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

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

Issue 2226443002: Support multiple media tracks in MSE / ChunkDemuxer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed integer overflow Created 4 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/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 <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <list>
10 #include <utility> 9 #include <utility>
11 10
12 #include "base/bind.h" 11 #include "base/bind.h"
13 #include "base/callback_helpers.h" 12 #include "base/callback_helpers.h"
14 #include "base/location.h" 13 #include "base/location.h"
15 #include "base/macros.h" 14 #include "base/macros.h"
16 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
17 #include "base/stl_util.h" 16 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
19 #include "media/base/audio_decoder_config.h" 18 #include "media/base/audio_decoder_config.h"
20 #include "media/base/bind_to_current_loop.h" 19 #include "media/base/bind_to_current_loop.h"
21 #include "media/base/media_tracks.h" 20 #include "media/base/media_tracks.h"
21 #include "media/base/mime_util.h"
22 #include "media/base/stream_parser_buffer.h" 22 #include "media/base/stream_parser_buffer.h"
23 #include "media/base/timestamp_constants.h" 23 #include "media/base/timestamp_constants.h"
24 #include "media/base/video_codecs.h" 24 #include "media/base/video_codecs.h"
25 #include "media/base/video_decoder_config.h" 25 #include "media/base/video_decoder_config.h"
26 #include "media/filters/frame_processor.h" 26 #include "media/filters/frame_processor.h"
27 #include "media/filters/stream_parser_factory.h" 27 #include "media/filters/stream_parser_factory.h"
28 28
29 using base::TimeDelta; 29 using base::TimeDelta;
30 30
31 namespace media { 31 namespace media {
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, 402 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb,
403 const scoped_refptr<MediaLog>& media_log, 403 const scoped_refptr<MediaLog>& media_log,
404 bool splice_frames_enabled) 404 bool splice_frames_enabled)
405 : state_(WAITING_FOR_INIT), 405 : state_(WAITING_FOR_INIT),
406 cancel_next_seek_(false), 406 cancel_next_seek_(false),
407 host_(NULL), 407 host_(NULL),
408 open_cb_(open_cb), 408 open_cb_(open_cb),
409 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), 409 encrypted_media_init_data_cb_(encrypted_media_init_data_cb),
410 enable_text_(false), 410 enable_text_(false),
411 media_log_(media_log), 411 media_log_(media_log),
412 pending_source_init_done_count_(0),
413 duration_(kNoTimestamp), 412 duration_(kNoTimestamp),
414 user_specified_duration_(-1), 413 user_specified_duration_(-1),
415 liveness_(DemuxerStream::LIVENESS_UNKNOWN), 414 liveness_(DemuxerStream::LIVENESS_UNKNOWN),
416 splice_frames_enabled_(splice_frames_enabled), 415 splice_frames_enabled_(splice_frames_enabled),
417 detected_audio_track_count_(0), 416 detected_audio_track_count_(0),
418 detected_video_track_count_(0), 417 detected_video_track_count_(0),
419 detected_text_track_count_(0) { 418 detected_text_track_count_(0) {
420 DCHECK(!open_cb_.is_null()); 419 DCHECK(!open_cb_.is_null());
421 DCHECK(!encrypted_media_init_data_cb_.is_null()); 420 DCHECK(!encrypted_media_init_data_cb_.is_null());
422 } 421 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 } 483 }
485 484
486 // Demuxer implementation. 485 // Demuxer implementation.
487 base::Time ChunkDemuxer::GetTimelineOffset() const { 486 base::Time ChunkDemuxer::GetTimelineOffset() const {
488 return timeline_offset_; 487 return timeline_offset_;
489 } 488 }
490 489
491 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { 490 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) {
492 DCHECK_NE(type, DemuxerStream::TEXT); 491 DCHECK_NE(type, DemuxerStream::TEXT);
493 base::AutoLock auto_lock(lock_); 492 base::AutoLock auto_lock(lock_);
493
494 // TODO(servolk): For now return only the first enabled audio/video stream,
495 // since this GetStream method is part of the implementation of the
496 // DemuxerStreamProvider interface that is used in many places and can't be
497 // changed easily. It will be fixed later, when we add support for multiple
498 // streams/tracks in DemuxerStreamProvider, tracked by crbug.com/646669
499 if (type == DemuxerStream::AUDIO)
500 for (const auto& s : audio_streams_)
501 if (s->enabled())
502 return s.get();
503
494 if (type == DemuxerStream::VIDEO) 504 if (type == DemuxerStream::VIDEO)
495 return video_.get(); 505 for (const auto& s : video_streams_)
496 506 if (s->enabled())
497 if (type == DemuxerStream::AUDIO) 507 return s.get();
498 return audio_.get();
499 508
500 return NULL; 509 return NULL;
501 } 510 }
502 511
503 TimeDelta ChunkDemuxer::GetStartTime() const { 512 TimeDelta ChunkDemuxer::GetStartTime() const {
504 return TimeDelta(); 513 return TimeDelta();
505 } 514 }
506 515
507 int64_t ChunkDemuxer::GetMemoryUsage() const { 516 int64_t ChunkDemuxer::GetMemoryUsage() const {
508 base::AutoLock auto_lock(lock_); 517 base::AutoLock auto_lock(lock_);
509 return (audio_ ? audio_->GetBufferedSize() : 0) + 518 int64_t mem = 0;
510 (video_ ? video_->GetBufferedSize() : 0); 519 for (const auto& s : audio_streams_)
520 mem += s->GetBufferedSize();
521 for (const auto& s : video_streams_)
522 mem += s->GetBufferedSize();
523 return mem;
511 } 524 }
512 525
513 void ChunkDemuxer::AbortPendingReads() { 526 void ChunkDemuxer::AbortPendingReads() {
514 base::AutoLock auto_lock(lock_); 527 base::AutoLock auto_lock(lock_);
515 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN || 528 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
516 state_ == PARSE_ERROR) 529 state_ == PARSE_ERROR)
517 << state_; 530 << state_;
518 531
519 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 532 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
520 return; 533 return;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 if (seek_cb_.is_null()) { 567 if (seek_cb_.is_null()) {
555 cancel_next_seek_ = true; 568 cancel_next_seek_ = true;
556 return; 569 return;
557 } 570 }
558 571
559 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 572 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
560 } 573 }
561 574
562 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, 575 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
563 const std::string& type, 576 const std::string& type,
564 std::vector<std::string>& codecs) { 577 const std::string& codecs) {
578 DVLOG(1) << __func__ << " id=" << id << " mime_type=" << type
579 << " codecs=" << codecs;
565 base::AutoLock auto_lock(lock_); 580 base::AutoLock auto_lock(lock_);
566 581
567 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) 582 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
568 return kReachedIdLimit; 583 return kReachedIdLimit;
569 584
570 bool has_audio = false; 585 std::vector<std::string> parsed_codec_ids;
571 bool has_video = false; 586 media::ParseCodecString(codecs, &parsed_codec_ids, false);
587
572 std::unique_ptr<media::StreamParser> stream_parser( 588 std::unique_ptr<media::StreamParser> stream_parser(
573 StreamParserFactory::Create(type, codecs, media_log_, &has_audio, 589 StreamParserFactory::Create(type, parsed_codec_ids, media_log_));
574 &has_video));
575 590
576 if (!stream_parser) 591 if (!stream_parser)
577 return ChunkDemuxer::kNotSupported; 592 return ChunkDemuxer::kNotSupported;
578 593
579 if ((has_audio && !source_id_audio_.empty()) ||
580 (has_video && !source_id_video_.empty()))
581 return kReachedIdLimit;
582
583 if (has_audio)
584 source_id_audio_ = id;
585
586 if (has_video)
587 source_id_video_ = id;
588
589 std::unique_ptr<FrameProcessor> frame_processor( 594 std::unique_ptr<FrameProcessor> frame_processor(
590 new FrameProcessor(base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, 595 new FrameProcessor(base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
591 base::Unretained(this)), 596 base::Unretained(this)),
592 media_log_)); 597 media_log_));
593 598
594 std::unique_ptr<MediaSourceState> source_state(new MediaSourceState( 599 std::unique_ptr<MediaSourceState> source_state(
595 std::move(stream_parser), std::move(frame_processor), 600 new MediaSourceState(std::move(stream_parser), std::move(frame_processor),
596 base::Bind(&ChunkDemuxer::CreateDemuxerStream, base::Unretained(this)), 601 base::Bind(&ChunkDemuxer::CreateDemuxerStream,
597 media_log_)); 602 base::Unretained(this), id),
603 media_log_));
598 604
599 MediaSourceState::NewTextTrackCB new_text_track_cb; 605 MediaSourceState::NewTextTrackCB new_text_track_cb;
600 606
601 if (enable_text_) { 607 if (enable_text_) {
602 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, 608 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack,
603 base::Unretained(this)); 609 base::Unretained(this));
604 } 610 }
605 611
606 pending_source_init_done_count_++; 612 pending_source_init_ids_.insert(id);
613
614 std::string expected_mss_codecs = codecs;
615 if (codecs == "" && type == "audio/aac")
616 expected_mss_codecs = "aac";
617 if (codecs == "" && (type == "audio/mpeg" || type == "audio/mp3"))
618 expected_mss_codecs = "mp3";
607 619
608 source_state->Init( 620 source_state->Init(
609 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), 621 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this), id),
610 has_audio, has_video, encrypted_media_init_data_cb_, new_text_track_cb); 622 expected_mss_codecs, encrypted_media_init_data_cb_, new_text_track_cb);
611 623
612 source_state_map_[id] = source_state.release(); 624 source_state_map_[id] = source_state.release();
613 return kOk; 625 return kOk;
614 } 626 }
615 627
616 void ChunkDemuxer::SetTracksWatcher( 628 void ChunkDemuxer::SetTracksWatcher(
617 const std::string& id, 629 const std::string& id,
618 const MediaTracksUpdatedCB& tracks_updated_cb) { 630 const MediaTracksUpdatedCB& tracks_updated_cb) {
619 base::AutoLock auto_lock(lock_); 631 base::AutoLock auto_lock(lock_);
620 CHECK(IsValidId(id)); 632 CHECK(IsValidId(id));
621 source_state_map_[id]->SetTracksWatcher(tracks_updated_cb); 633 source_state_map_[id]->SetTracksWatcher(tracks_updated_cb);
622 } 634 }
623 635
624 void ChunkDemuxer::RemoveId(const std::string& id) { 636 void ChunkDemuxer::RemoveId(const std::string& id) {
637 DVLOG(1) << __func__ << " id=" << id;
625 base::AutoLock auto_lock(lock_); 638 base::AutoLock auto_lock(lock_);
626 CHECK(IsValidId(id)); 639 CHECK(IsValidId(id));
627 640
628 delete source_state_map_[id]; 641 delete source_state_map_[id];
629 source_state_map_.erase(id); 642 source_state_map_.erase(id);
630 643 pending_source_init_ids_.erase(id);
631 if (source_id_audio_ == id) 644 // Remove demuxer streams created for this id.
632 source_id_audio_.clear(); 645 for (const ChunkDemuxerStream* s : id_to_streams_map_[id]) {
633 646 bool stream_found = false;
634 if (source_id_video_ == id) 647 for (size_t i = 0; i < audio_streams_.size(); ++i) {
635 source_id_video_.clear(); 648 if (audio_streams_[i].get() == s) {
649 stream_found = true;
650 removed_streams_.push_back(std::move(audio_streams_[i]));
651 audio_streams_.erase(audio_streams_.begin() + i);
652 break;
653 }
654 }
655 if (stream_found)
656 continue;
657 for (size_t i = 0; i < video_streams_.size(); ++i) {
658 if (video_streams_[i].get() == s) {
659 stream_found = true;
660 removed_streams_.push_back(std::move(video_streams_[i]));
661 video_streams_.erase(video_streams_.begin() + i);
662 break;
663 }
664 }
665 CHECK(stream_found);
666 }
667 id_to_streams_map_.erase(id);
636 } 668 }
637 669
638 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 670 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
639 base::AutoLock auto_lock(lock_); 671 base::AutoLock auto_lock(lock_);
640 DCHECK(!id.empty()); 672 DCHECK(!id.empty());
641 673
642 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id); 674 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
643 675
644 DCHECK(itr != source_state_map_.end()); 676 DCHECK(itr != source_state_map_.end());
645 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); 677 return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
646 } 678 }
647 679
648 base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp( 680 base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp(
649 const std::string& id) const { 681 const std::string& id) const {
650 base::AutoLock auto_lock(lock_); 682 base::AutoLock auto_lock(lock_);
651 DCHECK(!id.empty()); 683 DCHECK(!id.empty());
652 684
653 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id); 685 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
654 686
655 DCHECK(itr != source_state_map_.end()); 687 DCHECK(itr != source_state_map_.end());
656 return itr->second->GetHighestPresentationTimestamp(); 688 return itr->second->GetHighestPresentationTimestamp();
657 } 689 }
658 690
659 void ChunkDemuxer::OnEnabledAudioTracksChanged( 691 void ChunkDemuxer::OnEnabledAudioTracksChanged(
660 const std::vector<MediaTrack::Id>& track_ids, 692 const std::vector<MediaTrack::Id>& track_ids,
661 base::TimeDelta currTime) { 693 base::TimeDelta currTime) {
662 // Note: We intentionally don't lock here, since we are not accessing any 694 base::AutoLock auto_lock(lock_);
663 // members directly. 695 std::set<DemuxerStream*> enabled_streams;
664 DemuxerStream* audio_stream = GetStream(DemuxerStream::AUDIO); 696 for (const auto& id : track_ids) {
665 bool enabled = false; 697 DemuxerStream* stream = track_id_to_demux_stream_map_[id];
666 CHECK(audio_stream); 698 DCHECK(stream);
667 DCHECK_LE(track_ids.size(), 1u); 699 DCHECK_EQ(DemuxerStream::AUDIO, stream->type());
668 if (track_ids.size() > 0) { 700 enabled_streams.insert(stream);
669 #if DCHECK_IS_ON()
670 base::AutoLock auto_lock(lock_);
671 DCHECK(track_id_to_demux_stream_map_[track_ids[0]] == audio_stream);
672 #endif
673 enabled = true;
674 } 701 }
675 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") 702
676 << " audio stream"; 703 // First disable all streams that need to be disabled and then enable streams
677 audio_stream->set_enabled(enabled, currTime); 704 // that are enabled.
705 for (const auto& stream : audio_streams_) {
706 if (enabled_streams.find(stream.get()) == enabled_streams.end()) {
707 DVLOG(1) << __func__ << ": disabling stream " << stream.get();
708 stream->set_enabled(false, currTime);
709 }
710 }
711 for (const auto& stream : enabled_streams) {
712 DVLOG(1) << __func__ << ": enabling stream " << stream;
713 stream->set_enabled(true, currTime);
714 }
678 } 715 }
679 716
680 void ChunkDemuxer::OnSelectedVideoTrackChanged( 717 void ChunkDemuxer::OnSelectedVideoTrackChanged(
681 const std::vector<MediaTrack::Id>& track_ids, 718 const std::vector<MediaTrack::Id>& track_ids,
682 base::TimeDelta currTime) { 719 base::TimeDelta currTime) {
683 // Note: We intentionally don't lock here, since we are not accessing any
684 // members directly.
685 DemuxerStream* video_stream = GetStream(DemuxerStream::VIDEO);
686 bool enabled = false;
687 CHECK(video_stream);
688 DCHECK_LE(track_ids.size(), 1u); 720 DCHECK_LE(track_ids.size(), 1u);
689 if (track_ids.size() > 0) { 721
690 #if DCHECK_IS_ON() 722 base::AutoLock auto_lock(lock_);
691 base::AutoLock auto_lock(lock_); 723 DemuxerStream* selected_stream = nullptr;
692 DCHECK(track_id_to_demux_stream_map_[track_ids[0]] == video_stream); 724 if (!track_ids.empty()) {
693 #endif 725 selected_stream = track_id_to_demux_stream_map_[track_ids[0]];
694 enabled = true; 726 DCHECK(selected_stream);
727 DCHECK_EQ(DemuxerStream::VIDEO, selected_stream->type());
695 } 728 }
696 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") 729
697 << " video stream"; 730 // First disable all streams that need to be disabled and then enable the
698 video_stream->set_enabled(enabled, currTime); 731 // stream that needs to be enabled (if any).
732 for (const auto& stream : video_streams_) {
733 if (stream.get() != selected_stream) {
734 DVLOG(1) << __func__ << ": disabling stream " << stream.get();
735 DCHECK_EQ(DemuxerStream::VIDEO, stream->type());
736 stream->set_enabled(false, currTime);
737 }
738 }
739 if (selected_stream) {
740 DVLOG(1) << __func__ << ": enabling stream " << selected_stream;
741 selected_stream->set_enabled(true, currTime);
742 }
699 } 743 }
700 744
701 bool ChunkDemuxer::EvictCodedFrames(const std::string& id, 745 bool ChunkDemuxer::EvictCodedFrames(const std::string& id,
702 base::TimeDelta currentMediaTime, 746 base::TimeDelta currentMediaTime,
703 size_t newDataSize) { 747 size_t newDataSize) {
704 DVLOG(1) << __func__ << "(" << id << ")" 748 DVLOG(1) << __func__ << "(" << id << ")"
705 << " media_time=" << currentMediaTime.InSecondsF() 749 << " media_time=" << currentMediaTime.InSecondsF()
706 << " newDataSize=" << newDataSize; 750 << " newDataSize=" << newDataSize;
707 base::AutoLock auto_lock(lock_); 751 base::AutoLock auto_lock(lock_);
708 752
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 return; 1022 return;
979 1023
980 ShutdownAllStreams(); 1024 ShutdownAllStreams();
981 1025
982 ChangeState_Locked(SHUTDOWN); 1026 ChangeState_Locked(SHUTDOWN);
983 1027
984 if (!seek_cb_.is_null()) 1028 if (!seek_cb_.is_null())
985 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT); 1029 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT);
986 } 1030 }
987 1031
988 void ChunkDemuxer::SetMemoryLimits(DemuxerStream::Type type, 1032 void ChunkDemuxer::SetMemoryLimitsForTest(DemuxerStream::Type type,
989 size_t memory_limit) { 1033 size_t memory_limit) {
990 for (MediaSourceStateMap::iterator itr = source_state_map_.begin(); 1034 for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
991 itr != source_state_map_.end(); ++itr) { 1035 itr != source_state_map_.end(); ++itr) {
992 itr->second->SetMemoryLimits(type, memory_limit); 1036 itr->second->SetMemoryLimits(type, memory_limit);
993 } 1037 }
994 } 1038 }
995 1039
996 void ChunkDemuxer::ChangeState_Locked(State new_state) { 1040 void ChunkDemuxer::ChangeState_Locked(State new_state) {
997 lock_.AssertAcquired(); 1041 lock_.AssertAcquired();
998 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " 1042 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
999 << state_ << " -> " << new_state; 1043 << state_ << " -> " << new_state;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin(); 1082 for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin();
1039 itr != source_state_map_.end(); ++itr) { 1083 itr != source_state_map_.end(); ++itr) {
1040 if (itr->second->IsSeekWaitingForData()) 1084 if (itr->second->IsSeekWaitingForData())
1041 return true; 1085 return true;
1042 } 1086 }
1043 1087
1044 return false; 1088 return false;
1045 } 1089 }
1046 1090
1047 void ChunkDemuxer::OnSourceInitDone( 1091 void ChunkDemuxer::OnSourceInitDone(
1092 const std::string& source_id,
1048 const StreamParser::InitParameters& params) { 1093 const StreamParser::InitParameters& params) {
1049 DVLOG(1) << "OnSourceInitDone(" << params.duration.InSecondsF() << ")"; 1094 DVLOG(1) << "OnSourceInitDone source_id=" << source_id
1095 << " duration=" << params.duration.InSecondsF();
1050 lock_.AssertAcquired(); 1096 lock_.AssertAcquired();
1051 DCHECK_EQ(state_, INITIALIZING); 1097 DCHECK_EQ(state_, INITIALIZING);
1052 if (!audio_ && !video_) { 1098 DCHECK(pending_source_init_ids_.find(source_id) !=
1099 pending_source_init_ids_.end());
1100 if (audio_streams_.empty() && video_streams_.empty()) {
1053 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1101 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1054 return; 1102 return;
1055 } 1103 }
1056 1104
1057 if (!params.duration.is_zero() && duration_ == kNoTimestamp) 1105 if (!params.duration.is_zero() && duration_ == kNoTimestamp)
1058 UpdateDuration(params.duration); 1106 UpdateDuration(params.duration);
1059 1107
1060 if (!params.timeline_offset.is_null()) { 1108 if (!params.timeline_offset.is_null()) {
1061 if (!timeline_offset_.is_null() && 1109 if (!timeline_offset_.is_null() &&
1062 params.timeline_offset != timeline_offset_) { 1110 params.timeline_offset != timeline_offset_) {
1063 MEDIA_LOG(ERROR, media_log_) 1111 MEDIA_LOG(ERROR, media_log_)
1064 << "Timeline offset is not the same across all SourceBuffers."; 1112 << "Timeline offset is not the same across all SourceBuffers.";
1065 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1113 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1066 return; 1114 return;
1067 } 1115 }
1068 1116
1069 timeline_offset_ = params.timeline_offset; 1117 timeline_offset_ = params.timeline_offset;
1070 } 1118 }
1071 1119
1072 if (params.liveness != DemuxerStream::LIVENESS_UNKNOWN) { 1120 if (params.liveness != DemuxerStream::LIVENESS_UNKNOWN) {
1073 if (audio_) 1121 for (const auto& s : audio_streams_)
1074 audio_->SetLiveness(params.liveness); 1122 s->SetLiveness(params.liveness);
1075 if (video_) 1123 for (const auto& s : video_streams_)
1076 video_->SetLiveness(params.liveness); 1124 s->SetLiveness(params.liveness);
1077 } 1125 }
1078 1126
1079 detected_audio_track_count_ += params.detected_audio_track_count; 1127 detected_audio_track_count_ += params.detected_audio_track_count;
1080 detected_video_track_count_ += params.detected_video_track_count; 1128 detected_video_track_count_ += params.detected_video_track_count;
1081 detected_text_track_count_ += params.detected_text_track_count; 1129 detected_text_track_count_ += params.detected_text_track_count;
1082 1130
1083 // Wait until all streams have initialized. 1131 // Wait until all streams have initialized.
1084 pending_source_init_done_count_--; 1132 pending_source_init_ids_.erase(source_id);
1085 1133 if (!pending_source_init_ids_.empty())
1086 if (pending_source_init_done_count_ > 0)
1087 return; 1134 return;
1088 1135
1089 DCHECK_EQ(0, pending_source_init_done_count_);
1090 DCHECK((source_id_audio_.empty() == !audio_) &&
1091 (source_id_video_.empty() == !video_));
1092
1093 // Record detected track counts by type corresponding to an MSE playback. 1136 // Record detected track counts by type corresponding to an MSE playback.
1094 // Counts are split into 50 buckets, capped into [0,100] range. 1137 // Counts are split into 50 buckets, capped into [0,100] range.
1095 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Audio", 1138 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Audio",
1096 detected_audio_track_count_); 1139 detected_audio_track_count_);
1097 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Video", 1140 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Video",
1098 detected_video_track_count_); 1141 detected_video_track_count_);
1099 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Text", 1142 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Text",
1100 detected_text_track_count_); 1143 detected_text_track_count_);
1101 1144
1102 if (video_) { 1145 for (const auto& s : video_streams_) {
1103 media_log_->RecordRapporWithSecurityOrigin( 1146 media_log_->RecordRapporWithSecurityOrigin(
1104 "Media.OriginUrl.MSE.VideoCodec." + 1147 "Media.OriginUrl.MSE.VideoCodec." +
1105 GetCodecName(video_->video_decoder_config().codec())); 1148 GetCodecName(s->video_decoder_config().codec()));
1106 } 1149 }
1107 1150
1108 SeekAllSources(GetStartTime()); 1151 SeekAllSources(GetStartTime());
1109 StartReturningData(); 1152 StartReturningData();
1110 1153
1111 if (duration_ == kNoTimestamp) 1154 if (duration_ == kNoTimestamp)
1112 duration_ = kInfiniteDuration; 1155 duration_ = kInfiniteDuration;
1113 1156
1114 // The demuxer is now initialized after the |start_timestamp_| was set. 1157 // The demuxer is now initialized after the |start_timestamp_| was set.
1115 ChangeState_Locked(INITIALIZED); 1158 ChangeState_Locked(INITIALIZED);
1116 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 1159 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
1117 } 1160 }
1118 1161
1119 // static 1162 // static
1120 MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() { 1163 MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() {
1121 static unsigned g_track_count = 0; 1164 static unsigned g_track_count = 0;
1122 return base::UintToString(++g_track_count); 1165 return base::UintToString(++g_track_count);
1123 } 1166 }
1124 1167
1125 ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream( 1168 ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream(
1169 const std::string& source_id,
1126 DemuxerStream::Type type) { 1170 DemuxerStream::Type type) {
1127 // New ChunkDemuxerStreams can be created only during initialization segment 1171 // New ChunkDemuxerStreams can be created only during initialization segment
1128 // processing, which happens when a new chunk of data is appended and the 1172 // processing, which happens when a new chunk of data is appended and the
1129 // lock_ must be held by ChunkDemuxer::AppendData. 1173 // lock_ must be held by ChunkDemuxer::AppendData.
1130 lock_.AssertAcquired(); 1174 lock_.AssertAcquired();
1131 1175
1132 MediaTrack::Id media_track_id = GenerateMediaTrackId(); 1176 MediaTrack::Id media_track_id = GenerateMediaTrackId();
1133 1177
1134 switch (type) { 1178 switch (type) {
1135 case DemuxerStream::AUDIO: 1179 case DemuxerStream::AUDIO: {
1136 if (audio_) 1180 std::unique_ptr<ChunkDemuxerStream> audio_stream(new ChunkDemuxerStream(
1137 return NULL;
1138 audio_.reset(new ChunkDemuxerStream(
1139 DemuxerStream::AUDIO, splice_frames_enabled_, media_track_id)); 1181 DemuxerStream::AUDIO, splice_frames_enabled_, media_track_id));
1140 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) == 1182 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
1141 track_id_to_demux_stream_map_.end()); 1183 track_id_to_demux_stream_map_.end());
1142 track_id_to_demux_stream_map_[media_track_id] = audio_.get(); 1184 track_id_to_demux_stream_map_[media_track_id] = audio_stream.get();
1143 return audio_.get(); 1185 id_to_streams_map_[source_id].push_back(audio_stream.get());
1144 break; 1186 audio_streams_.push_back(std::move(audio_stream));
1145 case DemuxerStream::VIDEO: 1187 return audio_streams_.back().get();
1146 if (video_) 1188 }
1147 return NULL; 1189 case DemuxerStream::VIDEO: {
1148 video_.reset(new ChunkDemuxerStream( 1190 std::unique_ptr<ChunkDemuxerStream> video_stream(new ChunkDemuxerStream(
1149 DemuxerStream::VIDEO, splice_frames_enabled_, media_track_id)); 1191 DemuxerStream::VIDEO, splice_frames_enabled_, media_track_id));
1150 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) == 1192 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
1151 track_id_to_demux_stream_map_.end()); 1193 track_id_to_demux_stream_map_.end());
1152 track_id_to_demux_stream_map_[media_track_id] = video_.get(); 1194 track_id_to_demux_stream_map_[media_track_id] = video_stream.get();
1153 return video_.get(); 1195 id_to_streams_map_[source_id].push_back(video_stream.get());
1154 break; 1196 video_streams_.push_back(std::move(video_stream));
1197 return video_streams_.back().get();
1198 }
1155 case DemuxerStream::TEXT: { 1199 case DemuxerStream::TEXT: {
1156 return new ChunkDemuxerStream(DemuxerStream::TEXT, splice_frames_enabled_, 1200 ChunkDemuxerStream* text_stream = new ChunkDemuxerStream(
1157 media_track_id); 1201 DemuxerStream::TEXT, splice_frames_enabled_, media_track_id);
1158 break; 1202 id_to_streams_map_[source_id].push_back(text_stream);
1203 return text_stream;
1159 } 1204 }
1160 case DemuxerStream::UNKNOWN: 1205 case DemuxerStream::UNKNOWN:
1161 case DemuxerStream::NUM_TYPES: 1206 case DemuxerStream::NUM_TYPES:
1162 NOTREACHED(); 1207 NOTREACHED();
1163 return NULL; 1208 return NULL;
1164 } 1209 }
1165 NOTREACHED(); 1210 NOTREACHED();
1166 return NULL; 1211 return NULL;
1167 } 1212 }
1168 1213
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 } 1317 }
1273 1318
1274 void ChunkDemuxer::ShutdownAllStreams() { 1319 void ChunkDemuxer::ShutdownAllStreams() {
1275 for (MediaSourceStateMap::iterator itr = source_state_map_.begin(); 1320 for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
1276 itr != source_state_map_.end(); ++itr) { 1321 itr != source_state_map_.end(); ++itr) {
1277 itr->second->Shutdown(); 1322 itr->second->Shutdown();
1278 } 1323 }
1279 } 1324 }
1280 1325
1281 } // namespace media 1326 } // 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