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