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

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: nit 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
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 for (size_t i = 0; i < video_streams_.size(); ++i) {
wolenetz 2016/09/14 23:31:21 s/i </!stream_found && i </
servolk 2016/09/15 00:18:32 Done (only slightly differently to preserve the ca
wolenetz 2016/09/15 01:00:08 Acknowledged.
656 if (video_streams_[i].get() == s) {
657 stream_found = true;
658 removed_streams_.push_back(std::move(video_streams_[i]));
659 video_streams_.erase(video_streams_.begin() + i);
660 break;
661 }
662 }
663 CHECK(stream_found);
664 }
665 id_to_streams_map_.erase(id);
636 } 666 }
637 667
638 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 668 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
639 base::AutoLock auto_lock(lock_); 669 base::AutoLock auto_lock(lock_);
640 DCHECK(!id.empty()); 670 DCHECK(!id.empty());
641 671
642 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id); 672 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
643 673
644 DCHECK(itr != source_state_map_.end()); 674 DCHECK(itr != source_state_map_.end());
645 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); 675 return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
646 } 676 }
647 677
648 base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp( 678 base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp(
649 const std::string& id) const { 679 const std::string& id) const {
650 base::AutoLock auto_lock(lock_); 680 base::AutoLock auto_lock(lock_);
651 DCHECK(!id.empty()); 681 DCHECK(!id.empty());
652 682
653 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id); 683 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
654 684
655 DCHECK(itr != source_state_map_.end()); 685 DCHECK(itr != source_state_map_.end());
656 return itr->second->GetHighestPresentationTimestamp(); 686 return itr->second->GetHighestPresentationTimestamp();
657 } 687 }
658 688
659 void ChunkDemuxer::OnEnabledAudioTracksChanged( 689 void ChunkDemuxer::OnEnabledAudioTracksChanged(
660 const std::vector<MediaTrack::Id>& track_ids, 690 const std::vector<MediaTrack::Id>& track_ids,
661 base::TimeDelta currTime) { 691 base::TimeDelta currTime) {
662 // Note: We intentionally don't lock here, since we are not accessing any 692 base::AutoLock auto_lock(lock_);
663 // members directly. 693 std::set<DemuxerStream*> enabled_streams;
664 DemuxerStream* audio_stream = GetStream(DemuxerStream::AUDIO); 694 for (const auto& id : track_ids) {
665 bool enabled = false; 695 DemuxerStream* stream = track_id_to_demux_stream_map_[id];
666 CHECK(audio_stream); 696 DCHECK(stream);
667 DCHECK_LE(track_ids.size(), 1u); 697 DCHECK_EQ(DemuxerStream::AUDIO, stream->type());
668 if (track_ids.size() > 0) { 698 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 } 699 }
675 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") 700
676 << " audio stream"; 701 // First disable all streams that need to be disabled and then enable streams
677 audio_stream->set_enabled(enabled, currTime); 702 // that are enabled.
703 for (const auto& stream : audio_streams_) {
704 if (enabled_streams.find(stream.get()) == enabled_streams.end()) {
705 DVLOG(1) << __func__ << ": disabling stream " << stream.get();
706 stream->set_enabled(false, currTime);
707 }
708 }
709 for (const auto& stream : enabled_streams) {
710 DVLOG(1) << __func__ << ": enabling stream " << stream;
711 stream->set_enabled(true, currTime);
712 }
678 } 713 }
679 714
680 void ChunkDemuxer::OnSelectedVideoTrackChanged( 715 void ChunkDemuxer::OnSelectedVideoTrackChanged(
681 const std::vector<MediaTrack::Id>& track_ids, 716 const std::vector<MediaTrack::Id>& track_ids,
682 base::TimeDelta currTime) { 717 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); 718 DCHECK_LE(track_ids.size(), 1u);
689 if (track_ids.size() > 0) { 719
690 #if DCHECK_IS_ON() 720 base::AutoLock auto_lock(lock_);
691 base::AutoLock auto_lock(lock_); 721 DemuxerStream* selected_stream = nullptr;
692 DCHECK(track_id_to_demux_stream_map_[track_ids[0]] == video_stream); 722 if (!track_ids.empty()) {
693 #endif 723 selected_stream = track_id_to_demux_stream_map_[track_ids[0]];
694 enabled = true; 724 DCHECK(selected_stream);
725 DCHECK_EQ(DemuxerStream::VIDEO, selected_stream->type());
695 } 726 }
696 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") 727
697 << " video stream"; 728 // First disable all streams that need to be disabled and then enable the
698 video_stream->set_enabled(enabled, currTime); 729 // stream that needs to be enabled (if any).
730 for (const auto& stream : video_streams_) {
731 if (stream->type() == DemuxerStream::VIDEO &&
732 stream.get() != selected_stream) {
733 DVLOG(1) << __func__ << ": disabling stream " << stream.get();
734 stream->set_enabled(false, currTime);
735 }
736 }
737 if (selected_stream) {
738 DVLOG(1) << __func__ << ": enabling stream " << selected_stream;
739 selected_stream->set_enabled(true, currTime);
740 }
699 } 741 }
700 742
701 bool ChunkDemuxer::EvictCodedFrames(const std::string& id, 743 bool ChunkDemuxer::EvictCodedFrames(const std::string& id,
702 base::TimeDelta currentMediaTime, 744 base::TimeDelta currentMediaTime,
703 size_t newDataSize) { 745 size_t newDataSize) {
704 DVLOG(1) << __func__ << "(" << id << ")" 746 DVLOG(1) << __func__ << "(" << id << ")"
705 << " media_time=" << currentMediaTime.InSecondsF() 747 << " media_time=" << currentMediaTime.InSecondsF()
706 << " newDataSize=" << newDataSize; 748 << " newDataSize=" << newDataSize;
707 base::AutoLock auto_lock(lock_); 749 base::AutoLock auto_lock(lock_);
708 750
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin(); 1080 for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin();
1039 itr != source_state_map_.end(); ++itr) { 1081 itr != source_state_map_.end(); ++itr) {
1040 if (itr->second->IsSeekWaitingForData()) 1082 if (itr->second->IsSeekWaitingForData())
1041 return true; 1083 return true;
1042 } 1084 }
1043 1085
1044 return false; 1086 return false;
1045 } 1087 }
1046 1088
1047 void ChunkDemuxer::OnSourceInitDone( 1089 void ChunkDemuxer::OnSourceInitDone(
1090 const std::string& source_id,
1048 const StreamParser::InitParameters& params) { 1091 const StreamParser::InitParameters& params) {
1049 DVLOG(1) << "OnSourceInitDone(" << params.duration.InSecondsF() << ")"; 1092 DVLOG(1) << "OnSourceInitDone source_id=" << source_id
1093 << " duration=" << params.duration.InSecondsF();
1050 lock_.AssertAcquired(); 1094 lock_.AssertAcquired();
1051 DCHECK_EQ(state_, INITIALIZING); 1095 DCHECK_EQ(state_, INITIALIZING);
1052 if (!audio_ && !video_) { 1096 DCHECK(pending_source_init_ids_.find(source_id) !=
1097 pending_source_init_ids_.end());
1098 if (audio_streams_.empty() && video_streams_.empty()) {
1053 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1099 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1054 return; 1100 return;
1055 } 1101 }
1056 1102
1057 if (!params.duration.is_zero() && duration_ == kNoTimestamp) 1103 if (!params.duration.is_zero() && duration_ == kNoTimestamp)
1058 UpdateDuration(params.duration); 1104 UpdateDuration(params.duration);
1059 1105
1060 if (!params.timeline_offset.is_null()) { 1106 if (!params.timeline_offset.is_null()) {
1061 if (!timeline_offset_.is_null() && 1107 if (!timeline_offset_.is_null() &&
1062 params.timeline_offset != timeline_offset_) { 1108 params.timeline_offset != timeline_offset_) {
1063 MEDIA_LOG(ERROR, media_log_) 1109 MEDIA_LOG(ERROR, media_log_)
1064 << "Timeline offset is not the same across all SourceBuffers."; 1110 << "Timeline offset is not the same across all SourceBuffers.";
1065 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1111 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1066 return; 1112 return;
1067 } 1113 }
1068 1114
1069 timeline_offset_ = params.timeline_offset; 1115 timeline_offset_ = params.timeline_offset;
1070 } 1116 }
1071 1117
1072 if (params.liveness != DemuxerStream::LIVENESS_UNKNOWN) { 1118 if (params.liveness != DemuxerStream::LIVENESS_UNKNOWN) {
1073 if (audio_) 1119 for (const auto& s : audio_streams_)
1074 audio_->SetLiveness(params.liveness); 1120 s->SetLiveness(params.liveness);
1075 if (video_) 1121 for (const auto& s : video_streams_)
1076 video_->SetLiveness(params.liveness); 1122 s->SetLiveness(params.liveness);
1077 } 1123 }
1078 1124
1079 detected_audio_track_count_ += params.detected_audio_track_count; 1125 detected_audio_track_count_ += params.detected_audio_track_count;
1080 detected_video_track_count_ += params.detected_video_track_count; 1126 detected_video_track_count_ += params.detected_video_track_count;
1081 detected_text_track_count_ += params.detected_text_track_count; 1127 detected_text_track_count_ += params.detected_text_track_count;
1082 1128
1083 // Wait until all streams have initialized. 1129 // Wait until all streams have initialized.
1084 pending_source_init_done_count_--; 1130 pending_source_init_ids_.erase(source_id);
1085 1131 if (!pending_source_init_ids_.empty())
1086 if (pending_source_init_done_count_ > 0)
1087 return; 1132 return;
1088 1133
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. 1134 // Record detected track counts by type corresponding to an MSE playback.
1094 // Counts are split into 50 buckets, capped into [0,100] range. 1135 // Counts are split into 50 buckets, capped into [0,100] range.
1095 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Audio", 1136 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Audio",
1096 detected_audio_track_count_); 1137 detected_audio_track_count_);
1097 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Video", 1138 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Video",
1098 detected_video_track_count_); 1139 detected_video_track_count_);
1099 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Text", 1140 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Text",
1100 detected_text_track_count_); 1141 detected_text_track_count_);
1101 1142
1102 if (video_) { 1143 for (const auto& s : video_streams_) {
1103 media_log_->RecordRapporWithSecurityOrigin( 1144 media_log_->RecordRapporWithSecurityOrigin(
1104 "Media.OriginUrl.MSE.VideoCodec." + 1145 "Media.OriginUrl.MSE.VideoCodec." +
1105 GetCodecName(video_->video_decoder_config().codec())); 1146 GetCodecName(s->video_decoder_config().codec()));
1106 } 1147 }
1107 1148
1108 SeekAllSources(GetStartTime()); 1149 SeekAllSources(GetStartTime());
1109 StartReturningData(); 1150 StartReturningData();
1110 1151
1111 if (duration_ == kNoTimestamp) 1152 if (duration_ == kNoTimestamp)
1112 duration_ = kInfiniteDuration; 1153 duration_ = kInfiniteDuration;
1113 1154
1114 // The demuxer is now initialized after the |start_timestamp_| was set. 1155 // The demuxer is now initialized after the |start_timestamp_| was set.
1115 ChangeState_Locked(INITIALIZED); 1156 ChangeState_Locked(INITIALIZED);
1116 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 1157 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
1117 } 1158 }
1118 1159
1119 // static 1160 // static
1120 MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() { 1161 MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() {
1121 static unsigned g_track_count = 0; 1162 static unsigned g_track_count = 0;
1122 return base::UintToString(++g_track_count); 1163 return base::UintToString(++g_track_count);
1123 } 1164 }
1124 1165
1125 ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream( 1166 ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream(
1167 const std::string& source_id,
1126 DemuxerStream::Type type) { 1168 DemuxerStream::Type type) {
1127 // New ChunkDemuxerStreams can be created only during initialization segment 1169 // New ChunkDemuxerStreams can be created only during initialization segment
1128 // processing, which happens when a new chunk of data is appended and the 1170 // processing, which happens when a new chunk of data is appended and the
1129 // lock_ must be held by ChunkDemuxer::AppendData. 1171 // lock_ must be held by ChunkDemuxer::AppendData.
1130 lock_.AssertAcquired(); 1172 lock_.AssertAcquired();
1131 1173
1132 MediaTrack::Id media_track_id = GenerateMediaTrackId(); 1174 MediaTrack::Id media_track_id = GenerateMediaTrackId();
1133 1175
1134 switch (type) { 1176 switch (type) {
1135 case DemuxerStream::AUDIO: 1177 case DemuxerStream::AUDIO: {
1136 if (audio_) 1178 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)); 1179 DemuxerStream::AUDIO, splice_frames_enabled_, media_track_id));
1140 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) == 1180 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
1141 track_id_to_demux_stream_map_.end()); 1181 track_id_to_demux_stream_map_.end());
1142 track_id_to_demux_stream_map_[media_track_id] = audio_.get(); 1182 track_id_to_demux_stream_map_[media_track_id] = audio_stream.get();
1143 return audio_.get(); 1183 id_to_streams_map_[source_id].push_back(audio_stream.get());
1144 break; 1184 audio_streams_.push_back(std::move(audio_stream));
1145 case DemuxerStream::VIDEO: 1185 return audio_streams_.back().get();
1146 if (video_) 1186 }
1147 return NULL; 1187 case DemuxerStream::VIDEO: {
1148 video_.reset(new ChunkDemuxerStream( 1188 std::unique_ptr<ChunkDemuxerStream> video_stream(new ChunkDemuxerStream(
1149 DemuxerStream::VIDEO, splice_frames_enabled_, media_track_id)); 1189 DemuxerStream::VIDEO, splice_frames_enabled_, media_track_id));
1150 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) == 1190 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
1151 track_id_to_demux_stream_map_.end()); 1191 track_id_to_demux_stream_map_.end());
1152 track_id_to_demux_stream_map_[media_track_id] = video_.get(); 1192 track_id_to_demux_stream_map_[media_track_id] = video_stream.get();
1153 return video_.get(); 1193 id_to_streams_map_[source_id].push_back(video_stream.get());
1154 break; 1194 video_streams_.push_back(std::move(video_stream));
1195 return video_streams_.back().get();
1196 }
1155 case DemuxerStream::TEXT: { 1197 case DemuxerStream::TEXT: {
1156 return new ChunkDemuxerStream(DemuxerStream::TEXT, splice_frames_enabled_, 1198 ChunkDemuxerStream* text_stream = new ChunkDemuxerStream(
1157 media_track_id); 1199 DemuxerStream::TEXT, splice_frames_enabled_, media_track_id);
1158 break; 1200 id_to_streams_map_[source_id].push_back(text_stream);
1201 return text_stream;
1159 } 1202 }
1160 case DemuxerStream::UNKNOWN: 1203 case DemuxerStream::UNKNOWN:
1161 case DemuxerStream::NUM_TYPES: 1204 case DemuxerStream::NUM_TYPES:
1162 NOTREACHED(); 1205 NOTREACHED();
1163 return NULL; 1206 return NULL;
1164 } 1207 }
1165 NOTREACHED(); 1208 NOTREACHED();
1166 return NULL; 1209 return NULL;
1167 } 1210 }
1168 1211
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 } 1315 }
1273 1316
1274 void ChunkDemuxer::ShutdownAllStreams() { 1317 void ChunkDemuxer::ShutdownAllStreams() {
1275 for (MediaSourceStateMap::iterator itr = source_state_map_.begin(); 1318 for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
1276 itr != source_state_map_.end(); ++itr) { 1319 itr != source_state_map_.end(); ++itr) {
1277 itr->second->Shutdown(); 1320 itr->second->Shutdown();
1278 } 1321 }
1279 } 1322 }
1280 1323
1281 } // namespace media 1324 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698