5 #include "packager/media/formats/webm/tracks_builder.h"
7 #include "packager/base/logging.h"
8 #include "packager/media/formats/webm/webm_constants.h"
14 static int GetUIntMkvSize(uint64_t value) {
17 if (value < 0x03FFFULL)
19 if (value < 0x01FFFFFULL)
21 if (value < 0x0FFFFFFFULL)
23 if (value < 0x07FFFFFFFFULL)
25 if (value < 0x03FFFFFFFFFFULL)
27 if (value < 0x01FFFFFFFFFFFFULL)
33 static int GetUIntSize(uint64_t value) {
34 if (value < 0x0100ULL)
36 if (value < 0x010000ULL)
38 if (value < 0x01000000ULL)
40 if (value < 0x0100000000ULL)
42 if (value < 0x010000000000ULL)
44 if (value < 0x01000000000000ULL)
46 if (value < 0x0100000000000000ULL)
51 static int MasterElementSize(
int element_id,
int payload_size) {
52 return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
55 static int UIntElementSize(
int element_id, uint64_t value) {
56 return GetUIntSize(element_id) + 1 + GetUIntSize(value);
59 static int DoubleElementSize(
int element_id) {
60 return GetUIntSize(element_id) + 1 + 8;
63 static int StringElementSize(
int element_id,
const std::string& value) {
64 return GetUIntSize(element_id) + GetUIntMkvSize(value.length()) +
65 static_cast<int>(value.length());
68 static void SerializeInt(uint8_t** buf_ptr,
72 uint8_t*& buf = *buf_ptr;
73 int& buf_size = *buf_size_ptr;
75 for (
int idx = 1; idx <= size; ++idx) {
76 *buf++ =
static_cast<uint8_t
>(value >> ((size - idx) * 8));
81 static void SerializeDouble(uint8_t** buf_ptr,
92 SerializeInt(buf_ptr, buf_size_ptr, tmp.dst, 8);
95 static void WriteElementId(uint8_t** buf,
int* buf_size,
int element_id) {
96 SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
99 static void WriteUInt(uint8_t** buf,
int* buf_size, uint64_t value) {
100 const int size = GetUIntMkvSize(value);
101 value |= (1ULL << (size * 7));
102 SerializeInt(buf, buf_size, value, size);
105 static void WriteMasterElement(uint8_t** buf,
109 WriteElementId(buf, buf_size, element_id);
110 WriteUInt(buf, buf_size, payload_size);
113 static void WriteUIntElement(uint8_t** buf,
117 WriteElementId(buf, buf_size, element_id);
119 const int size = GetUIntSize(value);
120 WriteUInt(buf, buf_size, size);
122 SerializeInt(buf, buf_size, value, size);
125 static void WriteDoubleElement(uint8_t** buf,
129 WriteElementId(buf, buf_size, element_id);
130 WriteUInt(buf, buf_size, 8);
131 SerializeDouble(buf, buf_size, value);
134 static void WriteStringElement(uint8_t** buf_ptr,
137 const std::string& value) {
138 uint8_t*& buf = *buf_ptr;
139 int& buf_size = *buf_size_ptr;
141 WriteElementId(&buf, &buf_size, element_id);
143 const uint64_t size = value.length();
144 WriteUInt(&buf, &buf_size, size);
146 memcpy(buf, value.data(), size);
151 TracksBuilder::TracksBuilder(
bool allow_invalid_values)
152 : allow_invalid_values_(allow_invalid_values) {}
153 TracksBuilder::TracksBuilder()
154 : allow_invalid_values_(false) {}
155 TracksBuilder::~TracksBuilder() {}
157 void TracksBuilder::AddVideoTrack(
int track_num,
159 const std::string& codec_id,
160 const std::string& name,
161 const std::string& language,
162 int default_duration,
163 int video_pixel_width,
164 int video_pixel_height) {
165 AddTrackInternal(track_num, kWebMTrackTypeVideo, track_uid, codec_id, name,
166 language, default_duration, video_pixel_width,
167 video_pixel_height, -1, -1);
170 void TracksBuilder::AddAudioTrack(
int track_num,
172 const std::string& codec_id,
173 const std::string& name,
174 const std::string& language,
175 int default_duration,
177 double audio_sampling_frequency) {
178 AddTrackInternal(track_num, kWebMTrackTypeAudio, track_uid, codec_id, name,
179 language, default_duration, -1, -1, audio_channels,
180 audio_sampling_frequency);
183 void TracksBuilder::AddTextTrack(
int track_num,
185 const std::string& codec_id,
186 const std::string& name,
187 const std::string& language) {
188 AddTrackInternal(track_num, kWebMTrackTypeSubtitlesOrCaptions, track_uid,
189 codec_id, name, language, -1, -1, -1, -1, -1);
192 std::vector<uint8_t> TracksBuilder::Finish() {
194 std::vector<uint8_t> buffer;
195 buffer.resize(GetTracksSize());
198 WriteTracks(&buffer[0], static_cast<int>(buffer.size()));
203 void TracksBuilder::AddTrackInternal(
int track_num,
206 const std::string& codec_id,
207 const std::string& name,
208 const std::string& language,
209 int default_duration,
210 int video_pixel_width,
211 int video_pixel_height,
213 double audio_sampling_frequency) {
214 tracks_.push_back(Track(track_num, track_type, track_uid, codec_id, name,
215 language, default_duration, video_pixel_width,
216 video_pixel_height, audio_channels,
217 audio_sampling_frequency, allow_invalid_values_));
220 int TracksBuilder::GetTracksSize()
const {
221 return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
224 int TracksBuilder::GetTracksPayloadSize()
const {
225 int payload_size = 0;
227 for (TrackList::const_iterator itr = tracks_.begin();
228 itr != tracks_.end(); ++itr) {
229 payload_size += itr->GetSize();
235 void TracksBuilder::WriteTracks(uint8_t* buf,
int buf_size)
const {
236 WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
238 for (TrackList::const_iterator itr = tracks_.begin();
239 itr != tracks_.end(); ++itr) {
240 itr->Write(&buf, &buf_size);
244 TracksBuilder::Track::Track(
int track_num,
247 const std::string& codec_id,
248 const std::string& name,
249 const std::string& language,
250 int default_duration,
251 int video_pixel_width,
252 int video_pixel_height,
254 double audio_sampling_frequency,
255 bool allow_invalid_values)
256 : track_num_(track_num),
257 track_type_(track_type),
258 track_uid_(track_uid),
262 default_duration_(default_duration),
263 video_pixel_width_(video_pixel_width),
264 video_pixel_height_(video_pixel_height),
265 audio_channels_(audio_channels),
266 audio_sampling_frequency_(audio_sampling_frequency) {
267 if (!allow_invalid_values) {
268 CHECK_GT(track_num_, 0);
269 CHECK_GT(track_type_, 0);
270 CHECK_LT(track_type_, 255);
271 CHECK_GT(track_uid_, 0);
272 if (track_type != kWebMTrackTypeVideo &&
273 track_type != kWebMTrackTypeAudio) {
274 CHECK_EQ(default_duration_, -1);
276 CHECK(default_duration_ == -1 || default_duration_ > 0);
279 if (track_type == kWebMTrackTypeVideo) {
280 CHECK_GT(video_pixel_width_, 0);
281 CHECK_GT(video_pixel_height_, 0);
283 CHECK_EQ(video_pixel_width_, -1);
284 CHECK_EQ(video_pixel_height_, -1);
287 if (track_type == kWebMTrackTypeAudio) {
288 CHECK_GT(audio_channels_, 0);
289 CHECK_GT(audio_sampling_frequency_, 0.0);
291 CHECK_EQ(audio_channels_, -1);
292 CHECK_EQ(audio_sampling_frequency_, -1.0);
297 int TracksBuilder::Track::GetSize()
const {
298 return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
301 int TracksBuilder::Track::GetVideoPayloadSize()
const {
302 int payload_size = 0;
304 if (video_pixel_width_ >= 0)
305 payload_size += UIntElementSize(kWebMIdPixelWidth, video_pixel_width_);
306 if (video_pixel_height_ >= 0)
307 payload_size += UIntElementSize(kWebMIdPixelHeight, video_pixel_height_);
312 int TracksBuilder::Track::GetAudioPayloadSize()
const {
313 int payload_size = 0;
315 if (audio_channels_ >= 0)
316 payload_size += UIntElementSize(kWebMIdChannels, audio_channels_);
317 if (audio_sampling_frequency_ >= 0)
318 payload_size += DoubleElementSize(kWebMIdSamplingFrequency);
323 int TracksBuilder::Track::GetPayloadSize()
const {
326 size += UIntElementSize(kWebMIdTrackNumber, track_num_);
327 size += UIntElementSize(kWebMIdTrackType, track_type_);
328 size += UIntElementSize(kWebMIdTrackUID, track_uid_);
330 if (default_duration_ >= 0)
331 size += UIntElementSize(kWebMIdDefaultDuration, default_duration_);
333 if (!codec_id_.empty())
334 size += StringElementSize(kWebMIdCodecID, codec_id_);
337 size += StringElementSize(kWebMIdName, name_);
339 if (!language_.empty())
340 size += StringElementSize(kWebMIdLanguage, language_);
342 if (GetVideoPayloadSize() > 0) {
343 size += MasterElementSize(kWebMIdVideo, GetVideoPayloadSize());
346 if (GetAudioPayloadSize() > 0) {
347 size += MasterElementSize(kWebMIdAudio, GetAudioPayloadSize());
353 void TracksBuilder::Track::Write(uint8_t** buf,
int* buf_size)
const {
354 WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
356 WriteUIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
357 WriteUIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
358 WriteUIntElement(buf, buf_size, kWebMIdTrackUID, track_uid_);
360 if (default_duration_ >= 0)
361 WriteUIntElement(buf, buf_size, kWebMIdDefaultDuration, default_duration_);
363 if (!codec_id_.empty())
364 WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
367 WriteStringElement(buf, buf_size, kWebMIdName, name_);
369 if (!language_.empty())
370 WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);
372 if (GetVideoPayloadSize() > 0) {
373 WriteMasterElement(buf, buf_size, kWebMIdVideo, GetVideoPayloadSize());
375 if (video_pixel_width_ >= 0)
376 WriteUIntElement(buf, buf_size, kWebMIdPixelWidth, video_pixel_width_);
378 if (video_pixel_height_ >= 0)
379 WriteUIntElement(buf, buf_size, kWebMIdPixelHeight, video_pixel_height_);
382 if (GetAudioPayloadSize() > 0) {
383 WriteMasterElement(buf, buf_size, kWebMIdAudio, GetAudioPayloadSize());
385 if (audio_channels_ >= 0)
386 WriteUIntElement(buf, buf_size, kWebMIdChannels, audio_channels_);
388 if (audio_sampling_frequency_ >= 0) {
389 WriteDoubleElement(buf, buf_size, kWebMIdSamplingFrequency,
390 audio_sampling_frequency_);