Roll ANGLE e754fb8..6ffeb74
[chromium-blink-merge.git] / media / formats / webm / webm_tracks_parser.cc
blob86bb0a73103f6f24473a9a0cefb06a46afe1ac41
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.
5 #include "media/formats/webm/webm_tracks_parser.h"
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"
14 namespace media {
16 static TextKind CodecIdToTextKind(const std::string& codec_id) {
17 if (codec_id == kWebMCodecSubtitles)
18 return kTextSubtitles;
20 if (codec_id == kWebMCodecCaptions)
21 return kTextCaptions;
23 if (codec_id == kWebMCodecDescriptions)
24 return kTextDescriptions;
26 if (codec_id == kWebMCodecMetadata)
27 return kTextMetadata;
29 return kTextNone;
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();
37 int64 mult = duration_in_ns / 1000;
38 mult /= timecode_scale_in_us;
39 if (mult == 0)
40 return kNoTimestamp();
42 mult = static_cast<double>(mult) * timecode_scale_in_us;
43 return base::TimeDelta::FromMicroseconds(mult);
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) {
62 WebMTracksParser::~WebMTracksParser() {}
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();
79 WebMListParser parser(kWebMIdTracks, this);
80 int result = parser.Parse(buf, size);
82 if (result <= 0)
83 return result;
85 // For now we do all or nothing parsing.
86 return parser.IsParsingComplete() ? result : 0;
89 base::TimeDelta WebMTracksParser::GetAudioDefaultDuration(
90 const double timecode_scale_in_us) const {
91 return PrecisionCappedDefaultDuration(timecode_scale_in_us,
92 audio_default_duration_);
95 base::TimeDelta WebMTracksParser::GetVideoDefaultDuration(
96 const double timecode_scale_in_us) const {
97 return PrecisionCappedDefaultDuration(timecode_scale_in_us,
98 video_default_duration_);
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);
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;
122 if (id == kWebMIdAudio)
123 return &audio_client_;
125 if (id == kWebMIdVideo)
126 return &video_client_;
128 return this;
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);
137 if (id == kWebMIdTrackEntry) {
138 if (track_type_ == -1 || track_num_ == -1) {
139 MEDIA_LOG(ERROR, log_cb_) << "Missing TrackEntry data for "
140 << " TrackType " << track_type_ << " TrackNum "
141 << track_num_;
142 return false;
145 if (track_type_ != kWebMTrackTypeAudio &&
146 track_type_ != kWebMTrackTypeVideo &&
147 track_type_ != kWebMTrackTypeSubtitlesOrCaptions &&
148 track_type_ != kWebMTrackTypeDescriptionsOrMetadata) {
149 MEDIA_LOG(ERROR, log_cb_) << "Unexpected TrackType " << track_type_;
150 return false;
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(ERROR, log_cb_) << "Missing TrackEntry CodecID"
158 << " TrackNum " << track_num_;
159 return false;
162 if (text_track_kind != kTextSubtitles &&
163 text_track_kind != kTextCaptions) {
164 MEDIA_LOG(ERROR, log_cb_) << "Wrong TrackEntry CodecID"
165 << " TrackNum " << track_num_;
166 return false;
168 } else if (track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
169 text_track_kind = CodecIdToTextKind(codec_id_);
170 if (text_track_kind == kTextNone) {
171 MEDIA_LOG(ERROR, log_cb_) << "Missing TrackEntry CodecID"
172 << " TrackNum " << track_num_;
173 return false;
176 if (text_track_kind != kTextDescriptions &&
177 text_track_kind != kTextMetadata) {
178 MEDIA_LOG(ERROR, log_cb_) << "Wrong TrackEntry CodecID"
179 << " TrackNum " << track_num_;
180 return false;
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();
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;
198 if (default_duration_ == 0) {
199 MEDIA_LOG(ERROR, log_cb_) << "Illegal 0ns audio TrackEntry "
200 "DefaultDuration";
201 return false;
203 audio_default_duration_ = default_duration_;
205 DCHECK(!audio_decoder_config_.IsValidConfig());
206 if (!audio_client_.InitializeConfig(
207 codec_id_, codec_private_, seek_preroll_, codec_delay_,
208 !audio_encryption_key_id_.empty(), &audio_decoder_config_)) {
209 return false;
211 } else {
212 MEDIA_LOG(DEBUG, log_cb_) << "Ignoring audio track " << track_num_;
213 ignored_tracks_.insert(track_num_);
215 } else if (track_type_ == kWebMTrackTypeVideo) {
216 if (video_track_num_ == -1) {
217 video_track_num_ = track_num_;
218 video_encryption_key_id_ = encryption_key_id;
220 if (default_duration_ == 0) {
221 MEDIA_LOG(ERROR, log_cb_) << "Illegal 0ns video TrackEntry "
222 "DefaultDuration";
223 return false;
225 video_default_duration_ = default_duration_;
227 DCHECK(!video_decoder_config_.IsValidConfig());
228 if (!video_client_.InitializeConfig(
229 codec_id_, codec_private_, !video_encryption_key_id_.empty(),
230 &video_decoder_config_)) {
231 return false;
233 } else {
234 MEDIA_LOG(DEBUG, log_cb_) << "Ignoring video track " << track_num_;
235 ignored_tracks_.insert(track_num_);
237 } else if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions ||
238 track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
239 if (ignore_text_tracks_) {
240 MEDIA_LOG(DEBUG, log_cb_) << "Ignoring text track " << track_num_;
241 ignored_tracks_.insert(track_num_);
242 } else {
243 std::string track_num = base::Int64ToString(track_num_);
244 text_tracks_[track_num_] = TextTrackConfig(
245 text_track_kind, track_name_, track_language_, track_num);
247 } else {
248 MEDIA_LOG(ERROR, log_cb_) << "Unexpected TrackType " << track_type_;
249 return false;
252 track_type_ = -1;
253 track_num_ = -1;
254 default_duration_ = -1;
255 track_name_.clear();
256 track_language_.clear();
257 codec_id_ = "";
258 codec_private_.clear();
259 track_content_encodings_client_.reset();
261 audio_client_.Reset();
262 video_client_.Reset();
263 return true;
266 return true;
269 bool WebMTracksParser::OnUInt(int id, int64 val) {
270 int64* dst = NULL;
272 switch (id) {
273 case kWebMIdTrackNumber:
274 dst = &track_num_;
275 break;
276 case kWebMIdTrackType:
277 dst = &track_type_;
278 break;
279 case kWebMIdSeekPreRoll:
280 dst = &seek_preroll_;
281 break;
282 case kWebMIdCodecDelay:
283 dst = &codec_delay_;
284 break;
285 case kWebMIdDefaultDuration:
286 dst = &default_duration_;
287 break;
288 default:
289 return true;
292 if (*dst != -1) {
293 MEDIA_LOG(ERROR, log_cb_) << "Multiple values for id " << std::hex << id
294 << " specified";
295 return false;
298 *dst = val;
299 return true;
302 bool WebMTracksParser::OnFloat(int id, double val) {
303 return true;
306 bool WebMTracksParser::OnBinary(int id, const uint8* data, int size) {
307 if (id == kWebMIdCodecPrivate) {
308 if (!codec_private_.empty()) {
309 MEDIA_LOG(ERROR, log_cb_) << "Multiple CodecPrivate fields in a track.";
310 return false;
312 codec_private_.assign(data, data + size);
313 return true;
315 return true;
318 bool WebMTracksParser::OnString(int id, const std::string& str) {
319 if (id == kWebMIdCodecID) {
320 if (!codec_id_.empty()) {
321 MEDIA_LOG(ERROR, log_cb_) << "Multiple CodecID fields in a track";
322 return false;
325 codec_id_ = str;
326 return true;
329 if (id == kWebMIdName) {
330 track_name_ = str;
331 return true;
334 if (id == kWebMIdLanguage) {
335 track_language_ = str;
336 return true;
339 return true;
342 } // namespace media