5#include <packager/media/formats/webm/webm_tracks_parser.h>
12#include <absl/log/check.h>
13#include <absl/log/log.h>
14#include <absl/strings/str_format.h>
16#include <packager/media/base/text_track_config.h>
17#include <packager/media/base/timestamp.h>
18#include <packager/media/formats/webm/webm_constants.h>
19#include <packager/media/formats/webm/webm_content_encodings.h>
20#include <packager/media/formats/webm/webm_content_encodings_client.h>
21#include <packager/media/formats/webm/webm_parser.h>
26static TextKind CodecIdToTextKind(
const std::string& codec_id) {
27 if (codec_id == kWebMCodecSubtitles)
28 return kTextSubtitles;
30 if (codec_id == kWebMCodecCaptions)
33 if (codec_id == kWebMCodecDescriptions)
34 return kTextDescriptions;
36 if (codec_id == kWebMCodecMetadata)
42static int64_t PrecisionCappedDefaultDuration(
const double timecode_scale_in_us,
43 const int64_t duration_in_ns) {
44 if (duration_in_ns <= 0)
47 int64_t mult = duration_in_ns / 1000;
48 mult /= timecode_scale_in_us;
52 mult =
static_cast<double>(mult) * timecode_scale_in_us;
56WebMTracksParser::WebMTracksParser(
bool ignore_text_tracks)
61 default_duration_(-1),
63 audio_default_duration_(-1),
65 video_default_duration_(-1),
66 ignore_text_tracks_(ignore_text_tracks),
70WebMTracksParser::~WebMTracksParser() {}
72int WebMTracksParser::Parse(
const uint8_t* buf,
int size) {
75 default_duration_ = -1;
77 track_language_.clear();
78 audio_track_num_ = -1;
79 audio_default_duration_ = -1;
80 audio_stream_info_ =
nullptr;
81 video_track_num_ = -1;
82 video_default_duration_ = -1;
83 video_stream_info_ =
nullptr;
85 ignored_tracks_.clear();
88 int result = parser.
Parse(buf, size);
97int64_t WebMTracksParser::GetAudioDefaultDuration(
98 const double timecode_scale_in_us)
const {
99 return PrecisionCappedDefaultDuration(timecode_scale_in_us,
100 audio_default_duration_);
103int64_t WebMTracksParser::GetVideoDefaultDuration(
104 const double timecode_scale_in_us)
const {
105 return PrecisionCappedDefaultDuration(timecode_scale_in_us,
106 video_default_duration_);
109WebMParserClient* WebMTracksParser::OnListStart(
int id) {
110 if (
id == kWebMIdContentEncodings) {
111 DCHECK(!track_content_encodings_client_.get());
112 track_content_encodings_client_.reset(
new WebMContentEncodingsClient());
113 return track_content_encodings_client_->OnListStart(
id);
116 if (
id == kWebMIdTrackEntry) {
119 default_duration_ = -1;
121 track_language_.clear();
123 codec_private_.clear();
124 audio_client_.Reset();
125 video_client_.Reset();
129 if (
id == kWebMIdAudio)
130 return &audio_client_;
132 if (
id == kWebMIdVideo)
133 return &video_client_;
138bool WebMTracksParser::OnListEnd(
int id) {
139 if (
id == kWebMIdContentEncodings) {
140 DCHECK(track_content_encodings_client_.get());
141 return track_content_encodings_client_->OnListEnd(
id);
144 if (
id == kWebMIdTrackEntry) {
145 if (track_type_ == -1 || track_num_ == -1) {
146 LOG(ERROR) <<
"Missing TrackEntry data for "
147 <<
" TrackType " << track_type_ <<
" TrackNum " << track_num_;
151 if (track_type_ != kWebMTrackTypeAudio &&
152 track_type_ != kWebMTrackTypeVideo &&
153 track_type_ != kWebMTrackTypeSubtitlesOrCaptions &&
154 track_type_ != kWebMTrackTypeDescriptionsOrMetadata) {
155 LOG(ERROR) <<
"Unexpected TrackType " << track_type_;
159 TextKind text_track_kind = kTextNone;
160 if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions) {
161 text_track_kind = CodecIdToTextKind(codec_id_);
162 if (text_track_kind == kTextNone) {
163 LOG(ERROR) <<
"Missing TrackEntry CodecID"
164 <<
" TrackNum " << track_num_;
168 if (text_track_kind != kTextSubtitles &&
169 text_track_kind != kTextCaptions) {
170 LOG(ERROR) <<
"Wrong TrackEntry CodecID"
171 <<
" TrackNum " << track_num_;
174 }
else if (track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
175 text_track_kind = CodecIdToTextKind(codec_id_);
176 if (text_track_kind == kTextNone) {
177 LOG(ERROR) <<
"Missing TrackEntry CodecID"
178 <<
" TrackNum " << track_num_;
182 if (text_track_kind != kTextDescriptions &&
183 text_track_kind != kTextMetadata) {
184 LOG(ERROR) <<
"Wrong TrackEntry CodecID"
185 <<
" TrackNum " << track_num_;
190 std::string encryption_key_id;
191 if (track_content_encodings_client_) {
192 DCHECK(!track_content_encodings_client_->content_encodings().empty());
196 track_content_encodings_client_->content_encodings()[0]
197 ->encryption_key_id();
200 if (track_type_ == kWebMTrackTypeAudio) {
201 if (audio_track_num_ == -1) {
202 audio_track_num_ = track_num_;
203 audio_encryption_key_id_ = encryption_key_id;
205 if (default_duration_ == 0) {
206 LOG(ERROR) <<
"Illegal 0ns audio TrackEntry "
210 audio_default_duration_ = default_duration_;
212 DCHECK(!audio_stream_info_);
213 audio_stream_info_ = audio_client_.GetAudioStreamInfo(
214 audio_track_num_, codec_id_, codec_private_, seek_preroll_,
215 codec_delay_, track_language_, !audio_encryption_key_id_.empty());
216 if (!audio_stream_info_)
219 DLOG(INFO) <<
"Ignoring audio track " << track_num_;
220 ignored_tracks_.insert(track_num_);
222 }
else if (track_type_ == kWebMTrackTypeVideo) {
223 if (video_track_num_ == -1) {
224 video_track_num_ = track_num_;
225 video_encryption_key_id_ = encryption_key_id;
227 if (default_duration_ == 0) {
228 LOG(ERROR) <<
"Illegal 0ns video TrackEntry "
232 video_default_duration_ = default_duration_;
234 DCHECK(!video_stream_info_);
235 video_stream_info_ = video_client_.GetVideoStreamInfo(
236 video_track_num_, codec_id_, codec_private_,
237 !video_encryption_key_id_.empty());
238 if (!video_stream_info_)
241 if (codec_id_ ==
"V_VP8" || codec_id_ ==
"V_VP9") {
242 vp_config_ = video_client_.GetVpCodecConfig(codec_private_);
243 const double kNanosecondsPerSecond = 1000000000.0;
244 if (codec_id_ ==
"V_VP9" &&
245 (!vp_config_.is_level_set() || vp_config_.level() == 0)) {
246 vp_config_.SetVP9Level(
247 video_stream_info_->width(), video_stream_info_->height(),
248 video_default_duration_ / kNanosecondsPerSecond);
253 DLOG(INFO) <<
"Ignoring video track " << track_num_;
254 ignored_tracks_.insert(track_num_);
256 }
else if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions ||
257 track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
258 if (ignore_text_tracks_) {
259 DLOG(INFO) <<
"Ignoring text track " << track_num_;
260 ignored_tracks_.insert(track_num_);
262 std::string track_num = absl::StrFormat(
"%d", track_num_);
263 text_tracks_[track_num_] = TextTrackConfig(text_track_kind, track_name_,
264 track_language_, track_num);
267 LOG(ERROR) <<
"Unexpected TrackType " << track_type_;
273 default_duration_ = -1;
275 track_language_.clear();
277 codec_private_.clear();
278 track_content_encodings_client_.reset();
280 audio_client_.Reset();
281 video_client_.Reset();
288bool WebMTracksParser::OnUInt(
int id, int64_t val) {
292 case kWebMIdTrackNumber:
295 case kWebMIdTrackType:
298 case kWebMIdSeekPreRoll:
299 dst = &seek_preroll_;
301 case kWebMIdCodecDelay:
304 case kWebMIdDefaultDuration:
305 dst = &default_duration_;
312 LOG(ERROR) <<
"Multiple values for id " << std::hex <<
id <<
" specified";
320bool WebMTracksParser::OnFloat(
int ,
double ) {
324bool WebMTracksParser::OnBinary(
int id,
const uint8_t* data,
int size) {
325 if (
id == kWebMIdCodecPrivate) {
326 if (!codec_private_.empty()) {
327 LOG(ERROR) <<
"Multiple CodecPrivate fields in a track.";
330 codec_private_.assign(data, data + size);
336bool WebMTracksParser::OnString(
int id,
const std::string& str) {
337 if (
id == kWebMIdCodecID) {
338 if (!codec_id_.empty()) {
339 LOG(ERROR) <<
"Multiple CodecID fields in a track";
347 if (
id == kWebMIdName) {
352 if (
id == kWebMIdLanguage) {
353 track_language_ = str;
All the methods that are virtual are virtual for mocking.