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 <deque> | 8 #include <deque> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 // Checks to see if the specified |type| and |codecs| list are supported. | 100 // Checks to see if the specified |type| and |codecs| list are supported. |
101 // Returns true if |type| and all codecs listed in |codecs| are supported. | 101 // Returns true if |type| and all codecs listed in |codecs| are supported. |
102 // |factory_function| contains a function that can build a StreamParser | 102 // |factory_function| contains a function that can build a StreamParser |
103 // for this type. | 103 // for this type. |
104 // |has_audio| is true if an audio codec was specified. | 104 // |has_audio| is true if an audio codec was specified. |
105 // |has_video| is true if a video codec was specified. | 105 // |has_video| is true if a video codec was specified. |
106 // Returns false otherwise. The values of |factory_function|, |has_audio|, | 106 // Returns false otherwise. The values of |factory_function|, |has_audio|, |
107 // and |has_video| are undefined. | 107 // and |has_video| are undefined. |
108 static bool IsSupported(const std::string& type, | 108 static bool IsSupported(const std::string& type, |
109 std::vector<std::string>& codecs, | 109 std::vector<std::string>& codecs, |
| 110 const LogCB& log_cb, |
110 ParserFactoryFunction* factory_function, | 111 ParserFactoryFunction* factory_function, |
111 bool* has_audio, | 112 bool* has_audio, |
112 bool* has_video) { | 113 bool* has_video) { |
113 *factory_function = NULL; | 114 *factory_function = NULL; |
114 *has_audio = false; | 115 *has_audio = false; |
115 *has_video = false; | 116 *has_video = false; |
116 | 117 |
117 // Search for the SupportedTypeInfo for |type|. | 118 // Search for the SupportedTypeInfo for |type|. |
118 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { | 119 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { |
119 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; | 120 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; |
120 if (type == type_info.type) { | 121 if (type == type_info.type) { |
121 // Make sure all the codecs specified in |codecs| are | 122 // Make sure all the codecs specified in |codecs| are |
122 // in the supported type info. | 123 // in the supported type info. |
123 for (size_t j = 0; j < codecs.size(); ++j) { | 124 for (size_t j = 0; j < codecs.size(); ++j) { |
124 // Search the type info for a match. | 125 // Search the type info for a match. |
125 bool found_codec = false; | 126 bool found_codec = false; |
126 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; | 127 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; |
127 | 128 |
128 for (int k = 0; type_info.codecs[k]; ++k) { | 129 for (int k = 0; type_info.codecs[k]; ++k) { |
129 if (MatchPattern(codecs[j], type_info.codecs[k]->pattern)) { | 130 if (MatchPattern(codecs[j], type_info.codecs[k]->pattern)) { |
130 found_codec = true; | 131 found_codec = true; |
131 codec_type = type_info.codecs[k]->type; | 132 codec_type = type_info.codecs[k]->type; |
132 break; | 133 break; |
133 } | 134 } |
134 } | 135 } |
135 | 136 |
136 if (!found_codec) | 137 if (!found_codec) { |
| 138 MEDIA_LOG(log_cb) << "Codec '" << codecs[j] |
| 139 <<"' is not supported for '" << type << "'"; |
137 return false; | 140 return false; |
| 141 } |
138 | 142 |
139 switch (codec_type) { | 143 switch (codec_type) { |
140 case DemuxerStream::AUDIO: | 144 case DemuxerStream::AUDIO: |
141 *has_audio = true; | 145 *has_audio = true; |
142 break; | 146 break; |
143 case DemuxerStream::VIDEO: | 147 case DemuxerStream::VIDEO: |
144 *has_video = true; | 148 *has_video = true; |
145 break; | 149 break; |
146 default: | 150 default: |
147 DVLOG(1) << "Unsupported codec type '"<< codec_type << "' for " | 151 MEDIA_LOG(log_cb) << "Unsupported codec type '"<< codec_type |
148 << codecs[j]; | 152 << "' for " << codecs[j]; |
149 return false; | 153 return false; |
150 } | 154 } |
151 } | 155 } |
152 | 156 |
153 *factory_function = type_info.factory_function; | 157 *factory_function = type_info.factory_function; |
154 | 158 |
155 // All codecs were supported by this |type|. | 159 // All codecs were supported by this |type|. |
156 return true; | 160 return true; |
157 } | 161 } |
158 } | 162 } |
159 | 163 |
160 // |type| didn't match any of the supported types. | 164 // |type| didn't match any of the supported types. |
161 return false; | 165 return false; |
162 } | 166 } |
163 | 167 |
164 class ChunkDemuxerStream : public DemuxerStream { | 168 class ChunkDemuxerStream : public DemuxerStream { |
165 public: | 169 public: |
166 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 170 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
167 typedef std::deque<ReadCB> ReadCBQueue; | 171 typedef std::deque<ReadCB> ReadCBQueue; |
168 typedef std::deque<base::Closure> ClosureQueue; | 172 typedef std::deque<base::Closure> ClosureQueue; |
169 | 173 |
170 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config); | 174 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
171 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config); | 175 const LogCB& log_cb); |
| 176 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 177 const LogCB& log_cb); |
172 | 178 |
173 void StartWaitingForSeek(); | 179 void StartWaitingForSeek(); |
174 void Seek(TimeDelta time); | 180 void Seek(TimeDelta time); |
175 void CancelPendingSeek(); | 181 void CancelPendingSeek(); |
176 bool IsSeekPending() const; | 182 bool IsSeekPending() const; |
177 | 183 |
178 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, | 184 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
179 // which handle ordering and overlap resolution. | 185 // which handle ordering and overlap resolution. |
180 // Returns true if buffers were successfully added. | 186 // Returns true if buffers were successfully added. |
181 bool Append(const StreamParser::BufferQueue& buffers); | 187 bool Append(const StreamParser::BufferQueue& buffers); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 scoped_ptr<SourceBufferStream> stream_; | 247 scoped_ptr<SourceBufferStream> stream_; |
242 | 248 |
243 mutable base::Lock lock_; | 249 mutable base::Lock lock_; |
244 State state_; | 250 State state_; |
245 ReadCBQueue read_cbs_; | 251 ReadCBQueue read_cbs_; |
246 bool end_of_stream_; | 252 bool end_of_stream_; |
247 | 253 |
248 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 254 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
249 }; | 255 }; |
250 | 256 |
251 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) | 257 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 258 const LogCB& log_cb) |
252 : type_(AUDIO), | 259 : type_(AUDIO), |
253 state_(RETURNING_DATA_FOR_READS), | 260 state_(RETURNING_DATA_FOR_READS), |
254 end_of_stream_(false) { | 261 end_of_stream_(false) { |
255 stream_.reset(new SourceBufferStream(audio_config)); | 262 stream_.reset(new SourceBufferStream(audio_config, log_cb)); |
256 } | 263 } |
257 | 264 |
258 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config) | 265 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 266 const LogCB& log_cb) |
259 : type_(VIDEO), | 267 : type_(VIDEO), |
260 state_(RETURNING_DATA_FOR_READS), | 268 state_(RETURNING_DATA_FOR_READS), |
261 end_of_stream_(false) { | 269 end_of_stream_(false) { |
262 stream_.reset(new SourceBufferStream(video_config)); | 270 stream_.reset(new SourceBufferStream(video_config, log_cb)); |
263 } | 271 } |
264 | 272 |
265 void ChunkDemuxerStream::StartWaitingForSeek() { | 273 void ChunkDemuxerStream::StartWaitingForSeek() { |
266 DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; | 274 DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; |
267 ReadCBQueue read_cbs; | 275 ReadCBQueue read_cbs; |
268 { | 276 { |
269 base::AutoLock auto_lock(lock_); | 277 base::AutoLock auto_lock(lock_); |
270 if (state_ != CANCELED) | 278 if (state_ != CANCELED) |
271 end_of_stream_ = false; | 279 end_of_stream_ = false; |
272 ChangeState_Locked(WAITING_FOR_SEEK); | 280 ChangeState_Locked(WAITING_FOR_SEEK); |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 *status = DemuxerStream::kOk; | 534 *status = DemuxerStream::kOk; |
527 *buffer = StreamParserBuffer::CreateEOSBuffer(); | 535 *buffer = StreamParserBuffer::CreateEOSBuffer(); |
528 return true; | 536 return true; |
529 } | 537 } |
530 | 538 |
531 NOTREACHED(); | 539 NOTREACHED(); |
532 return false; | 540 return false; |
533 } | 541 } |
534 | 542 |
535 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, | 543 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, |
536 const NeedKeyCB& need_key_cb) | 544 const NeedKeyCB& need_key_cb, |
| 545 const LogCB& log_cb) |
537 : state_(WAITING_FOR_INIT), | 546 : state_(WAITING_FOR_INIT), |
538 host_(NULL), | 547 host_(NULL), |
539 open_cb_(open_cb), | 548 open_cb_(open_cb), |
540 need_key_cb_(need_key_cb) { | 549 need_key_cb_(need_key_cb), |
| 550 log_cb_(log_cb) { |
541 DCHECK(!open_cb_.is_null()); | 551 DCHECK(!open_cb_.is_null()); |
542 DCHECK(!need_key_cb_.is_null()); | 552 DCHECK(!need_key_cb_.is_null()); |
543 } | 553 } |
544 | 554 |
545 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { | 555 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { |
546 DVLOG(1) << "Init()"; | 556 DVLOG(1) << "Init()"; |
547 | 557 |
548 base::AutoLock auto_lock(lock_); | 558 base::AutoLock auto_lock(lock_); |
549 DCHECK_EQ(state_, WAITING_FOR_INIT); | 559 DCHECK_EQ(state_, WAITING_FOR_INIT); |
550 host_ = host; | 560 host_ = host; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 DCHECK_GT(codecs.size(), 0u); | 665 DCHECK_GT(codecs.size(), 0u); |
656 base::AutoLock auto_lock(lock_); | 666 base::AutoLock auto_lock(lock_); |
657 | 667 |
658 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || | 668 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || |
659 stream_parser_map_.count(id) > 0u) | 669 stream_parser_map_.count(id) > 0u) |
660 return kReachedIdLimit; | 670 return kReachedIdLimit; |
661 | 671 |
662 bool has_audio = false; | 672 bool has_audio = false; |
663 bool has_video = false; | 673 bool has_video = false; |
664 ParserFactoryFunction factory_function = NULL; | 674 ParserFactoryFunction factory_function = NULL; |
665 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video)) | 675 std::string error; |
| 676 if (!IsSupported(type, codecs, log_cb_, &factory_function, &has_audio, |
| 677 &has_video)) { |
666 return kNotSupported; | 678 return kNotSupported; |
| 679 } |
667 | 680 |
668 if ((has_audio && !source_id_audio_.empty()) || | 681 if ((has_audio && !source_id_audio_.empty()) || |
669 (has_video && !source_id_video_.empty())) | 682 (has_video && !source_id_video_.empty())) |
670 return kReachedIdLimit; | 683 return kReachedIdLimit; |
671 | 684 |
672 StreamParser::NewBuffersCB audio_cb; | 685 StreamParser::NewBuffersCB audio_cb; |
673 StreamParser::NewBuffersCB video_cb; | 686 StreamParser::NewBuffersCB video_cb; |
674 | 687 |
675 if (has_audio) { | 688 if (has_audio) { |
676 source_id_audio_ = id; | 689 source_id_audio_ = id; |
(...skipping 12 matching lines...) Expand all Loading... |
689 | 702 |
690 stream_parser->Init( | 703 stream_parser->Init( |
691 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)), | 704 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)), |
692 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 705 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), |
693 has_audio, has_video), | 706 has_audio, has_video), |
694 audio_cb, | 707 audio_cb, |
695 video_cb, | 708 video_cb, |
696 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 709 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
697 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), | 710 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
698 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, | 711 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, |
699 base::Unretained(this), id)); | 712 base::Unretained(this), id), |
| 713 log_cb_); |
700 | 714 |
701 stream_parser_map_[id] = stream_parser.release(); | 715 stream_parser_map_[id] = stream_parser.release(); |
702 SourceInfo info = { base::TimeDelta(), true }; | 716 SourceInfo info = { base::TimeDelta(), true }; |
703 source_info_map_[id] = info; | 717 source_info_map_[id] = info; |
704 | 718 |
705 return kOk; | 719 return kOk; |
706 } | 720 } |
707 | 721 |
708 void ChunkDemuxer::RemoveId(const std::string& id) { | 722 void ChunkDemuxer::RemoveId(const std::string& id) { |
709 CHECK(IsValidId(id)); | 723 CHECK(IsValidId(id)); |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1039 | 1053 |
1040 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { | 1054 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { |
1041 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; | 1055 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; |
1042 return false; | 1056 return false; |
1043 } | 1057 } |
1044 | 1058 |
1045 // Signal an error if we get configuration info for stream types that weren't | 1059 // Signal an error if we get configuration info for stream types that weren't |
1046 // specified in AddId() or more configs after a stream is initialized. | 1060 // specified in AddId() or more configs after a stream is initialized. |
1047 // Only allow a single audio config for now. | 1061 // Only allow a single audio config for now. |
1048 if (has_audio != audio_config.IsValidConfig()) { | 1062 if (has_audio != audio_config.IsValidConfig()) { |
1049 DVLOG(1) << "OnNewConfigs() : Got unexpected audio config."; | 1063 MEDIA_LOG(log_cb_) |
| 1064 << "Initialization segment" |
| 1065 << (audio_config.IsValidConfig() ? " has" : " does not have") |
| 1066 << " an audio track, but the mimetype" |
| 1067 << (has_audio ? " specifies" : " does not specify") |
| 1068 << " an audio codec."; |
1050 return false; | 1069 return false; |
1051 } | 1070 } |
1052 | 1071 |
1053 // Only allow a single video config for now. | 1072 // Only allow a single video config for now. |
1054 if (has_video != video_config.IsValidConfig()) { | 1073 if (has_video != video_config.IsValidConfig()) { |
1055 DVLOG(1) << "OnNewConfigs() : Got unexpected video config."; | 1074 MEDIA_LOG(log_cb_) |
| 1075 << "Initialization segment" |
| 1076 << (video_config.IsValidConfig() ? " has" : " does not have") |
| 1077 << " a video track, but the mimetype" |
| 1078 << (has_video ? " specifies" : " does not specify") |
| 1079 << " a video codec."; |
1056 return false; | 1080 return false; |
1057 } | 1081 } |
1058 | 1082 |
1059 bool success = true; | 1083 bool success = true; |
1060 if (audio_config.IsValidConfig()) { | 1084 if (audio_config.IsValidConfig()) { |
1061 if (audio_) { | 1085 if (audio_) { |
1062 success &= audio_->UpdateAudioConfig(audio_config); | 1086 success &= audio_->UpdateAudioConfig(audio_config); |
1063 } else { | 1087 } else { |
1064 audio_ = new ChunkDemuxerStream(audio_config); | 1088 audio_ = new ChunkDemuxerStream(audio_config, log_cb_); |
1065 } | 1089 } |
1066 } | 1090 } |
1067 | 1091 |
1068 if (video_config.IsValidConfig()) { | 1092 if (video_config.IsValidConfig()) { |
1069 if (video_) { | 1093 if (video_) { |
1070 success &= video_->UpdateVideoConfig(video_config); | 1094 success &= video_->UpdateVideoConfig(video_config); |
1071 } else { | 1095 } else { |
1072 video_ = new ChunkDemuxerStream(video_config); | 1096 video_ = new ChunkDemuxerStream(video_config, log_cb_); |
1073 } | 1097 } |
1074 } | 1098 } |
1075 | 1099 |
1076 DVLOG(1) << "OnNewConfigs() : success " << success; | 1100 DVLOG(1) << "OnNewConfigs() : success " << success; |
1077 return success; | 1101 return success; |
1078 } | 1102 } |
1079 | 1103 |
1080 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { | 1104 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
1081 lock_.AssertAcquired(); | 1105 lock_.AssertAcquired(); |
1082 DCHECK_NE(state_, SHUTDOWN); | 1106 DCHECK_NE(state_, SHUTDOWN); |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1200 | 1224 |
1201 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1225 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
1202 if (audio_ && !video_) | 1226 if (audio_ && !video_) |
1203 return audio_->GetBufferedRanges(duration_); | 1227 return audio_->GetBufferedRanges(duration_); |
1204 else if (!audio_ && video_) | 1228 else if (!audio_ && video_) |
1205 return video_->GetBufferedRanges(duration_); | 1229 return video_->GetBufferedRanges(duration_); |
1206 return ComputeIntersection(); | 1230 return ComputeIntersection(); |
1207 } | 1231 } |
1208 | 1232 |
1209 } // namespace media | 1233 } // namespace media |
OLD | NEW |