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

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: mp4 format is not supported on some trybots, so use webm 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_);
494 if (type == DemuxerStream::VIDEO)
495 return video_.get();
496 493
497 if (type == DemuxerStream::AUDIO) 494 if (type == DemuxerStream::AUDIO)
498 return audio_.get(); 495 for (const auto& s : audio_streams_)
496 if (s->enabled())
wolenetz 2016/09/13 21:03:13 Add TODO and crbug (if missing) w.r.t. mixing mult
servolk 2016/09/14 18:15:24 We should probably keep the GetStream name for now
wolenetz 2016/09/14 23:31:21 Acknowledged.
497 return s.get();
498
499 if (type == DemuxerStream::VIDEO)
500 for (const auto& s : video_streams_)
501 if (s->enabled())
502 return s.get();
499 503
500 return NULL; 504 return NULL;
501 } 505 }
502 506
503 TimeDelta ChunkDemuxer::GetStartTime() const { 507 TimeDelta ChunkDemuxer::GetStartTime() const {
504 return TimeDelta(); 508 return TimeDelta();
505 } 509 }
506 510
507 int64_t ChunkDemuxer::GetMemoryUsage() const { 511 int64_t ChunkDemuxer::GetMemoryUsage() const {
508 base::AutoLock auto_lock(lock_); 512 base::AutoLock auto_lock(lock_);
509 return (audio_ ? audio_->GetBufferedSize() : 0) + 513 int64_t mem = 0;
510 (video_ ? video_->GetBufferedSize() : 0); 514 for (const auto& s : audio_streams_)
515 mem += s->GetBufferedSize();
516 for (const auto& s : video_streams_)
517 mem += s->GetBufferedSize();
518 return mem;
511 } 519 }
512 520
513 void ChunkDemuxer::AbortPendingReads() { 521 void ChunkDemuxer::AbortPendingReads() {
514 base::AutoLock auto_lock(lock_); 522 base::AutoLock auto_lock(lock_);
515 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN || 523 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
516 state_ == PARSE_ERROR) 524 state_ == PARSE_ERROR)
517 << state_; 525 << state_;
518 526
519 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 527 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
520 return; 528 return;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 if (seek_cb_.is_null()) { 562 if (seek_cb_.is_null()) {
555 cancel_next_seek_ = true; 563 cancel_next_seek_ = true;
556 return; 564 return;
557 } 565 }
558 566
559 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 567 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
560 } 568 }
561 569
562 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, 570 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
563 const std::string& type, 571 const std::string& type,
564 std::vector<std::string>& codecs) { 572 const std::string& codecs) {
573 DVLOG(1) << __func__ << " id=" << id << " mime_type=" << type
574 << " codecs=" << codecs;
565 base::AutoLock auto_lock(lock_); 575 base::AutoLock auto_lock(lock_);
566 576
567 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) 577 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
568 return kReachedIdLimit; 578 return kReachedIdLimit;
569 579
570 bool has_audio = false; 580 std::vector<std::string> parsed_codec_ids;
571 bool has_video = false; 581 media::ParseCodecString(codecs, &parsed_codec_ids, false);
582
572 std::unique_ptr<media::StreamParser> stream_parser( 583 std::unique_ptr<media::StreamParser> stream_parser(
573 StreamParserFactory::Create(type, codecs, media_log_, &has_audio, 584 StreamParserFactory::Create(type, parsed_codec_ids, media_log_));
574 &has_video));
575 585
576 if (!stream_parser) 586 if (!stream_parser)
577 return ChunkDemuxer::kNotSupported; 587 return ChunkDemuxer::kNotSupported;
578 588
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( 589 std::unique_ptr<FrameProcessor> frame_processor(
590 new FrameProcessor(base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, 590 new FrameProcessor(base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
591 base::Unretained(this)), 591 base::Unretained(this)),
592 media_log_)); 592 media_log_));
593 593
594 std::unique_ptr<MediaSourceState> source_state(new MediaSourceState( 594 std::unique_ptr<MediaSourceState> source_state(
595 std::move(stream_parser), std::move(frame_processor), 595 new MediaSourceState(std::move(stream_parser), std::move(frame_processor),
596 base::Bind(&ChunkDemuxer::CreateDemuxerStream, base::Unretained(this)), 596 base::Bind(&ChunkDemuxer::CreateDemuxerStream,
597 media_log_)); 597 base::Unretained(this), id),
598 media_log_));
598 599
599 MediaSourceState::NewTextTrackCB new_text_track_cb; 600 MediaSourceState::NewTextTrackCB new_text_track_cb;
600 601
601 if (enable_text_) { 602 if (enable_text_) {
602 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, 603 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack,
603 base::Unretained(this)); 604 base::Unretained(this));
604 } 605 }
605 606
606 pending_source_init_done_count_++; 607 pending_source_init_ids_.insert(id);
608
609 std::string expected_mss_codecs = codecs;
610 if (codecs == "" && type == "audio/aac")
611 expected_mss_codecs = "aac";
612 if (codecs == "" && (type == "audio/mpeg" || type == "audio/mp3"))
613 expected_mss_codecs = "mp3";
607 614
608 source_state->Init( 615 source_state->Init(
609 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), 616 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this), id),
610 has_audio, has_video, encrypted_media_init_data_cb_, new_text_track_cb); 617 expected_mss_codecs, encrypted_media_init_data_cb_, new_text_track_cb);
611 618
612 source_state_map_[id] = source_state.release(); 619 source_state_map_[id] = source_state.release();
613 return kOk; 620 return kOk;
614 } 621 }
615 622
616 void ChunkDemuxer::SetTracksWatcher( 623 void ChunkDemuxer::SetTracksWatcher(
617 const std::string& id, 624 const std::string& id,
618 const MediaTracksUpdatedCB& tracks_updated_cb) { 625 const MediaTracksUpdatedCB& tracks_updated_cb) {
619 base::AutoLock auto_lock(lock_); 626 base::AutoLock auto_lock(lock_);
620 CHECK(IsValidId(id)); 627 CHECK(IsValidId(id));
621 source_state_map_[id]->SetTracksWatcher(tracks_updated_cb); 628 source_state_map_[id]->SetTracksWatcher(tracks_updated_cb);
622 } 629 }
623 630
624 void ChunkDemuxer::RemoveId(const std::string& id) { 631 void ChunkDemuxer::RemoveId(const std::string& id) {
632 DVLOG(1) << __func__ << " id=" << id;
625 base::AutoLock auto_lock(lock_); 633 base::AutoLock auto_lock(lock_);
626 CHECK(IsValidId(id)); 634 CHECK(IsValidId(id));
627 635
628 delete source_state_map_[id]; 636 delete source_state_map_[id];
629 source_state_map_.erase(id); 637 source_state_map_.erase(id);
630 638 pending_source_init_ids_.erase(id);
631 if (source_id_audio_ == id) 639 // Remove demuxer streams created for this id.
632 source_id_audio_.clear(); 640 for (const ChunkDemuxerStream* s : id_to_streams_map_[id]) {
633 641 for (size_t i = 0; i < audio_streams_.size(); ++i) {
wolenetz 2016/09/13 21:03:13 nit: CHECK that we actually found and moved all th
servolk 2016/09/14 18:15:23 Done.
634 if (source_id_video_ == id) 642 if (audio_streams_[i].get() == s) {
635 source_id_video_.clear(); 643 removed_streams_.push_back(std::move(audio_streams_[i]));
644 audio_streams_.erase(audio_streams_.begin() + i);
645 break;
646 }
647 }
648 for (size_t i = 0; i < video_streams_.size(); ++i) {
649 if (video_streams_[i].get() == s) {
650 removed_streams_.push_back(std::move(video_streams_[i]));
651 video_streams_.erase(video_streams_.begin() + i);
652 break;
653 }
654 }
655 }
656 id_to_streams_map_.erase(id);
636 } 657 }
637 658
638 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 659 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
639 base::AutoLock auto_lock(lock_); 660 base::AutoLock auto_lock(lock_);
640 DCHECK(!id.empty()); 661 DCHECK(!id.empty());
641 662
642 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id); 663 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
643 664
644 DCHECK(itr != source_state_map_.end()); 665 DCHECK(itr != source_state_map_.end());
645 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); 666 return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
646 } 667 }
647 668
648 base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp( 669 base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp(
649 const std::string& id) const { 670 const std::string& id) const {
650 base::AutoLock auto_lock(lock_); 671 base::AutoLock auto_lock(lock_);
651 DCHECK(!id.empty()); 672 DCHECK(!id.empty());
652 673
653 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id); 674 MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
654 675
655 DCHECK(itr != source_state_map_.end()); 676 DCHECK(itr != source_state_map_.end());
656 return itr->second->GetHighestPresentationTimestamp(); 677 return itr->second->GetHighestPresentationTimestamp();
657 } 678 }
658 679
659 void ChunkDemuxer::OnEnabledAudioTracksChanged( 680 void ChunkDemuxer::OnEnabledAudioTracksChanged(
660 const std::vector<MediaTrack::Id>& track_ids, 681 const std::vector<MediaTrack::Id>& track_ids,
661 base::TimeDelta currTime) { 682 base::TimeDelta currTime) {
662 // Note: We intentionally don't lock here, since we are not accessing any 683 base::AutoLock auto_lock(lock_);
663 // members directly. 684 std::set<DemuxerStream*> enabled_streams;
664 DemuxerStream* audio_stream = GetStream(DemuxerStream::AUDIO); 685 for (const auto& id : track_ids) {
665 bool enabled = false; 686 DemuxerStream* stream = track_id_to_demux_stream_map_[id];
666 CHECK(audio_stream); 687 DCHECK(stream);
667 DCHECK_LE(track_ids.size(), 1u); 688 DCHECK_EQ(DemuxerStream::AUDIO, stream->type());
668 if (track_ids.size() > 0) { 689 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 } 690 }
675 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") 691
676 << " audio stream"; 692 // First disable all streams that need to be disabled and then enable streams
677 audio_stream->set_enabled(enabled, currTime); 693 // that are enabled.
694 for (const auto& stream : audio_streams_) {
695 if (enabled_streams.find(stream.get()) == enabled_streams.end()) {
696 DVLOG(1) << __func__ << ": disabling stream " << stream.get();
697 stream->set_enabled(false, currTime);
698 }
699 }
700 for (const auto& stream : enabled_streams) {
701 DVLOG(1) << __func__ << ": enabling stream " << stream;
702 stream->set_enabled(true, currTime);
703 }
678 } 704 }
679 705
680 void ChunkDemuxer::OnSelectedVideoTrackChanged( 706 void ChunkDemuxer::OnSelectedVideoTrackChanged(
681 const std::vector<MediaTrack::Id>& track_ids, 707 const std::vector<MediaTrack::Id>& track_ids,
682 base::TimeDelta currTime) { 708 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); 709 DCHECK_LE(track_ids.size(), 1u);
689 if (track_ids.size() > 0) { 710
690 #if DCHECK_IS_ON() 711 base::AutoLock auto_lock(lock_);
691 base::AutoLock auto_lock(lock_); 712 DemuxerStream* selected_stream = nullptr;
692 DCHECK(track_id_to_demux_stream_map_[track_ids[0]] == video_stream); 713 if (!track_ids.empty()) {
693 #endif 714 selected_stream = track_id_to_demux_stream_map_[track_ids[0]];
694 enabled = true; 715 DCHECK(selected_stream);
716 DCHECK_EQ(DemuxerStream::VIDEO, selected_stream->type());
695 } 717 }
696 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") 718
697 << " video stream"; 719 // First disable all streams that need to be disabled and then enable the
698 video_stream->set_enabled(enabled, currTime); 720 // stream that needs to be enabled (if any).
721 for (const auto& stream : video_streams_) {
722 if (stream->type() == DemuxerStream::VIDEO &&
723 stream.get() != selected_stream) {
724 DVLOG(1) << __func__ << ": disabling stream " << stream.get();
725 stream->set_enabled(false, currTime);
726 }
727 }
728 if (selected_stream) {
729 DVLOG(1) << __func__ << ": enabling stream " << selected_stream;
730 selected_stream->set_enabled(true, currTime);
731 }
699 } 732 }
700 733
701 bool ChunkDemuxer::EvictCodedFrames(const std::string& id, 734 bool ChunkDemuxer::EvictCodedFrames(const std::string& id,
702 base::TimeDelta currentMediaTime, 735 base::TimeDelta currentMediaTime,
703 size_t newDataSize) { 736 size_t newDataSize) {
704 DVLOG(1) << __func__ << "(" << id << ")" 737 DVLOG(1) << __func__ << "(" << id << ")"
705 << " media_time=" << currentMediaTime.InSecondsF() 738 << " media_time=" << currentMediaTime.InSecondsF()
706 << " newDataSize=" << newDataSize; 739 << " newDataSize=" << newDataSize;
707 base::AutoLock auto_lock(lock_); 740 base::AutoLock auto_lock(lock_);
708 741
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin(); 1071 for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin();
1039 itr != source_state_map_.end(); ++itr) { 1072 itr != source_state_map_.end(); ++itr) {
1040 if (itr->second->IsSeekWaitingForData()) 1073 if (itr->second->IsSeekWaitingForData())
1041 return true; 1074 return true;
1042 } 1075 }
1043 1076
1044 return false; 1077 return false;
1045 } 1078 }
1046 1079
1047 void ChunkDemuxer::OnSourceInitDone( 1080 void ChunkDemuxer::OnSourceInitDone(
1081 const std::string& source_id,
1048 const StreamParser::InitParameters& params) { 1082 const StreamParser::InitParameters& params) {
1049 DVLOG(1) << "OnSourceInitDone(" << params.duration.InSecondsF() << ")"; 1083 DVLOG(1) << "OnSourceInitDone source_id=" << source_id
1084 << " duration=" << params.duration.InSecondsF();
1050 lock_.AssertAcquired(); 1085 lock_.AssertAcquired();
1051 DCHECK_EQ(state_, INITIALIZING); 1086 DCHECK_EQ(state_, INITIALIZING);
1052 if (!audio_ && !video_) { 1087 DCHECK(pending_source_init_ids_.find(source_id) !=
1088 pending_source_init_ids_.end());
1089 if (audio_streams_.empty() && video_streams_.empty()) {
1053 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1090 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1054 return; 1091 return;
1055 } 1092 }
1056 1093
1057 if (!params.duration.is_zero() && duration_ == kNoTimestamp) 1094 if (!params.duration.is_zero() && duration_ == kNoTimestamp)
1058 UpdateDuration(params.duration); 1095 UpdateDuration(params.duration);
1059 1096
1060 if (!params.timeline_offset.is_null()) { 1097 if (!params.timeline_offset.is_null()) {
1061 if (!timeline_offset_.is_null() && 1098 if (!timeline_offset_.is_null() &&
1062 params.timeline_offset != timeline_offset_) { 1099 params.timeline_offset != timeline_offset_) {
1063 MEDIA_LOG(ERROR, media_log_) 1100 MEDIA_LOG(ERROR, media_log_)
1064 << "Timeline offset is not the same across all SourceBuffers."; 1101 << "Timeline offset is not the same across all SourceBuffers.";
1065 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1102 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1066 return; 1103 return;
1067 } 1104 }
1068 1105
1069 timeline_offset_ = params.timeline_offset; 1106 timeline_offset_ = params.timeline_offset;
1070 } 1107 }
1071 1108
1072 if (params.liveness != DemuxerStream::LIVENESS_UNKNOWN) { 1109 if (params.liveness != DemuxerStream::LIVENESS_UNKNOWN) {
1073 if (audio_) 1110 for (const auto& s : audio_streams_)
1074 audio_->SetLiveness(params.liveness); 1111 s->SetLiveness(params.liveness);
1075 if (video_) 1112 for (const auto& s : video_streams_)
1076 video_->SetLiveness(params.liveness); 1113 s->SetLiveness(params.liveness);
1077 } 1114 }
1078 1115
1079 detected_audio_track_count_ += params.detected_audio_track_count; 1116 detected_audio_track_count_ += params.detected_audio_track_count;
1080 detected_video_track_count_ += params.detected_video_track_count; 1117 detected_video_track_count_ += params.detected_video_track_count;
1081 detected_text_track_count_ += params.detected_text_track_count; 1118 detected_text_track_count_ += params.detected_text_track_count;
1082 1119
1083 // Wait until all streams have initialized. 1120 // Wait until all streams have initialized.
1084 pending_source_init_done_count_--; 1121 pending_source_init_ids_.erase(source_id);
1085 1122 if (!pending_source_init_ids_.empty())
1086 if (pending_source_init_done_count_ > 0)
1087 return; 1123 return;
1088 1124
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. 1125 // Record detected track counts by type corresponding to an MSE playback.
1094 // Counts are split into 50 buckets, capped into [0,100] range. 1126 // Counts are split into 50 buckets, capped into [0,100] range.
1095 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Audio", 1127 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Audio",
1096 detected_audio_track_count_); 1128 detected_audio_track_count_);
1097 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Video", 1129 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Video",
1098 detected_video_track_count_); 1130 detected_video_track_count_);
1099 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Text", 1131 UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Text",
1100 detected_text_track_count_); 1132 detected_text_track_count_);
1101 1133
1102 if (video_) { 1134 for (const auto& s : video_streams_) {
1103 media_log_->RecordRapporWithSecurityOrigin( 1135 media_log_->RecordRapporWithSecurityOrigin(
1104 "Media.OriginUrl.MSE.VideoCodec." + 1136 "Media.OriginUrl.MSE.VideoCodec." +
1105 GetCodecName(video_->video_decoder_config().codec())); 1137 GetCodecName(s->video_decoder_config().codec()));
1106 } 1138 }
1107 1139
1108 SeekAllSources(GetStartTime()); 1140 SeekAllSources(GetStartTime());
1109 StartReturningData(); 1141 StartReturningData();
1110 1142
1111 if (duration_ == kNoTimestamp) 1143 if (duration_ == kNoTimestamp)
1112 duration_ = kInfiniteDuration; 1144 duration_ = kInfiniteDuration;
1113 1145
1114 // The demuxer is now initialized after the |start_timestamp_| was set. 1146 // The demuxer is now initialized after the |start_timestamp_| was set.
1115 ChangeState_Locked(INITIALIZED); 1147 ChangeState_Locked(INITIALIZED);
1116 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 1148 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
1117 } 1149 }
1118 1150
1119 // static 1151 // static
1120 MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() { 1152 MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() {
1121 static unsigned g_track_count = 0; 1153 static unsigned g_track_count = 0;
1122 return base::UintToString(++g_track_count); 1154 return base::UintToString(++g_track_count);
1123 } 1155 }
1124 1156
1125 ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream( 1157 ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream(
1158 const std::string& source_id,
1126 DemuxerStream::Type type) { 1159 DemuxerStream::Type type) {
1127 // New ChunkDemuxerStreams can be created only during initialization segment 1160 // New ChunkDemuxerStreams can be created only during initialization segment
1128 // processing, which happens when a new chunk of data is appended and the 1161 // processing, which happens when a new chunk of data is appended and the
1129 // lock_ must be held by ChunkDemuxer::AppendData. 1162 // lock_ must be held by ChunkDemuxer::AppendData.
1130 lock_.AssertAcquired(); 1163 lock_.AssertAcquired();
1131 1164
1132 MediaTrack::Id media_track_id = GenerateMediaTrackId(); 1165 MediaTrack::Id media_track_id = GenerateMediaTrackId();
1133 1166
1134 switch (type) { 1167 switch (type) {
1135 case DemuxerStream::AUDIO: 1168 case DemuxerStream::AUDIO: {
1136 if (audio_) 1169 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)); 1170 DemuxerStream::AUDIO, splice_frames_enabled_, media_track_id));
1140 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) == 1171 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
1141 track_id_to_demux_stream_map_.end()); 1172 track_id_to_demux_stream_map_.end());
1142 track_id_to_demux_stream_map_[media_track_id] = audio_.get(); 1173 track_id_to_demux_stream_map_[media_track_id] = audio_stream.get();
1143 return audio_.get(); 1174 id_to_streams_map_[source_id].push_back(audio_stream.get());
1144 break; 1175 audio_streams_.push_back(std::move(audio_stream));
1145 case DemuxerStream::VIDEO: 1176 return audio_streams_.back().get();
1146 if (video_) 1177 }
1147 return NULL; 1178 case DemuxerStream::VIDEO: {
1148 video_.reset(new ChunkDemuxerStream( 1179 std::unique_ptr<ChunkDemuxerStream> video_stream(new ChunkDemuxerStream(
1149 DemuxerStream::VIDEO, splice_frames_enabled_, media_track_id)); 1180 DemuxerStream::VIDEO, splice_frames_enabled_, media_track_id));
1150 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) == 1181 DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
1151 track_id_to_demux_stream_map_.end()); 1182 track_id_to_demux_stream_map_.end());
1152 track_id_to_demux_stream_map_[media_track_id] = video_.get(); 1183 track_id_to_demux_stream_map_[media_track_id] = video_stream.get();
1153 return video_.get(); 1184 id_to_streams_map_[source_id].push_back(video_stream.get());
1154 break; 1185 video_streams_.push_back(std::move(video_stream));
1186 return video_streams_.back().get();
1187 }
1155 case DemuxerStream::TEXT: { 1188 case DemuxerStream::TEXT: {
1156 return new ChunkDemuxerStream(DemuxerStream::TEXT, splice_frames_enabled_, 1189 ChunkDemuxerStream* text_stream = new ChunkDemuxerStream(
1157 media_track_id); 1190 DemuxerStream::TEXT, splice_frames_enabled_, media_track_id);
1158 break; 1191 id_to_streams_map_[source_id].push_back(text_stream);
1192 return text_stream;
1159 } 1193 }
1160 case DemuxerStream::UNKNOWN: 1194 case DemuxerStream::UNKNOWN:
1161 case DemuxerStream::NUM_TYPES: 1195 case DemuxerStream::NUM_TYPES:
1162 NOTREACHED(); 1196 NOTREACHED();
1163 return NULL; 1197 return NULL;
1164 } 1198 }
1165 NOTREACHED(); 1199 NOTREACHED();
1166 return NULL; 1200 return NULL;
1167 } 1201 }
1168 1202
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 } 1306 }
1273 1307
1274 void ChunkDemuxer::ShutdownAllStreams() { 1308 void ChunkDemuxer::ShutdownAllStreams() {
1275 for (MediaSourceStateMap::iterator itr = source_state_map_.begin(); 1309 for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
1276 itr != source_state_map_.end(); ++itr) { 1310 itr != source_state_map_.end(); ++itr) {
1277 itr->second->Shutdown(); 1311 itr->second->Shutdown();
1278 } 1312 }
1279 } 1313 }
1280 1314
1281 } // namespace media 1315 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698