Enable right clicking on the applist doodle web contents and log the data.
[chromium-blink-merge.git] / media / formats / webm / webm_tracks_parser.cc
blob92f044110ed5c92ee8a1f35fd65e54f57587806f
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(log_cb_) << "Missing TrackEntry data for "
140 << " TrackType " << track_type_
141 << " TrackNum " << 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(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(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(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(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(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(log_cb_) << "Illegal 0ns audio TrackEntry DefaultDuration";
200 return false;
202 audio_default_duration_ = default_duration_;
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;
210 } else {
211 MEDIA_LOG(log_cb_) << "Ignoring audio track " << track_num_;
212 ignored_tracks_.insert(track_num_);
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;
219 if (default_duration_ == 0) {
220 MEDIA_LOG(log_cb_) << "Illegal 0ns video TrackEntry DefaultDuration";
221 return false;
223 video_default_duration_ = default_duration_;
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;
231 } else {
232 MEDIA_LOG(log_cb_) << "Ignoring video track " << track_num_;
233 ignored_tracks_.insert(track_num_);
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);
245 } else {
246 MEDIA_LOG(log_cb_) << "Unexpected TrackType " << track_type_;
247 return false;
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();
259 audio_client_.Reset();
260 video_client_.Reset();
261 return true;
264 return true;
267 bool WebMTracksParser::OnUInt(int id, int64 val) {
268 int64* dst = NULL;
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;
290 if (*dst != -1) {
291 MEDIA_LOG(log_cb_) << "Multiple values for id " << std::hex << id
292 << " specified";
293 return false;
296 *dst = val;
297 return true;
300 bool WebMTracksParser::OnFloat(int id, double val) {
301 return true;
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;
310 codec_private_.assign(data, data + size);
311 return true;
313 return true;
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;
323 codec_id_ = str;
324 return true;
327 if (id == kWebMIdName) {
328 track_name_ = str;
329 return true;
332 if (id == kWebMIdLanguage) {
333 track_language_ = str;
334 return true;
337 return true;
340 } // namespace media