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 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 scoped_ptr<StreamParser> stream_parser(factory_function(codecs)); | 654 scoped_ptr<StreamParser> stream_parser(factory_function(codecs)); |
655 CHECK(stream_parser.get()); | 655 CHECK(stream_parser.get()); |
656 | 656 |
657 stream_parser->Init( | 657 stream_parser->Init( |
658 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), | 658 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), |
659 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 659 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), |
660 has_audio, has_video), | 660 has_audio, has_video), |
661 audio_cb, | 661 audio_cb, |
662 video_cb, | 662 video_cb, |
663 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 663 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
664 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); | 664 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
665 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, | |
666 base::Unretained(this), id)); | |
665 | 667 |
666 stream_parser_map_[id] = stream_parser.release(); | 668 stream_parser_map_[id] = stream_parser.release(); |
669 SourceInfo info = { base::TimeDelta(), true }; | |
670 source_info_map_[id] = info; | |
667 | 671 |
668 return kOk; | 672 return kOk; |
669 } | 673 } |
670 | 674 |
671 void ChunkDemuxer::RemoveId(const std::string& id) { | 675 void ChunkDemuxer::RemoveId(const std::string& id) { |
672 CHECK_GT(stream_parser_map_.count(id), 0u); | 676 CHECK_GT(stream_parser_map_.count(id), 0u); |
673 base::AutoLock auto_lock(lock_); | 677 base::AutoLock auto_lock(lock_); |
674 | 678 |
675 delete stream_parser_map_[id]; | 679 delete stream_parser_map_[id]; |
676 stream_parser_map_.erase(id); | 680 stream_parser_map_.erase(id); |
681 source_info_map_.erase(id); | |
677 | 682 |
678 if (source_id_audio_ == id && audio_) | 683 if (source_id_audio_ == id && audio_) |
679 audio_->Shutdown(); | 684 audio_->Shutdown(); |
680 | 685 |
681 if (source_id_video_ == id && video_) | 686 if (source_id_video_ == id && video_) |
682 video_->Shutdown(); | 687 video_->Shutdown(); |
683 } | 688 } |
684 | 689 |
685 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { | 690 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
686 DCHECK(!id.empty()); | 691 DCHECK(!id.empty()); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
802 } | 807 } |
803 | 808 |
804 void ChunkDemuxer::Abort(const std::string& id) { | 809 void ChunkDemuxer::Abort(const std::string& id) { |
805 DVLOG(1) << "Abort(" << id << ")"; | 810 DVLOG(1) << "Abort(" << id << ")"; |
806 DCHECK(!id.empty()); | 811 DCHECK(!id.empty()); |
807 DCHECK_GT(stream_parser_map_.count(id), 0u); | 812 DCHECK_GT(stream_parser_map_.count(id), 0u); |
808 | 813 |
809 stream_parser_map_[id]->Flush(); | 814 stream_parser_map_[id]->Flush(); |
810 } | 815 } |
811 | 816 |
817 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, float offset) { | |
818 DVLOG(1) << "TimestampOffset(" << id << ", " << offset << ")"; | |
acolwell GONE FROM CHROMIUM
2012/07/25 18:22:43
nit: Add Set
vrk (LEFT CHROMIUM)
2012/07/25 22:56:50
Done.
| |
819 DCHECK_GT(stream_parser_map_.count(id), 0u); | |
820 | |
821 TimeDelta time_offset = TimeDelta::FromMicroseconds( | |
822 offset * base::Time::kMicrosecondsPerSecond); | |
823 | |
824 if (!source_info_map_[id].can_update_offset) | |
acolwell GONE FROM CHROMIUM
2012/07/25 18:22:43
nit: move this above time_offset since we don't ne
vrk (LEFT CHROMIUM)
2012/07/25 22:56:50
Done.
| |
825 return false; | |
826 | |
827 source_info_map_[id].timestamp_offset = time_offset; | |
828 return true; | |
829 } | |
830 | |
812 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { | 831 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { |
813 DVLOG(1) << "EndOfStream(" << status << ")"; | 832 DVLOG(1) << "EndOfStream(" << status << ")"; |
814 base::AutoLock auto_lock(lock_); | 833 base::AutoLock auto_lock(lock_); |
815 DCHECK_NE(state_, WAITING_FOR_INIT); | 834 DCHECK_NE(state_, WAITING_FOR_INIT); |
816 DCHECK_NE(state_, ENDED); | 835 DCHECK_NE(state_, ENDED); |
817 | 836 |
818 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 837 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
819 return true; | 838 return true; |
820 | 839 |
821 if (state_ == INITIALIZING) { | 840 if (state_ == INITIALIZING) { |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1006 return success; | 1025 return success; |
1007 } | 1026 } |
1008 | 1027 |
1009 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { | 1028 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
1010 lock_.AssertAcquired(); | 1029 lock_.AssertAcquired(); |
1011 DCHECK_NE(state_, SHUTDOWN); | 1030 DCHECK_NE(state_, SHUTDOWN); |
1012 | 1031 |
1013 if (!audio_) | 1032 if (!audio_) |
1014 return false; | 1033 return false; |
1015 | 1034 |
1035 CHECK_GT(source_info_map_.count(source_id_audio_), 0u); | |
1036 AdjustBufferTimestamps( | |
1037 buffers, source_info_map_[source_id_audio_].timestamp_offset); | |
1038 | |
1016 return audio_->Append(buffers); | 1039 return audio_->Append(buffers); |
1017 } | 1040 } |
1018 | 1041 |
1019 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { | 1042 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
1020 lock_.AssertAcquired(); | 1043 lock_.AssertAcquired(); |
1021 DCHECK_NE(state_, SHUTDOWN); | 1044 DCHECK_NE(state_, SHUTDOWN); |
1022 | 1045 |
1023 if (!video_) | 1046 if (!video_) |
1024 return false; | 1047 return false; |
1025 | 1048 |
1049 CHECK_GT(source_info_map_.count(source_id_video_), 0u); | |
1050 AdjustBufferTimestamps( | |
1051 buffers, source_info_map_[source_id_video_].timestamp_offset); | |
1052 | |
1026 return video_->Append(buffers); | 1053 return video_->Append(buffers); |
1027 } | 1054 } |
1028 | 1055 |
1029 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, | 1056 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, |
1030 int init_data_size) { | 1057 int init_data_size) { |
1031 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); | 1058 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); |
1032 return true; | 1059 return true; |
1033 } | 1060 } |
1034 | 1061 |
1035 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, | 1062 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
1036 TimeDelta start_timestamp) { | 1063 TimeDelta timestamp) { |
1037 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " | 1064 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " |
1038 << start_timestamp.InSecondsF() << ")"; | 1065 << timestamp.InSecondsF() << ")"; |
1039 lock_.AssertAcquired(); | 1066 lock_.AssertAcquired(); |
1040 | 1067 |
1068 CHECK_GT(source_info_map_.count(source_id), 0u); | |
acolwell GONE FROM CHROMIUM
2012/07/25 18:22:43
nit: Create a bool IsValidId(source_id) helper so
vrk (LEFT CHROMIUM)
2012/07/25 22:56:50
Done.
| |
1069 source_info_map_[source_id].can_update_offset = false; | |
1070 base::TimeDelta start_timestamp = | |
1071 timestamp + source_info_map_[source_id].timestamp_offset; | |
1072 | |
1041 if (start_time_ == kNoTimestamp()) { | 1073 if (start_time_ == kNoTimestamp()) { |
1042 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); | 1074 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); |
1043 // Use the first reported media segment start time as the |start_time_| | 1075 // Use the first reported media segment start time as the |start_time_| |
1044 // for the demuxer. | 1076 // for the demuxer. |
1045 start_time_ = start_timestamp; | 1077 start_time_ = start_timestamp; |
1046 } | 1078 } |
1047 | 1079 |
1048 if (audio_ && source_id == source_id_audio_) | 1080 if (audio_ && source_id == source_id_audio_) |
1049 audio_->OnNewMediaSegment(start_timestamp); | 1081 audio_->OnNewMediaSegment(start_timestamp); |
1050 if (video_ && source_id == source_id_video_) | 1082 if (video_ && source_id == source_id_video_) |
1051 video_->OnNewMediaSegment(start_timestamp); | 1083 video_->OnNewMediaSegment(start_timestamp); |
1052 | 1084 |
1053 if (state_ != WAITING_FOR_START_TIME) | 1085 if (state_ != WAITING_FOR_START_TIME) |
1054 return; | 1086 return; |
1055 | 1087 |
1056 if (audio_) { | 1088 if (audio_) { |
1057 audio_->SetStartTime(start_time_); | 1089 audio_->SetStartTime(start_time_); |
1058 audio_->Seek(start_time_); | 1090 audio_->Seek(start_time_); |
1059 } | 1091 } |
1060 if (video_) { | 1092 if (video_) { |
1061 video_->SetStartTime(start_time_); | 1093 video_->SetStartTime(start_time_); |
1062 video_->Seek(start_time_); | 1094 video_->Seek(start_time_); |
1063 } | 1095 } |
1064 | 1096 |
1065 // The demuxer is now initialized after the |start_timestamp_| was set. | 1097 // The demuxer is now initialized after the |start_timestamp_| was set. |
1066 ChangeState_Locked(INITIALIZED); | 1098 ChangeState_Locked(INITIALIZED); |
1067 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1099 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
1068 } | 1100 } |
1069 | 1101 |
1102 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { | |
1103 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; | |
1104 CHECK_GT(source_info_map_.count(source_id), 0u); | |
1105 source_info_map_[source_id].can_update_offset = true; | |
1106 } | |
1107 | |
1108 void ChunkDemuxer::AdjustBufferTimestamps( | |
1109 const StreamParser::BufferQueue& buffers, | |
1110 base::TimeDelta timestamp_offset) { | |
1111 if (timestamp_offset == base::TimeDelta()) | |
1112 return; | |
1113 | |
1114 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | |
1115 itr != buffers.end(); ++itr) { | |
1116 (*itr)->SetDecodeTimestamp( | |
1117 (*itr)->GetDecodeTimestamp() + timestamp_offset); | |
1118 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); | |
1119 } | |
1120 } | |
1121 | |
1070 } // namespace media | 1122 } // namespace media |
OLD | NEW |