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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 // and |has_video| are undefined. | 104 // and |has_video| are undefined. |
105 static bool IsSupported(const std::string& type, | 105 static bool IsSupported(const std::string& type, |
106 std::vector<std::string>& codecs, | 106 std::vector<std::string>& codecs, |
107 ParserFactoryFunction* factory_function, | 107 ParserFactoryFunction* factory_function, |
108 bool* has_audio, | 108 bool* has_audio, |
109 bool* has_video) { | 109 bool* has_video) { |
110 *factory_function = NULL; | 110 *factory_function = NULL; |
111 *has_audio = false; | 111 *has_audio = false; |
112 *has_video = false; | 112 *has_video = false; |
113 | 113 |
114 // Search for the SupportedTypeInfo for |type| | 114 // Search for the SupportedTypeInfo for |type|. |
115 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { | 115 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { |
116 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; | 116 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; |
117 if (type == type_info.type) { | 117 if (type == type_info.type) { |
118 // Make sure all the codecs specified in |codecs| are | 118 // Make sure all the codecs specified in |codecs| are |
119 // in the supported type info. | 119 // in the supported type info. |
120 for (size_t j = 0; j < codecs.size(); ++j) { | 120 for (size_t j = 0; j < codecs.size(); ++j) { |
121 // Search the type info for a match. | 121 // Search the type info for a match. |
122 bool found_codec = false; | 122 bool found_codec = false; |
123 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; | 123 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; |
124 | 124 |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 scoped_ptr<StreamParser> stream_parser(factory_function(codecs)); | 630 scoped_ptr<StreamParser> stream_parser(factory_function(codecs)); |
631 CHECK(stream_parser.get()); | 631 CHECK(stream_parser.get()); |
632 | 632 |
633 stream_parser->Init( | 633 stream_parser->Init( |
634 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)), | 634 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)), |
635 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 635 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), |
636 has_audio, has_video), | 636 has_audio, has_video), |
637 audio_cb, | 637 audio_cb, |
638 video_cb, | 638 video_cb, |
639 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 639 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
640 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); | 640 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
| 641 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, |
| 642 base::Unretained(this), id)); |
641 | 643 |
642 stream_parser_map_[id] = stream_parser.release(); | 644 stream_parser_map_[id] = stream_parser.release(); |
| 645 SourceInfo info = { base::TimeDelta(), true }; |
| 646 source_info_map_[id] = info; |
643 | 647 |
644 return kOk; | 648 return kOk; |
645 } | 649 } |
646 | 650 |
647 void ChunkDemuxer::RemoveId(const std::string& id) { | 651 void ChunkDemuxer::RemoveId(const std::string& id) { |
648 CHECK_GT(stream_parser_map_.count(id), 0u); | 652 CHECK(IsValidId(id)); |
649 base::AutoLock auto_lock(lock_); | 653 base::AutoLock auto_lock(lock_); |
650 | 654 |
651 delete stream_parser_map_[id]; | 655 delete stream_parser_map_[id]; |
652 stream_parser_map_.erase(id); | 656 stream_parser_map_.erase(id); |
| 657 source_info_map_.erase(id); |
653 | 658 |
654 if (source_id_audio_ == id && audio_) | 659 if (source_id_audio_ == id && audio_) |
655 audio_->Shutdown(); | 660 audio_->Shutdown(); |
656 | 661 |
657 if (source_id_video_ == id && video_) | 662 if (source_id_video_ == id && video_) |
658 video_->Shutdown(); | 663 video_->Shutdown(); |
659 } | 664 } |
660 | 665 |
661 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { | 666 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
662 DCHECK(!id.empty()); | 667 DCHECK(!id.empty()); |
663 DCHECK_GT(stream_parser_map_.count(id), 0u); | 668 DCHECK(IsValidId(id)); |
664 DCHECK(id == source_id_audio_ || id == source_id_video_); | 669 DCHECK(id == source_id_audio_ || id == source_id_video_); |
665 | 670 |
666 base::AutoLock auto_lock(lock_); | 671 base::AutoLock auto_lock(lock_); |
667 | 672 |
668 if (id == source_id_audio_ && id != source_id_video_) { | 673 if (id == source_id_audio_ && id != source_id_video_) { |
669 // Only include ranges that have been buffered in |audio_| | 674 // Only include ranges that have been buffered in |audio_| |
670 return audio_ ? audio_->GetBufferedRanges() : Ranges<TimeDelta>(); | 675 return audio_ ? audio_->GetBufferedRanges() : Ranges<TimeDelta>(); |
671 } | 676 } |
672 | 677 |
673 if (id != source_id_audio_ && id == source_id_video_) { | 678 if (id != source_id_audio_ && id == source_id_video_) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 PipelineStatusCB cb; | 728 PipelineStatusCB cb; |
724 { | 729 { |
725 base::AutoLock auto_lock(lock_); | 730 base::AutoLock auto_lock(lock_); |
726 | 731 |
727 // Capture if the SourceBuffer has a pending seek before we start parsing. | 732 // Capture if the SourceBuffer has a pending seek before we start parsing. |
728 bool old_seek_pending = IsSeekPending_Locked(); | 733 bool old_seek_pending = IsSeekPending_Locked(); |
729 | 734 |
730 switch (state_) { | 735 switch (state_) { |
731 case INITIALIZING: | 736 case INITIALIZING: |
732 case WAITING_FOR_START_TIME: | 737 case WAITING_FOR_START_TIME: |
733 DCHECK_GT(stream_parser_map_.count(id), 0u); | 738 DCHECK(IsValidId(id)); |
734 if (!stream_parser_map_[id]->Parse(data, length)) { | 739 if (!stream_parser_map_[id]->Parse(data, length)) { |
735 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 740 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
736 return true; | 741 return true; |
737 } | 742 } |
738 break; | 743 break; |
739 | 744 |
740 case INITIALIZED: { | 745 case INITIALIZED: { |
741 DCHECK_GT(stream_parser_map_.count(id), 0u); | 746 DCHECK(IsValidId(id)); |
742 if (!stream_parser_map_[id]->Parse(data, length)) { | 747 if (!stream_parser_map_[id]->Parse(data, length)) { |
743 ReportError_Locked(PIPELINE_ERROR_DECODE); | 748 ReportError_Locked(PIPELINE_ERROR_DECODE); |
744 return true; | 749 return true; |
745 } | 750 } |
746 } break; | 751 } break; |
747 | 752 |
748 case WAITING_FOR_INIT: | 753 case WAITING_FOR_INIT: |
749 case ENDED: | 754 case ENDED: |
750 case PARSE_ERROR: | 755 case PARSE_ERROR: |
751 case SHUTDOWN: | 756 case SHUTDOWN: |
(...skipping 21 matching lines...) Expand all Loading... |
773 | 778 |
774 if (!cb.is_null()) | 779 if (!cb.is_null()) |
775 cb.Run(PIPELINE_OK); | 780 cb.Run(PIPELINE_OK); |
776 | 781 |
777 return true; | 782 return true; |
778 } | 783 } |
779 | 784 |
780 void ChunkDemuxer::Abort(const std::string& id) { | 785 void ChunkDemuxer::Abort(const std::string& id) { |
781 DVLOG(1) << "Abort(" << id << ")"; | 786 DVLOG(1) << "Abort(" << id << ")"; |
782 DCHECK(!id.empty()); | 787 DCHECK(!id.empty()); |
783 DCHECK_GT(stream_parser_map_.count(id), 0u); | 788 CHECK(IsValidId(id)); |
784 | 789 |
785 stream_parser_map_[id]->Flush(); | 790 stream_parser_map_[id]->Flush(); |
786 } | 791 } |
787 | 792 |
| 793 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, double offset) { |
| 794 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset << ")"; |
| 795 CHECK(IsValidId(id)); |
| 796 |
| 797 if (!source_info_map_[id].can_update_offset) |
| 798 return false; |
| 799 |
| 800 TimeDelta time_offset = TimeDelta::FromMicroseconds( |
| 801 offset * base::Time::kMicrosecondsPerSecond); |
| 802 source_info_map_[id].timestamp_offset = time_offset; |
| 803 return true; |
| 804 } |
| 805 |
788 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { | 806 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { |
789 DVLOG(1) << "EndOfStream(" << status << ")"; | 807 DVLOG(1) << "EndOfStream(" << status << ")"; |
790 base::AutoLock auto_lock(lock_); | 808 base::AutoLock auto_lock(lock_); |
791 DCHECK_NE(state_, WAITING_FOR_INIT); | 809 DCHECK_NE(state_, WAITING_FOR_INIT); |
792 DCHECK_NE(state_, ENDED); | 810 DCHECK_NE(state_, ENDED); |
793 | 811 |
794 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 812 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
795 return true; | 813 return true; |
796 | 814 |
797 if (state_ == INITIALIZING) { | 815 if (state_ == INITIALIZING) { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
976 return success; | 994 return success; |
977 } | 995 } |
978 | 996 |
979 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { | 997 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
980 lock_.AssertAcquired(); | 998 lock_.AssertAcquired(); |
981 DCHECK_NE(state_, SHUTDOWN); | 999 DCHECK_NE(state_, SHUTDOWN); |
982 | 1000 |
983 if (!audio_) | 1001 if (!audio_) |
984 return false; | 1002 return false; |
985 | 1003 |
| 1004 CHECK(IsValidId(source_id_audio_)); |
| 1005 AdjustBufferTimestamps( |
| 1006 buffers, source_info_map_[source_id_audio_].timestamp_offset); |
| 1007 |
986 return audio_->Append(buffers); | 1008 return audio_->Append(buffers); |
987 } | 1009 } |
988 | 1010 |
989 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { | 1011 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
990 lock_.AssertAcquired(); | 1012 lock_.AssertAcquired(); |
991 DCHECK_NE(state_, SHUTDOWN); | 1013 DCHECK_NE(state_, SHUTDOWN); |
992 | 1014 |
993 if (!video_) | 1015 if (!video_) |
994 return false; | 1016 return false; |
995 | 1017 |
| 1018 CHECK(IsValidId(source_id_video_)); |
| 1019 AdjustBufferTimestamps( |
| 1020 buffers, source_info_map_[source_id_video_].timestamp_offset); |
| 1021 |
996 return video_->Append(buffers); | 1022 return video_->Append(buffers); |
997 } | 1023 } |
998 | 1024 |
999 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, | 1025 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, |
1000 int init_data_size) { | 1026 int init_data_size) { |
1001 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); | 1027 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); |
1002 return true; | 1028 return true; |
1003 } | 1029 } |
1004 | 1030 |
1005 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, | 1031 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
1006 TimeDelta start_timestamp) { | 1032 TimeDelta timestamp) { |
1007 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " | 1033 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " |
1008 << start_timestamp.InSecondsF() << ")"; | 1034 << timestamp.InSecondsF() << ")"; |
1009 lock_.AssertAcquired(); | 1035 lock_.AssertAcquired(); |
1010 | 1036 |
| 1037 CHECK(IsValidId(source_id)); |
| 1038 source_info_map_[source_id].can_update_offset = false; |
| 1039 base::TimeDelta start_timestamp = |
| 1040 timestamp + source_info_map_[source_id].timestamp_offset; |
| 1041 |
1011 if (start_time_ == kNoTimestamp()) { | 1042 if (start_time_ == kNoTimestamp()) { |
1012 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); | 1043 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); |
1013 // Use the first reported media segment start time as the |start_time_| | 1044 // Use the first reported media segment start time as the |start_time_| |
1014 // for the demuxer. | 1045 // for the demuxer. |
1015 start_time_ = start_timestamp; | 1046 start_time_ = start_timestamp; |
1016 } | 1047 } |
1017 | 1048 |
1018 if (audio_ && source_id == source_id_audio_) | 1049 if (audio_ && source_id == source_id_audio_) |
1019 audio_->OnNewMediaSegment(start_timestamp); | 1050 audio_->OnNewMediaSegment(start_timestamp); |
1020 if (video_ && source_id == source_id_video_) | 1051 if (video_ && source_id == source_id_video_) |
1021 video_->OnNewMediaSegment(start_timestamp); | 1052 video_->OnNewMediaSegment(start_timestamp); |
1022 | 1053 |
1023 if (state_ != WAITING_FOR_START_TIME) | 1054 if (state_ != WAITING_FOR_START_TIME) |
1024 return; | 1055 return; |
1025 | 1056 |
1026 if (audio_) { | 1057 if (audio_) { |
1027 audio_->SetStartTime(start_time_); | 1058 audio_->SetStartTime(start_time_); |
1028 audio_->Seek(start_time_); | 1059 audio_->Seek(start_time_); |
1029 } | 1060 } |
1030 if (video_) { | 1061 if (video_) { |
1031 video_->SetStartTime(start_time_); | 1062 video_->SetStartTime(start_time_); |
1032 video_->Seek(start_time_); | 1063 video_->Seek(start_time_); |
1033 } | 1064 } |
1034 | 1065 |
1035 // The demuxer is now initialized after the |start_timestamp_| was set. | 1066 // The demuxer is now initialized after the |start_timestamp_| was set. |
1036 ChangeState_Locked(INITIALIZED); | 1067 ChangeState_Locked(INITIALIZED); |
1037 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1068 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
1038 } | 1069 } |
1039 | 1070 |
| 1071 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { |
| 1072 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; |
| 1073 CHECK(IsValidId(source_id)); |
| 1074 source_info_map_[source_id].can_update_offset = true; |
| 1075 } |
| 1076 |
| 1077 void ChunkDemuxer::AdjustBufferTimestamps( |
| 1078 const StreamParser::BufferQueue& buffers, |
| 1079 base::TimeDelta timestamp_offset) { |
| 1080 if (timestamp_offset == base::TimeDelta()) |
| 1081 return; |
| 1082 |
| 1083 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 1084 itr != buffers.end(); ++itr) { |
| 1085 (*itr)->SetDecodeTimestamp( |
| 1086 (*itr)->GetDecodeTimestamp() + timestamp_offset); |
| 1087 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); |
| 1088 } |
| 1089 } |
| 1090 |
| 1091 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
| 1092 return source_info_map_.count(source_id) > 0u && |
| 1093 stream_parser_map_.count(source_id) > 0u; |
| 1094 } |
| 1095 |
1040 } // namespace media | 1096 } // namespace media |
OLD | NEW |