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_util.h"
9 #include "media/base/buffers.h"
10 #include "media/webm/webm_constants.h"
11 #include "media/webm/webm_content_encodings.h"
15 static TextKind
CodecIdToTextKind(const std::string
& codec_id
) {
16 if (codec_id
== kWebMCodecSubtitles
)
17 return kTextSubtitles
;
19 if (codec_id
== kWebMCodecCaptions
)
22 if (codec_id
== kWebMCodecDescriptions
)
23 return kTextDescriptions
;
25 if (codec_id
== kWebMCodecMetadata
)
31 WebMTracksParser::WebMTracksParser(const LogCB
& log_cb
, bool ignore_text_tracks
)
38 ignore_text_tracks_(ignore_text_tracks
),
40 audio_client_(log_cb
),
41 video_client_(log_cb
) {
44 WebMTracksParser::~WebMTracksParser() {}
46 int WebMTracksParser::Parse(const uint8
* buf
, int size
) {
50 track_language_
.clear();
51 audio_track_num_
= -1;
52 audio_decoder_config_
= AudioDecoderConfig();
53 video_track_num_
= -1;
54 video_decoder_config_
= VideoDecoderConfig();
56 ignored_tracks_
.clear();
58 WebMListParser
parser(kWebMIdTracks
, this);
59 int result
= parser
.Parse(buf
, size
);
64 // For now we do all or nothing parsing.
65 return parser
.IsParsingComplete() ? result
: 0;
68 WebMParserClient
* WebMTracksParser::OnListStart(int id
) {
69 if (id
== kWebMIdContentEncodings
) {
70 DCHECK(!track_content_encodings_client_
.get());
71 track_content_encodings_client_
.reset(
72 new WebMContentEncodingsClient(log_cb_
));
73 return track_content_encodings_client_
->OnListStart(id
);
76 if (id
== kWebMIdTrackEntry
) {
80 track_language_
.clear();
82 codec_private_
.clear();
83 audio_client_
.Reset();
84 video_client_
.Reset();
88 if (id
== kWebMIdAudio
)
89 return &audio_client_
;
91 if (id
== kWebMIdVideo
)
92 return &video_client_
;
97 bool WebMTracksParser::OnListEnd(int id
) {
98 if (id
== kWebMIdContentEncodings
) {
99 DCHECK(track_content_encodings_client_
.get());
100 return track_content_encodings_client_
->OnListEnd(id
);
103 if (id
== kWebMIdTrackEntry
) {
104 if (track_type_
== -1 || track_num_
== -1) {
105 MEDIA_LOG(log_cb_
) << "Missing TrackEntry data for "
106 << " TrackType " << track_type_
107 << " TrackNum " << track_num_
;
111 if (track_type_
!= kWebMTrackTypeAudio
&&
112 track_type_
!= kWebMTrackTypeVideo
&&
113 track_type_
!= kWebMTrackTypeSubtitlesOrCaptions
&&
114 track_type_
!= kWebMTrackTypeDescriptionsOrMetadata
) {
115 MEDIA_LOG(log_cb_
) << "Unexpected TrackType " << track_type_
;
119 TextKind text_track_kind
= kTextNone
;
120 if (track_type_
== kWebMTrackTypeSubtitlesOrCaptions
) {
121 text_track_kind
= CodecIdToTextKind(codec_id_
);
122 if (text_track_kind
== kTextNone
) {
123 MEDIA_LOG(log_cb_
) << "Missing TrackEntry CodecID"
124 << " TrackNum " << track_num_
;
128 if (text_track_kind
!= kTextSubtitles
&&
129 text_track_kind
!= kTextCaptions
) {
130 MEDIA_LOG(log_cb_
) << "Wrong TrackEntry CodecID"
131 << " TrackNum " << track_num_
;
134 } else if (track_type_
== kWebMTrackTypeDescriptionsOrMetadata
) {
135 text_track_kind
= CodecIdToTextKind(codec_id_
);
136 if (text_track_kind
== kTextNone
) {
137 MEDIA_LOG(log_cb_
) << "Missing TrackEntry CodecID"
138 << " TrackNum " << track_num_
;
142 if (text_track_kind
!= kTextDescriptions
&&
143 text_track_kind
!= kTextMetadata
) {
144 MEDIA_LOG(log_cb_
) << "Wrong TrackEntry CodecID"
145 << " TrackNum " << track_num_
;
150 std::string encryption_key_id
;
151 if (track_content_encodings_client_
) {
152 DCHECK(!track_content_encodings_client_
->content_encodings().empty());
153 // If we have multiple ContentEncoding in one track. Always choose the
154 // key id in the first ContentEncoding as the key id of the track.
155 encryption_key_id
= track_content_encodings_client_
->
156 content_encodings()[0]->encryption_key_id();
159 if (track_type_
== kWebMTrackTypeAudio
) {
160 if (audio_track_num_
== -1) {
161 audio_track_num_
= track_num_
;
162 audio_encryption_key_id_
= encryption_key_id
;
164 DCHECK(!audio_decoder_config_
.IsValidConfig());
165 if (!audio_client_
.InitializeConfig(
166 codec_id_
, codec_private_
, seek_preroll_
, codec_delay_
,
167 !audio_encryption_key_id_
.empty(), &audio_decoder_config_
)) {
171 MEDIA_LOG(log_cb_
) << "Ignoring audio track " << track_num_
;
172 ignored_tracks_
.insert(track_num_
);
174 } else if (track_type_
== kWebMTrackTypeVideo
) {
175 if (video_track_num_
== -1) {
176 video_track_num_
= track_num_
;
177 video_encryption_key_id_
= encryption_key_id
;
179 DCHECK(!video_decoder_config_
.IsValidConfig());
180 if (!video_client_
.InitializeConfig(
181 codec_id_
, codec_private_
, !video_encryption_key_id_
.empty(),
182 &video_decoder_config_
)) {
186 MEDIA_LOG(log_cb_
) << "Ignoring video track " << track_num_
;
187 ignored_tracks_
.insert(track_num_
);
189 } else if (track_type_
== kWebMTrackTypeSubtitlesOrCaptions
||
190 track_type_
== kWebMTrackTypeDescriptionsOrMetadata
) {
191 if (ignore_text_tracks_
) {
192 MEDIA_LOG(log_cb_
) << "Ignoring text track " << track_num_
;
193 ignored_tracks_
.insert(track_num_
);
195 TextTrackInfo
& text_track_info
= text_tracks_
[track_num_
];
196 text_track_info
.kind
= text_track_kind
;
197 text_track_info
.name
= track_name_
;
198 text_track_info
.language
= track_language_
;
201 MEDIA_LOG(log_cb_
) << "Unexpected TrackType " << track_type_
;
208 track_language_
.clear();
210 codec_private_
.clear();
211 track_content_encodings_client_
.reset();
213 audio_client_
.Reset();
214 video_client_
.Reset();
221 bool WebMTracksParser::OnUInt(int id
, int64 val
) {
225 case kWebMIdTrackNumber
:
228 case kWebMIdTrackType
:
231 case kWebMIdSeekPreRoll
:
232 dst
= &seek_preroll_
;
234 case kWebMIdCodecDelay
:
242 MEDIA_LOG(log_cb_
) << "Multiple values for id " << std::hex
<< id
251 bool WebMTracksParser::OnFloat(int id
, double val
) {
255 bool WebMTracksParser::OnBinary(int id
, const uint8
* data
, int size
) {
256 if (id
== kWebMIdCodecPrivate
) {
257 if (!codec_private_
.empty()) {
258 MEDIA_LOG(log_cb_
) << "Multiple CodecPrivate fields in a track.";
262 codec_private_
.assign(data
, data
+ size
);
268 bool WebMTracksParser::OnString(int id
, const std::string
& str
) {
269 if (id
== kWebMIdCodecID
) {
270 if (!codec_id_
.empty()) {
271 MEDIA_LOG(log_cb_
) << "Multiple CodecID fields in a track";
279 if (id
== kWebMIdName
) {
284 if (id
== kWebMIdLanguage
) {
285 track_language_
= str
;