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 3 // found in the LICENSE file. 4 5 #include "media/webm/webm_tracks_parser.h" 6 7 #include "base/logging.h" 8 #include "base/strings/string_util.h" 9 #include "media/base/buffers.h" 10 #include "media/webm/webm_constants.h" 11 #include "media/webm/webm_content_encodings.h" 12 13 namespace media { 14 15 static TextKind CodecIdToTextKind(const std::string& codec_id) { 16 if (codec_id == kWebMCodecSubtitles) 17 return kTextSubtitles; 18 19 if (codec_id == kWebMCodecCaptions) 20 return kTextCaptions; 21 22 if (codec_id == kWebMCodecDescriptions) 23 return kTextDescriptions; 24 25 if (codec_id == kWebMCodecMetadata) 26 return kTextMetadata; 27 28 return kTextNone; 29 } 30 31 WebMTracksParser::WebMTracksParser(const LogCB& log_cb, bool ignore_text_tracks) 32 : track_type_(-1), 33 track_num_(-1), 34 audio_track_num_(-1), 35 video_track_num_(-1), 36 ignore_text_tracks_(ignore_text_tracks), 37 log_cb_(log_cb), 38 audio_client_(log_cb), 39 video_client_(log_cb) { 40 } 41 42 WebMTracksParser::~WebMTracksParser() {} 43 44 int WebMTracksParser::Parse(const uint8* buf, int size) { 45 track_type_ =-1; 46 track_num_ = -1; 47 track_name_.clear(); 48 track_language_.clear(); 49 audio_track_num_ = -1; 50 audio_decoder_config_ = AudioDecoderConfig(); 51 video_track_num_ = -1; 52 video_decoder_config_ = VideoDecoderConfig(); 53 text_tracks_.clear(); 54 ignored_tracks_.clear(); 55 56 WebMListParser parser(kWebMIdTracks, this); 57 int result = parser.Parse(buf, size); 58 59 if (result <= 0) 60 return result; 61 62 // For now we do all or nothing parsing. 63 return parser.IsParsingComplete() ? result : 0; 64 } 65 66 WebMParserClient* WebMTracksParser::OnListStart(int id) { 67 if (id == kWebMIdContentEncodings) { 68 DCHECK(!track_content_encodings_client_.get()); 69 track_content_encodings_client_.reset( 70 new WebMContentEncodingsClient(log_cb_)); 71 return track_content_encodings_client_->OnListStart(id); 72 } 73 74 if (id == kWebMIdTrackEntry) { 75 track_type_ = -1; 76 track_num_ = -1; 77 track_name_.clear(); 78 track_language_.clear(); 79 codec_id_ = ""; 80 codec_private_.clear(); 81 audio_client_.Reset(); 82 video_client_.Reset(); 83 return this; 84 } 85 86 if (id == kWebMIdAudio) 87 return &audio_client_; 88 89 if (id == kWebMIdVideo) 90 return &video_client_; 91 92 return this; 93 } 94 95 bool WebMTracksParser::OnListEnd(int id) { 96 if (id == kWebMIdContentEncodings) { 97 DCHECK(track_content_encodings_client_.get()); 98 return track_content_encodings_client_->OnListEnd(id); 99 } 100 101 if (id == kWebMIdTrackEntry) { 102 if (track_type_ == -1 || track_num_ == -1) { 103 MEDIA_LOG(log_cb_) << "Missing TrackEntry data for " 104 << " TrackType " << track_type_ 105 << " TrackNum " << track_num_; 106 return false; 107 } 108 109 if (track_type_ != kWebMTrackTypeAudio && 110 track_type_ != kWebMTrackTypeVideo && 111 track_type_ != kWebMTrackTypeSubtitlesOrCaptions && 112 track_type_ != kWebMTrackTypeDescriptionsOrMetadata) { 113 MEDIA_LOG(log_cb_) << "Unexpected TrackType " << track_type_; 114 return false; 115 } 116 117 TextKind text_track_kind = kTextNone; 118 if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions) { 119 text_track_kind = CodecIdToTextKind(codec_id_); 120 if (text_track_kind == kTextNone) { 121 MEDIA_LOG(log_cb_) << "Missing TrackEntry CodecID" 122 << " TrackNum " << track_num_; 123 return false; 124 } 125 126 if (text_track_kind != kTextSubtitles && 127 text_track_kind != kTextCaptions) { 128 MEDIA_LOG(log_cb_) << "Wrong TrackEntry CodecID" 129 << " TrackNum " << track_num_; 130 return false; 131 } 132 } else if (track_type_ == kWebMTrackTypeDescriptionsOrMetadata) { 133 text_track_kind = CodecIdToTextKind(codec_id_); 134 if (text_track_kind == kTextNone) { 135 MEDIA_LOG(log_cb_) << "Missing TrackEntry CodecID" 136 << " TrackNum " << track_num_; 137 return false; 138 } 139 140 if (text_track_kind != kTextDescriptions && 141 text_track_kind != kTextMetadata) { 142 MEDIA_LOG(log_cb_) << "Wrong TrackEntry CodecID" 143 << " TrackNum " << track_num_; 144 return false; 145 } 146 } 147 148 std::string encryption_key_id; 149 if (track_content_encodings_client_) { 150 DCHECK(!track_content_encodings_client_->content_encodings().empty()); 151 // If we have multiple ContentEncoding in one track. Always choose the 152 // key id in the first ContentEncoding as the key id of the track. 153 encryption_key_id = track_content_encodings_client_-> 154 content_encodings()[0]->encryption_key_id(); 155 } 156 157 if (track_type_ == kWebMTrackTypeAudio) { 158 if (audio_track_num_ == -1) { 159 audio_track_num_ = track_num_; 160 audio_encryption_key_id_ = encryption_key_id; 161 162 DCHECK(!audio_decoder_config_.IsValidConfig()); 163 if (!audio_client_.InitializeConfig( 164 codec_id_, codec_private_, !audio_encryption_key_id_.empty(), 165 &audio_decoder_config_)) { 166 return false; 167 } 168 } else { 169 MEDIA_LOG(log_cb_) << "Ignoring audio track " << track_num_; 170 ignored_tracks_.insert(track_num_); 171 } 172 } else if (track_type_ == kWebMTrackTypeVideo) { 173 if (video_track_num_ == -1) { 174 video_track_num_ = track_num_; 175 video_encryption_key_id_ = encryption_key_id; 176 177 DCHECK(!video_decoder_config_.IsValidConfig()); 178 if (!video_client_.InitializeConfig( 179 codec_id_, codec_private_, !video_encryption_key_id_.empty(), 180 &video_decoder_config_)) { 181 return false; 182 } 183 } else { 184 MEDIA_LOG(log_cb_) << "Ignoring video track " << track_num_; 185 ignored_tracks_.insert(track_num_); 186 } 187 } else if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions || 188 track_type_ == kWebMTrackTypeDescriptionsOrMetadata) { 189 if (ignore_text_tracks_) { 190 MEDIA_LOG(log_cb_) << "Ignoring text track " << track_num_; 191 ignored_tracks_.insert(track_num_); 192 } else { 193 TextTrackInfo& text_track_info = text_tracks_[track_num_]; 194 text_track_info.kind = text_track_kind; 195 text_track_info.name = track_name_; 196 text_track_info.language = track_language_; 197 } 198 } else { 199 MEDIA_LOG(log_cb_) << "Unexpected TrackType " << track_type_; 200 return false; 201 } 202 203 track_type_ = -1; 204 track_num_ = -1; 205 track_name_.clear(); 206 track_language_.clear(); 207 codec_id_ = ""; 208 codec_private_.clear(); 209 track_content_encodings_client_.reset(); 210 211 audio_client_.Reset(); 212 video_client_.Reset(); 213 return true; 214 } 215 216 return true; 217 } 218 219 bool WebMTracksParser::OnUInt(int id, int64 val) { 220 int64* dst = NULL; 221 222 switch (id) { 223 case kWebMIdTrackNumber: 224 dst = &track_num_; 225 break; 226 case kWebMIdTrackType: 227 dst = &track_type_; 228 break; 229 default: 230 return true; 231 } 232 233 if (*dst != -1) { 234 MEDIA_LOG(log_cb_) << "Multiple values for id " << std::hex << id 235 << " specified"; 236 return false; 237 } 238 239 *dst = val; 240 return true; 241 } 242 243 bool WebMTracksParser::OnFloat(int id, double val) { 244 return true; 245 } 246 247 bool WebMTracksParser::OnBinary(int id, const uint8* data, int size) { 248 if (id == kWebMIdCodecPrivate) { 249 if (!codec_private_.empty()) { 250 MEDIA_LOG(log_cb_) << "Multiple CodecPrivate fields in a track."; 251 return false; 252 } 253 254 codec_private_.assign(data, data + size); 255 return true; 256 } 257 return true; 258 } 259 260 bool WebMTracksParser::OnString(int id, const std::string& str) { 261 if (id == kWebMIdCodecID) { 262 if (!codec_id_.empty()) { 263 MEDIA_LOG(log_cb_) << "Multiple CodecID fields in a track"; 264 return false; 265 } 266 267 codec_id_ = str; 268 return true; 269 } 270 271 if (id == kWebMIdName) { 272 track_name_ = str; 273 return true; 274 } 275 276 if (id == kWebMIdLanguage) { 277 track_language_ = str; 278 return true; 279 } 280 281 return true; 282 } 283 284 } // namespace media 285