5 #include <packager/media/formats/webm/tracks_builder.h>
7 #include <absl/log/check.h>
8 #include <absl/log/log.h>
10 #include <packager/media/formats/webm/webm_constants.h>
16 static int GetUIntMkvSize(uint64_t value) {
19 if (value < 0x03FFFULL)
21 if (value < 0x01FFFFFULL)
23 if (value < 0x0FFFFFFFULL)
25 if (value < 0x07FFFFFFFFULL)
27 if (value < 0x03FFFFFFFFFFULL)
29 if (value < 0x01FFFFFFFFFFFFULL)
35 static int GetUIntSize(uint64_t value) {
36 if (value < 0x0100ULL)
38 if (value < 0x010000ULL)
40 if (value < 0x01000000ULL)
42 if (value < 0x0100000000ULL)
44 if (value < 0x010000000000ULL)
46 if (value < 0x01000000000000ULL)
48 if (value < 0x0100000000000000ULL)
53 static int MasterElementSize(
int element_id,
int payload_size) {
54 return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
57 static int UIntElementSize(
int element_id, uint64_t value) {
58 return GetUIntSize(element_id) + 1 + GetUIntSize(value);
61 static int DoubleElementSize(
int element_id) {
62 return GetUIntSize(element_id) + 1 + 8;
65 static int StringElementSize(
int element_id,
const std::string& value) {
66 return GetUIntSize(element_id) + GetUIntMkvSize(value.length()) +
67 static_cast<int>(value.length());
70 static void SerializeInt(uint8_t** buf_ptr,
74 uint8_t*& buf = *buf_ptr;
75 int& buf_size = *buf_size_ptr;
77 for (
int idx = 1; idx <= size; ++idx) {
78 *buf++ =
static_cast<uint8_t
>(value >> ((size - idx) * 8));
83 static void SerializeDouble(uint8_t** buf_ptr,
94 SerializeInt(buf_ptr, buf_size_ptr, tmp.dst, 8);
97 static void WriteElementId(uint8_t** buf,
int* buf_size,
int element_id) {
98 SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
101 static void WriteUInt(uint8_t** buf,
int* buf_size, uint64_t value) {
102 const int size = GetUIntMkvSize(value);
103 value |= (1ULL << (size * 7));
104 SerializeInt(buf, buf_size, value, size);
107 static void WriteMasterElement(uint8_t** buf,
111 WriteElementId(buf, buf_size, element_id);
112 WriteUInt(buf, buf_size, payload_size);
115 static void WriteUIntElement(uint8_t** buf,
119 WriteElementId(buf, buf_size, element_id);
121 const int size = GetUIntSize(value);
122 WriteUInt(buf, buf_size, size);
124 SerializeInt(buf, buf_size, value, size);
127 static void WriteDoubleElement(uint8_t** buf,
131 WriteElementId(buf, buf_size, element_id);
132 WriteUInt(buf, buf_size, 8);
133 SerializeDouble(buf, buf_size, value);
136 static void WriteStringElement(uint8_t** buf_ptr,
139 const std::string& value) {
140 uint8_t*& buf = *buf_ptr;
141 int& buf_size = *buf_size_ptr;
143 WriteElementId(&buf, &buf_size, element_id);
145 const uint64_t size = value.length();
146 WriteUInt(&buf, &buf_size, size);
148 memcpy(buf, value.data(), size);
153 TracksBuilder::TracksBuilder(
bool allow_invalid_values)
154 : allow_invalid_values_(allow_invalid_values) {}
155 TracksBuilder::TracksBuilder()
156 : allow_invalid_values_(false) {}
157 TracksBuilder::~TracksBuilder() {}
159 void TracksBuilder::AddVideoTrack(
int track_num,
161 const std::string& codec_id,
162 const std::string& name,
163 const std::string& language,
164 int default_duration,
165 int video_pixel_width,
166 int video_pixel_height) {
167 AddTrackInternal(track_num, kWebMTrackTypeVideo, track_uid, codec_id, name,
168 language, default_duration, video_pixel_width,
169 video_pixel_height, -1, -1);
172 void TracksBuilder::AddAudioTrack(
int track_num,
174 const std::string& codec_id,
175 const std::string& name,
176 const std::string& language,
177 int default_duration,
179 double audio_sampling_frequency) {
180 AddTrackInternal(track_num, kWebMTrackTypeAudio, track_uid, codec_id, name,
181 language, default_duration, -1, -1, audio_channels,
182 audio_sampling_frequency);
185 void TracksBuilder::AddTextTrack(
int track_num,
187 const std::string& codec_id,
188 const std::string& name,
189 const std::string& language) {
190 AddTrackInternal(track_num, kWebMTrackTypeSubtitlesOrCaptions, track_uid,
191 codec_id, name, language, -1, -1, -1, -1, -1);
194 std::vector<uint8_t> TracksBuilder::Finish() {
196 std::vector<uint8_t> buffer;
197 buffer.resize(GetTracksSize());
200 WriteTracks(&buffer[0],
static_cast<int>(buffer.size()));
205 void TracksBuilder::AddTrackInternal(
int track_num,
208 const std::string& codec_id,
209 const std::string& name,
210 const std::string& language,
211 int default_duration,
212 int video_pixel_width,
213 int video_pixel_height,
215 double audio_sampling_frequency) {
216 tracks_.push_back(Track(track_num, track_type, track_uid, codec_id, name,
217 language, default_duration, video_pixel_width,
218 video_pixel_height, audio_channels,
219 audio_sampling_frequency, allow_invalid_values_));
222 int TracksBuilder::GetTracksSize()
const {
223 return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
226 int TracksBuilder::GetTracksPayloadSize()
const {
227 int payload_size = 0;
229 for (TrackList::const_iterator itr = tracks_.begin();
230 itr != tracks_.end(); ++itr) {
231 payload_size += itr->GetSize();
237 void TracksBuilder::WriteTracks(uint8_t* buf,
int buf_size)
const {
238 WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
240 for (TrackList::const_iterator itr = tracks_.begin();
241 itr != tracks_.end(); ++itr) {
242 itr->Write(&buf, &buf_size);
246 TracksBuilder::Track::Track(
int track_num,
249 const std::string& codec_id,
250 const std::string& name,
251 const std::string& language,
252 int default_duration,
253 int video_pixel_width,
254 int video_pixel_height,
256 double audio_sampling_frequency,
257 bool allow_invalid_values)
258 : track_num_(track_num),
259 track_type_(track_type),
260 track_uid_(track_uid),
264 default_duration_(default_duration),
265 video_pixel_width_(video_pixel_width),
266 video_pixel_height_(video_pixel_height),
267 audio_channels_(audio_channels),
268 audio_sampling_frequency_(audio_sampling_frequency) {
269 if (!allow_invalid_values) {
270 CHECK_GT(track_num_, 0);
271 CHECK_GT(track_type_, 0);
272 CHECK_LT(track_type_, 255);
273 CHECK_GT(track_uid_, 0);
274 if (track_type != kWebMTrackTypeVideo &&
275 track_type != kWebMTrackTypeAudio) {
276 CHECK_EQ(default_duration_, -1);
278 CHECK(default_duration_ == -1 || default_duration_ > 0);
281 if (track_type == kWebMTrackTypeVideo) {
282 CHECK_GT(video_pixel_width_, 0);
283 CHECK_GT(video_pixel_height_, 0);
285 CHECK_EQ(video_pixel_width_, -1);
286 CHECK_EQ(video_pixel_height_, -1);
289 if (track_type == kWebMTrackTypeAudio) {
290 CHECK_GT(audio_channels_, 0);
291 CHECK_GT(audio_sampling_frequency_, 0.0);
293 CHECK_EQ(audio_channels_, -1);
294 CHECK_EQ(audio_sampling_frequency_, -1.0);
299 int TracksBuilder::Track::GetSize()
const {
300 return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
303 int TracksBuilder::Track::GetVideoPayloadSize()
const {
304 int payload_size = 0;
306 if (video_pixel_width_ >= 0)
307 payload_size += UIntElementSize(kWebMIdPixelWidth, video_pixel_width_);
308 if (video_pixel_height_ >= 0)
309 payload_size += UIntElementSize(kWebMIdPixelHeight, video_pixel_height_);
314 int TracksBuilder::Track::GetAudioPayloadSize()
const {
315 int payload_size = 0;
317 if (audio_channels_ >= 0)
318 payload_size += UIntElementSize(kWebMIdChannels, audio_channels_);
319 if (audio_sampling_frequency_ >= 0)
320 payload_size += DoubleElementSize(kWebMIdSamplingFrequency);
325 int TracksBuilder::Track::GetPayloadSize()
const {
328 size += UIntElementSize(kWebMIdTrackNumber, track_num_);
329 size += UIntElementSize(kWebMIdTrackType, track_type_);
330 size += UIntElementSize(kWebMIdTrackUID, track_uid_);
332 if (default_duration_ >= 0)
333 size += UIntElementSize(kWebMIdDefaultDuration, default_duration_);
335 if (!codec_id_.empty())
336 size += StringElementSize(kWebMIdCodecID, codec_id_);
339 size += StringElementSize(kWebMIdName, name_);
341 if (!language_.empty())
342 size += StringElementSize(kWebMIdLanguage, language_);
344 if (GetVideoPayloadSize() > 0) {
345 size += MasterElementSize(kWebMIdVideo, GetVideoPayloadSize());
348 if (GetAudioPayloadSize() > 0) {
349 size += MasterElementSize(kWebMIdAudio, GetAudioPayloadSize());
355 void TracksBuilder::Track::Write(uint8_t** buf,
int* buf_size)
const {
356 WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
358 WriteUIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
359 WriteUIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
360 WriteUIntElement(buf, buf_size, kWebMIdTrackUID, track_uid_);
362 if (default_duration_ >= 0)
363 WriteUIntElement(buf, buf_size, kWebMIdDefaultDuration, default_duration_);
365 if (!codec_id_.empty())
366 WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
369 WriteStringElement(buf, buf_size, kWebMIdName, name_);
371 if (!language_.empty())
372 WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);
374 if (GetVideoPayloadSize() > 0) {
375 WriteMasterElement(buf, buf_size, kWebMIdVideo, GetVideoPayloadSize());
377 if (video_pixel_width_ >= 0)
378 WriteUIntElement(buf, buf_size, kWebMIdPixelWidth, video_pixel_width_);
380 if (video_pixel_height_ >= 0)
381 WriteUIntElement(buf, buf_size, kWebMIdPixelHeight, video_pixel_height_);
384 if (GetAudioPayloadSize() > 0) {
385 WriteMasterElement(buf, buf_size, kWebMIdAudio, GetAudioPayloadSize());
387 if (audio_channels_ >= 0)
388 WriteUIntElement(buf, buf_size, kWebMIdChannels, audio_channels_);
390 if (audio_sampling_frequency_ >= 0) {
391 WriteDoubleElement(buf, buf_size, kWebMIdSamplingFrequency,
392 audio_sampling_frequency_);
All the methods that are virtual are virtual for mocking.