Chromium Code Reviews| 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_); |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |