5 #include "packager/media/formats/webm/webm_tracks_parser.h"
7 #include "packager/base/logging.h"
8 #include "packager/base/strings/string_number_conversions.h"
9 #include "packager/base/strings/string_util.h"
10 #include "packager/media/base/timestamp.h"
11 #include "packager/media/formats/webm/webm_constants.h"
12 #include "packager/media/formats/webm/webm_content_encodings.h"
17 static TextKind CodecIdToTextKind(
const std::string& codec_id) {
18 if (codec_id == kWebMCodecSubtitles)
19 return kTextSubtitles;
21 if (codec_id == kWebMCodecCaptions)
24 if (codec_id == kWebMCodecDescriptions)
25 return kTextDescriptions;
27 if (codec_id == kWebMCodecMetadata)
33 static int64_t PrecisionCappedDefaultDuration(
34 const double timecode_scale_in_us,
35 const int64_t duration_in_ns) {
36 if (duration_in_ns <= 0)
39 int64_t mult = duration_in_ns / 1000;
40 mult /= timecode_scale_in_us;
44 mult =
static_cast<double>(mult) * timecode_scale_in_us;
48 WebMTracksParser::WebMTracksParser(
bool ignore_text_tracks)
53 default_duration_(-1),
55 audio_default_duration_(-1),
57 video_default_duration_(-1),
58 ignore_text_tracks_(ignore_text_tracks),
63 WebMTracksParser::~WebMTracksParser() {}
65 int WebMTracksParser::Parse(
const uint8_t* buf,
int size) {
68 default_duration_ = -1;
70 track_language_.clear();
71 audio_track_num_ = -1;
72 audio_default_duration_ = -1;
73 audio_stream_info_ =
nullptr;
74 video_track_num_ = -1;
75 video_default_duration_ = -1;
76 video_stream_info_ =
nullptr;
78 ignored_tracks_.clear();
81 int result = parser.
Parse(buf, size);
90 int64_t WebMTracksParser::GetAudioDefaultDuration(
91 const double timecode_scale_in_us)
const {
92 return PrecisionCappedDefaultDuration(timecode_scale_in_us,
93 audio_default_duration_);
96 int64_t WebMTracksParser::GetVideoDefaultDuration(
97 const double timecode_scale_in_us)
const {
98 return PrecisionCappedDefaultDuration(timecode_scale_in_us,
99 video_default_duration_);
102 WebMParserClient* WebMTracksParser::OnListStart(
int id) {
103 if (
id == kWebMIdContentEncodings) {
104 DCHECK(!track_content_encodings_client_.get());
105 track_content_encodings_client_.reset(
new WebMContentEncodingsClient());
106 return track_content_encodings_client_->OnListStart(
id);
109 if (
id == kWebMIdTrackEntry) {
112 default_duration_ = -1;
114 track_language_.clear();
116 codec_private_.clear();
117 audio_client_.Reset();
118 video_client_.Reset();
122 if (
id == kWebMIdAudio)
123 return &audio_client_;
125 if (
id == kWebMIdVideo)
126 return &video_client_;
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 LOG(ERROR) <<
"Missing TrackEntry data for "
140 <<
" TrackType " << track_type_ <<
" TrackNum " << track_num_;
144 if (track_type_ != kWebMTrackTypeAudio &&
145 track_type_ != kWebMTrackTypeVideo &&
146 track_type_ != kWebMTrackTypeSubtitlesOrCaptions &&
147 track_type_ != kWebMTrackTypeDescriptionsOrMetadata) {
148 LOG(ERROR) <<
"Unexpected TrackType " << track_type_;
152 TextKind text_track_kind = kTextNone;
153 if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions) {
154 text_track_kind = CodecIdToTextKind(codec_id_);
155 if (text_track_kind == kTextNone) {
156 LOG(ERROR) <<
"Missing TrackEntry CodecID"
157 <<
" TrackNum " << track_num_;
161 if (text_track_kind != kTextSubtitles &&
162 text_track_kind != kTextCaptions) {
163 LOG(ERROR) <<
"Wrong TrackEntry CodecID"
164 <<
" TrackNum " << track_num_;
167 }
else if (track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
168 text_track_kind = CodecIdToTextKind(codec_id_);
169 if (text_track_kind == kTextNone) {
170 LOG(ERROR) <<
"Missing TrackEntry CodecID"
171 <<
" TrackNum " << track_num_;
175 if (text_track_kind != kTextDescriptions &&
176 text_track_kind != kTextMetadata) {
177 LOG(ERROR) <<
"Wrong TrackEntry CodecID"
178 <<
" TrackNum " << track_num_;
183 std::string encryption_key_id;
184 if (track_content_encodings_client_) {
185 DCHECK(!track_content_encodings_client_->content_encodings().empty());
188 encryption_key_id = track_content_encodings_client_->
189 content_encodings()[0]->encryption_key_id();
192 if (track_type_ == kWebMTrackTypeAudio) {
193 if (audio_track_num_ == -1) {
194 audio_track_num_ = track_num_;
195 audio_encryption_key_id_ = encryption_key_id;
197 if (default_duration_ == 0) {
198 LOG(ERROR) <<
"Illegal 0ns audio TrackEntry "
202 audio_default_duration_ = default_duration_;
204 DCHECK(!audio_stream_info_);
205 audio_stream_info_ = audio_client_.GetAudioStreamInfo(
206 audio_track_num_, codec_id_, codec_private_, seek_preroll_,
207 codec_delay_, track_language_, !audio_encryption_key_id_.empty());
208 if (!audio_stream_info_)
211 DLOG(INFO) <<
"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 LOG(ERROR) <<
"Illegal 0ns video TrackEntry "
224 video_default_duration_ = default_duration_;
226 DCHECK(!video_stream_info_);
227 video_stream_info_ = video_client_.GetVideoStreamInfo(
228 video_track_num_, codec_id_, codec_private_,
229 !video_encryption_key_id_.empty());
230 if (!video_stream_info_)
233 if (codec_id_ ==
"V_VP8" || codec_id_ ==
"V_VP9") {
234 vp_config_ = video_client_.GetVpCodecConfig(codec_private_);
235 const double kNanosecondsPerSecond = 1000000000.0;
236 if (codec_id_ ==
"V_VP9" &&
237 (!vp_config_.is_level_set() || vp_config_.level() == 0)) {
238 vp_config_.SetVP9Level(
239 video_stream_info_->width(), video_stream_info_->height(),
240 video_default_duration_ / kNanosecondsPerSecond);
245 DLOG(INFO) <<
"Ignoring video track " << track_num_;
246 ignored_tracks_.insert(track_num_);
248 }
else if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions ||
249 track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
250 if (ignore_text_tracks_) {
251 DLOG(INFO) <<
"Ignoring text track " << track_num_;
252 ignored_tracks_.insert(track_num_);
254 std::string track_num = base::Int64ToString(track_num_);
255 text_tracks_[track_num_] = TextTrackConfig(
256 text_track_kind, track_name_, track_language_, track_num);
259 LOG(ERROR) <<
"Unexpected TrackType " << track_type_;
265 default_duration_ = -1;
267 track_language_.clear();
269 codec_private_.clear();
270 track_content_encodings_client_.reset();
272 audio_client_.Reset();
273 video_client_.Reset();
280 bool WebMTracksParser::OnUInt(
int id, int64_t val) {
284 case kWebMIdTrackNumber:
287 case kWebMIdTrackType:
290 case kWebMIdSeekPreRoll:
291 dst = &seek_preroll_;
293 case kWebMIdCodecDelay:
296 case kWebMIdDefaultDuration:
297 dst = &default_duration_;
304 LOG(ERROR) <<
"Multiple values for id " << std::hex <<
id <<
" specified";
312 bool WebMTracksParser::OnFloat(
int id,
double val) {
316 bool WebMTracksParser::OnBinary(
int id,
const uint8_t* data,
int size) {
317 if (
id == kWebMIdCodecPrivate) {
318 if (!codec_private_.empty()) {
319 LOG(ERROR) <<
"Multiple CodecPrivate fields in a track.";
322 codec_private_.assign(data, data + size);
328 bool WebMTracksParser::OnString(
int id,
const std::string& str) {
329 if (
id == kWebMIdCodecID) {
330 if (!codec_id_.empty()) {
331 LOG(ERROR) <<
"Multiple CodecID fields in a track";
339 if (
id == kWebMIdName) {
344 if (
id == kWebMIdLanguage) {
345 track_language_ = str;
All the methods that are virtual are virtual for mocking.