OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |