| 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" |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/logging.h" | |
| 14 #include "base/message_loop_proxy.h" | 13 #include "base/message_loop_proxy.h" |
| 15 #include "base/string_number_conversions.h" | |
| 16 #include "base/string_util.h" | |
| 17 #include "media/base/audio_decoder_config.h" | 14 #include "media/base/audio_decoder_config.h" |
| 18 #include "media/base/stream_parser_buffer.h" | 15 #include "media/base/stream_parser_buffer.h" |
| 19 #include "media/base/video_decoder_config.h" | 16 #include "media/base/video_decoder_config.h" |
| 20 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) | 17 #include "media/filters/stream_parser_factory.h" |
| 21 #include "media/mp4/es_descriptor.h" | |
| 22 #include "media/mp4/mp4_stream_parser.h" | |
| 23 #endif | |
| 24 #include "media/webm/webm_stream_parser.h" | |
| 25 | 18 |
| 26 using base::TimeDelta; | 19 using base::TimeDelta; |
| 27 | 20 |
| 28 namespace media { | 21 namespace media { |
| 29 | 22 |
| 30 struct CodecInfo { | |
| 31 const char* pattern; | |
| 32 DemuxerStream::Type type; | |
| 33 }; | |
| 34 | |
| 35 typedef StreamParser* (*ParserFactoryFunction)( | |
| 36 const std::vector<std::string>& codecs, const LogCB& log_cb); | |
| 37 | |
| 38 struct SupportedTypeInfo { | |
| 39 const char* type; | |
| 40 const ParserFactoryFunction factory_function; | |
| 41 const CodecInfo** codecs; | |
| 42 }; | |
| 43 | |
| 44 static const CodecInfo kVP8CodecInfo = { "vp8", DemuxerStream::VIDEO }; | |
| 45 static const CodecInfo kVorbisCodecInfo = { "vorbis", DemuxerStream::AUDIO }; | |
| 46 | |
| 47 static const CodecInfo* kVideoWebMCodecs[] = { | |
| 48 &kVP8CodecInfo, | |
| 49 &kVorbisCodecInfo, | |
| 50 NULL | |
| 51 }; | |
| 52 | |
| 53 static const CodecInfo* kAudioWebMCodecs[] = { | |
| 54 &kVorbisCodecInfo, | |
| 55 NULL | |
| 56 }; | |
| 57 | |
| 58 static StreamParser* BuildWebMParser(const std::vector<std::string>& codecs, | |
| 59 const LogCB& log_cb) { | |
| 60 return new WebMStreamParser(); | |
| 61 } | |
| 62 | |
| 63 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) | |
| 64 static const CodecInfo kH264CodecInfo = { "avc1.*", DemuxerStream::VIDEO }; | |
| 65 static const CodecInfo kMPEG4AACCodecInfo = { | |
| 66 "mp4a.40.*", DemuxerStream::AUDIO | |
| 67 }; | |
| 68 | |
| 69 static const CodecInfo kMPEG2AACLCCodecInfo = { | |
| 70 "mp4a.67", DemuxerStream::AUDIO | |
| 71 }; | |
| 72 | |
| 73 static const CodecInfo* kVideoMP4Codecs[] = { | |
| 74 &kH264CodecInfo, | |
| 75 &kMPEG4AACCodecInfo, | |
| 76 &kMPEG2AACLCCodecInfo, | |
| 77 NULL | |
| 78 }; | |
| 79 | |
| 80 static const CodecInfo* kAudioMP4Codecs[] = { | |
| 81 &kMPEG4AACCodecInfo, | |
| 82 &kMPEG2AACLCCodecInfo, | |
| 83 NULL | |
| 84 }; | |
| 85 | |
| 86 // AAC Object Type IDs that Chrome supports. | |
| 87 static const int kAACLCObjectType = 2; | |
| 88 static const int kAACSBRObjectType = 5; | |
| 89 | |
| 90 static StreamParser* BuildMP4Parser(const std::vector<std::string>& codecs, | |
| 91 const LogCB& log_cb) { | |
| 92 std::set<int> audio_object_types; | |
| 93 bool has_sbr = false; | |
| 94 for (size_t i = 0; i < codecs.size(); ++i) { | |
| 95 if (MatchPattern(codecs[i], kMPEG2AACLCCodecInfo.pattern)) { | |
| 96 audio_object_types.insert(mp4::kISO_13818_7_AAC_LC); | |
| 97 } else if (MatchPattern(codecs[i], kMPEG4AACCodecInfo.pattern)) { | |
| 98 std::vector<std::string> tokens; | |
| 99 int audio_object_type; | |
| 100 if (Tokenize(codecs[i], ".", &tokens) != 3 || | |
| 101 !base::HexStringToInt(tokens[2], &audio_object_type)) { | |
| 102 MEDIA_LOG(log_cb) << "Malformed mimetype codec '" << codecs[i] << "'"; | |
| 103 return NULL; | |
| 104 } | |
| 105 | |
| 106 if (audio_object_type != kAACLCObjectType && | |
| 107 audio_object_type != kAACSBRObjectType) { | |
| 108 MEDIA_LOG(log_cb) << "Unsupported audio object type " | |
| 109 << "0x" << std::hex << audio_object_type | |
| 110 << " in codec '" << codecs[i] << "'"; | |
| 111 return NULL; | |
| 112 } | |
| 113 | |
| 114 audio_object_types.insert(mp4::kISO_14496_3); | |
| 115 | |
| 116 if (audio_object_type == kAACSBRObjectType) { | |
| 117 has_sbr = true; | |
| 118 break; | |
| 119 } | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 return new mp4::MP4StreamParser(audio_object_types, has_sbr); | |
| 124 } | |
| 125 #endif | |
| 126 | |
| 127 static const SupportedTypeInfo kSupportedTypeInfo[] = { | |
| 128 { "video/webm", &BuildWebMParser, kVideoWebMCodecs }, | |
| 129 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs }, | |
| 130 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) | |
| 131 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs }, | |
| 132 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs }, | |
| 133 #endif | |
| 134 }; | |
| 135 | |
| 136 // Checks to see if the specified |type| and |codecs| list are supported. | |
| 137 // Returns true if |type| and all codecs listed in |codecs| are supported. | |
| 138 // |factory_function| contains a function that can build a StreamParser | |
| 139 // for this type. | |
| 140 // |has_audio| is true if an audio codec was specified. | |
| 141 // |has_video| is true if a video codec was specified. | |
| 142 // Returns false otherwise. The values of |factory_function|, |has_audio|, | |
| 143 // and |has_video| are undefined. | |
| 144 static bool IsSupported(const std::string& type, | |
| 145 std::vector<std::string>& codecs, | |
| 146 const LogCB& log_cb, | |
| 147 ParserFactoryFunction* factory_function, | |
| 148 bool* has_audio, | |
| 149 bool* has_video) { | |
| 150 *factory_function = NULL; | |
| 151 *has_audio = false; | |
| 152 *has_video = false; | |
| 153 | |
| 154 // Search for the SupportedTypeInfo for |type|. | |
| 155 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { | |
| 156 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; | |
| 157 if (type == type_info.type) { | |
| 158 // Make sure all the codecs specified in |codecs| are | |
| 159 // in the supported type info. | |
| 160 for (size_t j = 0; j < codecs.size(); ++j) { | |
| 161 // Search the type info for a match. | |
| 162 bool found_codec = false; | |
| 163 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; | |
| 164 | |
| 165 for (int k = 0; type_info.codecs[k]; ++k) { | |
| 166 if (MatchPattern(codecs[j], type_info.codecs[k]->pattern)) { | |
| 167 found_codec = true; | |
| 168 codec_type = type_info.codecs[k]->type; | |
| 169 break; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 if (!found_codec) { | |
| 174 MEDIA_LOG(log_cb) << "Codec '" << codecs[j] | |
| 175 <<"' is not supported for '" << type << "'"; | |
| 176 return false; | |
| 177 } | |
| 178 | |
| 179 switch (codec_type) { | |
| 180 case DemuxerStream::AUDIO: | |
| 181 *has_audio = true; | |
| 182 break; | |
| 183 case DemuxerStream::VIDEO: | |
| 184 *has_video = true; | |
| 185 break; | |
| 186 default: | |
| 187 MEDIA_LOG(log_cb) << "Unsupported codec type '"<< codec_type | |
| 188 << "' for " << codecs[j]; | |
| 189 return false; | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 *factory_function = type_info.factory_function; | |
| 194 | |
| 195 // All codecs were supported by this |type|. | |
| 196 return true; | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 // |type| didn't match any of the supported types. | |
| 201 return false; | |
| 202 } | |
| 203 | 23 |
| 204 class ChunkDemuxerStream : public DemuxerStream { | 24 class ChunkDemuxerStream : public DemuxerStream { |
| 205 public: | 25 public: |
| 206 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 26 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| 207 typedef std::deque<ReadCB> ReadCBQueue; | 27 typedef std::deque<ReadCB> ReadCBQueue; |
| 208 typedef std::deque<base::Closure> ClosureQueue; | 28 typedef std::deque<base::Closure> ClosureQueue; |
| 209 | 29 |
| 210 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 30 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 211 const LogCB& log_cb); | 31 const LogCB& log_cb); |
| 212 ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 32 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 std::vector<std::string>& codecs) { | 530 std::vector<std::string>& codecs) { |
| 711 DCHECK_GT(codecs.size(), 0u); | 531 DCHECK_GT(codecs.size(), 0u); |
| 712 base::AutoLock auto_lock(lock_); | 532 base::AutoLock auto_lock(lock_); |
| 713 | 533 |
| 714 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || | 534 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || |
| 715 stream_parser_map_.count(id) > 0u) | 535 stream_parser_map_.count(id) > 0u) |
| 716 return kReachedIdLimit; | 536 return kReachedIdLimit; |
| 717 | 537 |
| 718 bool has_audio = false; | 538 bool has_audio = false; |
| 719 bool has_video = false; | 539 bool has_video = false; |
| 720 ParserFactoryFunction factory_function = NULL; | 540 scoped_ptr<media::StreamParser> stream_parser( |
| 721 std::string error; | 541 StreamParserFactory::Create(type, codecs, log_cb_, |
| 722 if (!IsSupported(type, codecs, log_cb_, &factory_function, &has_audio, | 542 &has_audio, &has_video)); |
| 723 &has_video)) { | 543 |
| 724 return kNotSupported; | 544 if (!stream_parser) |
| 725 } | 545 return ChunkDemuxer::kNotSupported; |
| 726 | 546 |
| 727 if ((has_audio && !source_id_audio_.empty()) || | 547 if ((has_audio && !source_id_audio_.empty()) || |
| 728 (has_video && !source_id_video_.empty())) | 548 (has_video && !source_id_video_.empty())) |
| 729 return kReachedIdLimit; | 549 return kReachedIdLimit; |
| 730 | 550 |
| 731 StreamParser::NewBuffersCB audio_cb; | 551 StreamParser::NewBuffersCB audio_cb; |
| 732 StreamParser::NewBuffersCB video_cb; | 552 StreamParser::NewBuffersCB video_cb; |
| 733 | 553 |
| 734 scoped_ptr<StreamParser> stream_parser(factory_function(codecs, log_cb_)); | |
| 735 if (!stream_parser) | |
| 736 return kNotSupported; | |
| 737 | |
| 738 if (has_audio) { | 554 if (has_audio) { |
| 739 source_id_audio_ = id; | 555 source_id_audio_ = id; |
| 740 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, | 556 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, |
| 741 base::Unretained(this)); | 557 base::Unretained(this)); |
| 742 } | 558 } |
| 743 | 559 |
| 744 if (has_video) { | 560 if (has_video) { |
| 745 source_id_video_ = id; | 561 source_id_video_ = id; |
| 746 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, | 562 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, |
| 747 base::Unretained(this)); | 563 base::Unretained(this)); |
| (...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1335 | 1151 |
| 1336 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1152 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
| 1337 if (audio_ && !video_) | 1153 if (audio_ && !video_) |
| 1338 return audio_->GetBufferedRanges(duration_); | 1154 return audio_->GetBufferedRanges(duration_); |
| 1339 else if (!audio_ && video_) | 1155 else if (!audio_ && video_) |
| 1340 return video_->GetBufferedRanges(duration_); | 1156 return video_->GetBufferedRanges(duration_); |
| 1341 return ComputeIntersection(); | 1157 return ComputeIntersection(); |
| 1342 } | 1158 } |
| 1343 | 1159 |
| 1344 } // namespace media | 1160 } // namespace media |
| OLD | NEW |