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