1 // Copyright (c) 2012 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/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/webm/webm_constants.h"
12 #include "media/webm/webm_content_encodings.h"
16 static TextKind
CodecIdToTextKind(const std::string
& codec_id
) {
17 if (codec_id
== kWebMCodecSubtitles
)
18 return kTextSubtitles
;
20 if (codec_id
== kWebMCodecCaptions
)
23 if (codec_id
== kWebMCodecDescriptions
)
24 return kTextDescriptions
;
26 if (codec_id
== kWebMCodecMetadata
)
32 WebMTracksParser::WebMTracksParser(const LogCB
& log_cb
, bool ignore_text_tracks
)
40 ignore_text_tracks_(ignore_text_tracks
),
42 audio_client_(log_cb
),
43 video_client_(log_cb
) {
46 WebMTracksParser::~WebMTracksParser() {}
48 int WebMTracksParser::Parse(const uint8
* buf
, int size
) {
53 track_language_
.clear();
54 audio_track_num_
= -1;
55 audio_decoder_config_
= AudioDecoderConfig();
56 video_track_num_
= -1;
57 video_decoder_config_
= VideoDecoderConfig();
59 ignored_tracks_
.clear();
61 WebMListParser
parser(kWebMIdTracks
, this);
62 int result
= parser
.Parse(buf
, size
);
67 // For now we do all or nothing parsing.
68 return parser
.IsParsingComplete() ? result
: 0;
71 WebMParserClient
* WebMTracksParser::OnListStart(int id
) {
72 if (id
== kWebMIdContentEncodings
) {
73 DCHECK(!track_content_encodings_client_
.get());
74 track_content_encodings_client_
.reset(
75 new WebMContentEncodingsClient(log_cb_
));
76 return track_content_encodings_client_
->OnListStart(id
);
79 if (id
== kWebMIdTrackEntry
) {
83 track_language_
.clear();
85 codec_private_
.clear();
86 audio_client_
.Reset();
87 video_client_
.Reset();
91 if (id
== kWebMIdAudio
)
92 return &audio_client_
;
94 if (id
== kWebMIdVideo
)
95 return &video_client_
;
100 bool WebMTracksParser::OnListEnd(int id
) {
101 if (id
== kWebMIdContentEncodings
) {
102 DCHECK(track_content_encodings_client_
.get());
103 return track_content_encodings_client_
->OnListEnd(id
);
106 if (id
== kWebMIdTrackEntry
) {
107 if (track_type_
== -1 || track_num_
== -1 || track_uid_
== -1) {
108 MEDIA_LOG(log_cb_
) << "Missing TrackEntry data for "
109 << " TrackType " << track_type_
110 << " TrackNum " << track_num_
111 << " TrackUID " << track_uid_
;
115 if (track_type_
!= kWebMTrackTypeAudio
&&
116 track_type_
!= kWebMTrackTypeVideo
&&
117 track_type_
!= kWebMTrackTypeSubtitlesOrCaptions
&&
118 track_type_
!= kWebMTrackTypeDescriptionsOrMetadata
) {
119 MEDIA_LOG(log_cb_
) << "Unexpected TrackType " << track_type_
;
123 TextKind text_track_kind
= kTextNone
;
124 if (track_type_
== kWebMTrackTypeSubtitlesOrCaptions
) {
125 text_track_kind
= CodecIdToTextKind(codec_id_
);
126 if (text_track_kind
== kTextNone
) {
127 MEDIA_LOG(log_cb_
) << "Missing TrackEntry CodecID"
128 << " TrackNum " << track_num_
;
132 if (text_track_kind
!= kTextSubtitles
&&
133 text_track_kind
!= kTextCaptions
) {
134 MEDIA_LOG(log_cb_
) << "Wrong TrackEntry CodecID"
135 << " TrackNum " << track_num_
;
138 } else if (track_type_
== kWebMTrackTypeDescriptionsOrMetadata
) {
139 text_track_kind
= CodecIdToTextKind(codec_id_
);
140 if (text_track_kind
== kTextNone
) {
141 MEDIA_LOG(log_cb_
) << "Missing TrackEntry CodecID"
142 << " TrackNum " << track_num_
;
146 if (text_track_kind
!= kTextDescriptions
&&
147 text_track_kind
!= kTextMetadata
) {
148 MEDIA_LOG(log_cb_
) << "Wrong TrackEntry CodecID"
149 << " TrackNum " << track_num_
;
154 std::string encryption_key_id
;
155 if (track_content_encodings_client_
) {
156 DCHECK(!track_content_encodings_client_
->content_encodings().empty());
157 // If we have multiple ContentEncoding in one track. Always choose the
158 // key id in the first ContentEncoding as the key id of the track.
159 encryption_key_id
= track_content_encodings_client_
->
160 content_encodings()[0]->encryption_key_id();
163 if (track_type_
== kWebMTrackTypeAudio
) {
164 if (audio_track_num_
== -1) {
165 audio_track_num_
= track_num_
;
166 audio_encryption_key_id_
= encryption_key_id
;
168 DCHECK(!audio_decoder_config_
.IsValidConfig());
169 if (!audio_client_
.InitializeConfig(
170 codec_id_
, codec_private_
, seek_preroll_
, codec_delay_
,
171 !audio_encryption_key_id_
.empty(), &audio_decoder_config_
)) {
175 MEDIA_LOG(log_cb_
) << "Ignoring audio track " << track_num_
;
176 ignored_tracks_
.insert(track_num_
);
178 } else if (track_type_
== kWebMTrackTypeVideo
) {
179 if (video_track_num_
== -1) {
180 video_track_num_
= track_num_
;
181 video_encryption_key_id_
= encryption_key_id
;
183 DCHECK(!video_decoder_config_
.IsValidConfig());
184 if (!video_client_
.InitializeConfig(
185 codec_id_
, codec_private_
, !video_encryption_key_id_
.empty(),
186 &video_decoder_config_
)) {
190 MEDIA_LOG(log_cb_
) << "Ignoring video track " << track_num_
;
191 ignored_tracks_
.insert(track_num_
);
193 } else if (track_type_
== kWebMTrackTypeSubtitlesOrCaptions
||
194 track_type_
== kWebMTrackTypeDescriptionsOrMetadata
) {
195 if (ignore_text_tracks_
) {
196 MEDIA_LOG(log_cb_
) << "Ignoring text track " << track_num_
;
197 ignored_tracks_
.insert(track_num_
);
199 std::string track_uid
= base::Int64ToString(track_uid_
);
200 text_tracks_
[track_num_
] = TextTrackConfig(text_track_kind
,
206 MEDIA_LOG(log_cb_
) << "Unexpected TrackType " << track_type_
;
214 track_language_
.clear();
216 codec_private_
.clear();
217 track_content_encodings_client_
.reset();
219 audio_client_
.Reset();
220 video_client_
.Reset();
227 bool WebMTracksParser::OnUInt(int id
, int64 val
) {
231 case kWebMIdTrackNumber
:
234 case kWebMIdTrackType
:
237 case kWebMIdTrackUID
:
240 case kWebMIdSeekPreRoll
:
241 dst
= &seek_preroll_
;
243 case kWebMIdCodecDelay
:
251 MEDIA_LOG(log_cb_
) << "Multiple values for id " << std::hex
<< id
260 bool WebMTracksParser::OnFloat(int id
, double val
) {
264 bool WebMTracksParser::OnBinary(int id
, const uint8
* data
, int size
) {
265 if (id
== kWebMIdCodecPrivate
) {
266 if (!codec_private_
.empty()) {
267 MEDIA_LOG(log_cb_
) << "Multiple CodecPrivate fields in a track.";
271 codec_private_
.assign(data
, data
+ size
);
277 bool WebMTracksParser::OnString(int id
, const std::string
& str
) {
278 if (id
== kWebMIdCodecID
) {
279 if (!codec_id_
.empty()) {
280 MEDIA_LOG(log_cb_
) << "Multiple CodecID fields in a track";
288 if (id
== kWebMIdName
) {
293 if (id
== kWebMIdLanguage
) {
294 track_language_
= str
;