Shaka Packager SDK
tracks_builder.cc
1 // Copyright 2014 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.
4 
5 #include <packager/media/formats/webm/tracks_builder.h>
6 
7 #include <absl/log/check.h>
8 #include <absl/log/log.h>
9 
10 #include <packager/media/formats/webm/webm_constants.h>
11 
12 namespace shaka {
13 namespace media {
14 
15 // Returns size of an integer, formatted using Matroska serialization.
16 static int GetUIntMkvSize(uint64_t value) {
17  if (value < 0x07FULL)
18  return 1;
19  if (value < 0x03FFFULL)
20  return 2;
21  if (value < 0x01FFFFFULL)
22  return 3;
23  if (value < 0x0FFFFFFFULL)
24  return 4;
25  if (value < 0x07FFFFFFFFULL)
26  return 5;
27  if (value < 0x03FFFFFFFFFFULL)
28  return 6;
29  if (value < 0x01FFFFFFFFFFFFULL)
30  return 7;
31  return 8;
32 }
33 
34 // Returns the minimium size required to serialize an integer value.
35 static int GetUIntSize(uint64_t value) {
36  if (value < 0x0100ULL)
37  return 1;
38  if (value < 0x010000ULL)
39  return 2;
40  if (value < 0x01000000ULL)
41  return 3;
42  if (value < 0x0100000000ULL)
43  return 4;
44  if (value < 0x010000000000ULL)
45  return 5;
46  if (value < 0x01000000000000ULL)
47  return 6;
48  if (value < 0x0100000000000000ULL)
49  return 7;
50  return 8;
51 }
52 
53 static int MasterElementSize(int element_id, int payload_size) {
54  return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
55 }
56 
57 static int UIntElementSize(int element_id, uint64_t value) {
58  return GetUIntSize(element_id) + 1 + GetUIntSize(value);
59 }
60 
61 static int DoubleElementSize(int element_id) {
62  return GetUIntSize(element_id) + 1 + 8;
63 }
64 
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());
68 }
69 
70 static void SerializeInt(uint8_t** buf_ptr,
71  int* buf_size_ptr,
72  int64_t value,
73  int size) {
74  uint8_t*& buf = *buf_ptr;
75  int& buf_size = *buf_size_ptr;
76 
77  for (int idx = 1; idx <= size; ++idx) {
78  *buf++ = static_cast<uint8_t>(value >> ((size - idx) * 8));
79  --buf_size;
80  }
81 }
82 
83 static void SerializeDouble(uint8_t** buf_ptr,
84  int* buf_size_ptr,
85  double value) {
86  // Use a union to convert |value| to native endian integer bit pattern.
87  union {
88  double src;
89  int64_t dst;
90  } tmp;
91  tmp.src = value;
92 
93  // Write the bytes from native endian |tmp.dst| to big-endian form in |buf|.
94  SerializeInt(buf_ptr, buf_size_ptr, tmp.dst, 8);
95 }
96 
97 static void WriteElementId(uint8_t** buf, int* buf_size, int element_id) {
98  SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
99 }
100 
101 static void WriteUInt(uint8_t** buf, int* buf_size, uint64_t value) {
102  const int size = GetUIntMkvSize(value);
103  value |= (1ULL << (size * 7)); // Matroska formatting
104  SerializeInt(buf, buf_size, value, size);
105 }
106 
107 static void WriteMasterElement(uint8_t** buf,
108  int* buf_size,
109  int element_id,
110  int payload_size) {
111  WriteElementId(buf, buf_size, element_id);
112  WriteUInt(buf, buf_size, payload_size);
113 }
114 
115 static void WriteUIntElement(uint8_t** buf,
116  int* buf_size,
117  int element_id,
118  uint64_t value) {
119  WriteElementId(buf, buf_size, element_id);
120 
121  const int size = GetUIntSize(value);
122  WriteUInt(buf, buf_size, size);
123 
124  SerializeInt(buf, buf_size, value, size);
125 }
126 
127 static void WriteDoubleElement(uint8_t** buf,
128  int* buf_size,
129  int element_id,
130  double value) {
131  WriteElementId(buf, buf_size, element_id);
132  WriteUInt(buf, buf_size, 8);
133  SerializeDouble(buf, buf_size, value);
134 }
135 
136 static void WriteStringElement(uint8_t** buf_ptr,
137  int* buf_size_ptr,
138  int element_id,
139  const std::string& value) {
140  uint8_t*& buf = *buf_ptr;
141  int& buf_size = *buf_size_ptr;
142 
143  WriteElementId(&buf, &buf_size, element_id);
144 
145  const uint64_t size = value.length();
146  WriteUInt(&buf, &buf_size, size);
147 
148  memcpy(buf, value.data(), size);
149  buf += size;
150  buf_size -= size;
151 }
152 
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() {}
158 
159 void TracksBuilder::AddVideoTrack(int track_num,
160  uint64_t track_uid,
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);
170 }
171 
172 void TracksBuilder::AddAudioTrack(int track_num,
173  uint64_t track_uid,
174  const std::string& codec_id,
175  const std::string& name,
176  const std::string& language,
177  int default_duration,
178  int audio_channels,
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);
183 }
184 
185 void TracksBuilder::AddTextTrack(int track_num,
186  uint64_t track_uid,
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);
192 }
193 
194 std::vector<uint8_t> TracksBuilder::Finish() {
195  // Allocate the storage
196  std::vector<uint8_t> buffer;
197  buffer.resize(GetTracksSize());
198 
199  // Populate the storage with a tracks header
200  WriteTracks(&buffer[0], static_cast<int>(buffer.size()));
201 
202  return buffer;
203 }
204 
205 void TracksBuilder::AddTrackInternal(int track_num,
206  int track_type,
207  uint64_t track_uid,
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,
214  int audio_channels,
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_));
220 }
221 
222 int TracksBuilder::GetTracksSize() const {
223  return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
224 }
225 
226 int TracksBuilder::GetTracksPayloadSize() const {
227  int payload_size = 0;
228 
229  for (TrackList::const_iterator itr = tracks_.begin();
230  itr != tracks_.end(); ++itr) {
231  payload_size += itr->GetSize();
232  }
233 
234  return payload_size;
235 }
236 
237 void TracksBuilder::WriteTracks(uint8_t* buf, int buf_size) const {
238  WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
239 
240  for (TrackList::const_iterator itr = tracks_.begin();
241  itr != tracks_.end(); ++itr) {
242  itr->Write(&buf, &buf_size);
243  }
244 }
245 
246 TracksBuilder::Track::Track(int track_num,
247  int track_type,
248  uint64_t track_uid,
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,
255  int audio_channels,
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),
261  codec_id_(codec_id),
262  name_(name),
263  language_(language),
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);
277  } else {
278  CHECK(default_duration_ == -1 || default_duration_ > 0);
279  }
280 
281  if (track_type == kWebMTrackTypeVideo) {
282  CHECK_GT(video_pixel_width_, 0);
283  CHECK_GT(video_pixel_height_, 0);
284  } else {
285  CHECK_EQ(video_pixel_width_, -1);
286  CHECK_EQ(video_pixel_height_, -1);
287  }
288 
289  if (track_type == kWebMTrackTypeAudio) {
290  CHECK_GT(audio_channels_, 0);
291  CHECK_GT(audio_sampling_frequency_, 0.0);
292  } else {
293  CHECK_EQ(audio_channels_, -1);
294  CHECK_EQ(audio_sampling_frequency_, -1.0);
295  }
296  }
297 }
298 
299 int TracksBuilder::Track::GetSize() const {
300  return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
301 }
302 
303 int TracksBuilder::Track::GetVideoPayloadSize() const {
304  int payload_size = 0;
305 
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_);
310 
311  return payload_size;
312 }
313 
314 int TracksBuilder::Track::GetAudioPayloadSize() const {
315  int payload_size = 0;
316 
317  if (audio_channels_ >= 0)
318  payload_size += UIntElementSize(kWebMIdChannels, audio_channels_);
319  if (audio_sampling_frequency_ >= 0)
320  payload_size += DoubleElementSize(kWebMIdSamplingFrequency);
321 
322  return payload_size;
323 }
324 
325 int TracksBuilder::Track::GetPayloadSize() const {
326  int size = 0;
327 
328  size += UIntElementSize(kWebMIdTrackNumber, track_num_);
329  size += UIntElementSize(kWebMIdTrackType, track_type_);
330  size += UIntElementSize(kWebMIdTrackUID, track_uid_);
331 
332  if (default_duration_ >= 0)
333  size += UIntElementSize(kWebMIdDefaultDuration, default_duration_);
334 
335  if (!codec_id_.empty())
336  size += StringElementSize(kWebMIdCodecID, codec_id_);
337 
338  if (!name_.empty())
339  size += StringElementSize(kWebMIdName, name_);
340 
341  if (!language_.empty())
342  size += StringElementSize(kWebMIdLanguage, language_);
343 
344  if (GetVideoPayloadSize() > 0) {
345  size += MasterElementSize(kWebMIdVideo, GetVideoPayloadSize());
346  }
347 
348  if (GetAudioPayloadSize() > 0) {
349  size += MasterElementSize(kWebMIdAudio, GetAudioPayloadSize());
350  }
351 
352  return size;
353 }
354 
355 void TracksBuilder::Track::Write(uint8_t** buf, int* buf_size) const {
356  WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
357 
358  WriteUIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
359  WriteUIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
360  WriteUIntElement(buf, buf_size, kWebMIdTrackUID, track_uid_);
361 
362  if (default_duration_ >= 0)
363  WriteUIntElement(buf, buf_size, kWebMIdDefaultDuration, default_duration_);
364 
365  if (!codec_id_.empty())
366  WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
367 
368  if (!name_.empty())
369  WriteStringElement(buf, buf_size, kWebMIdName, name_);
370 
371  if (!language_.empty())
372  WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);
373 
374  if (GetVideoPayloadSize() > 0) {
375  WriteMasterElement(buf, buf_size, kWebMIdVideo, GetVideoPayloadSize());
376 
377  if (video_pixel_width_ >= 0)
378  WriteUIntElement(buf, buf_size, kWebMIdPixelWidth, video_pixel_width_);
379 
380  if (video_pixel_height_ >= 0)
381  WriteUIntElement(buf, buf_size, kWebMIdPixelHeight, video_pixel_height_);
382  }
383 
384  if (GetAudioPayloadSize() > 0) {
385  WriteMasterElement(buf, buf_size, kWebMIdAudio, GetAudioPayloadSize());
386 
387  if (audio_channels_ >= 0)
388  WriteUIntElement(buf, buf_size, kWebMIdChannels, audio_channels_);
389 
390  if (audio_sampling_frequency_ >= 0) {
391  WriteDoubleElement(buf, buf_size, kWebMIdSamplingFrequency,
392  audio_sampling_frequency_);
393  }
394  }
395 }
396 
397 } // namespace media
398 } // namespace shaka
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66