• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CodecIdToTextKind(const std::string & codec_id)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 
PrecisionCappedDefaultDuration(const double timecode_scale_in_us,const int64 duration_in_ns)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 
WebMTracksParser(const LogCB & log_cb,bool ignore_text_tracks)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 
~WebMTracksParser()62 WebMTracksParser::~WebMTracksParser() {}
63 
Parse(const uint8 * buf,int size)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 
GetAudioDefaultDuration(const double timecode_scale_in_us) const89 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 
GetVideoDefaultDuration(const double timecode_scale_in_us) const95 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 
OnListStart(int id)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 
OnListEnd(int id)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 
OnUInt(int id,int64 val)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 
OnFloat(int id,double val)300 bool WebMTracksParser::OnFloat(int id, double val) {
301   return true;
302 }
303 
OnBinary(int id,const uint8 * data,int size)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 
OnString(int id,const std::string & str)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