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