| 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 ErrorLogCB& error_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 ERROR_LOG(error_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 ERROR_LOG(error_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 ErrorLogCB& error_cb); |
| 176 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 177 const ErrorLogCB& error_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 ErrorLogCB& error_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, error_cb)); |
| 256 } | 263 } |
| 257 | 264 |
| 258 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config) | 265 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 266 const ErrorLogCB& error_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, error_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 ErrorLogCB& error_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 error_cb_(error_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, error_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 error_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 ERROR_LOG(error_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 ERROR_LOG(error_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, error_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, error_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 |