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