1 // Copyright (c) 2013 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/webm/tracks_builder.h" 6 7 #include "media/webm/webm_constants.h" 8 9 namespace media { 10 11 // Returns size of an integer, formatted using Matroska serialization. 12 static int GetUIntMkvSize(uint64 value) { 13 if (value < 0x07FULL) 14 return 1; 15 if (value < 0x03FFFULL) 16 return 2; 17 if (value < 0x01FFFFFULL) 18 return 3; 19 if (value < 0x0FFFFFFFULL) 20 return 4; 21 if (value < 0x07FFFFFFFFULL) 22 return 5; 23 if (value < 0x03FFFFFFFFFFULL) 24 return 6; 25 if (value < 0x01FFFFFFFFFFFFULL) 26 return 7; 27 return 8; 28 } 29 30 // Returns the minimium size required to serialize an integer value. 31 static int GetUIntSize(uint64 value) { 32 if (value < 0x0100ULL) 33 return 1; 34 if (value < 0x010000ULL) 35 return 2; 36 if (value < 0x01000000ULL) 37 return 3; 38 if (value < 0x0100000000ULL) 39 return 4; 40 if (value < 0x010000000000ULL) 41 return 5; 42 if (value < 0x01000000000000ULL) 43 return 6; 44 if (value < 0x0100000000000000ULL) 45 return 7; 46 return 8; 47 } 48 49 static int MasterElementSize(int element_id, int payload_size) { 50 return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size; 51 } 52 53 static int IntElementSize(int element_id, int value) { 54 return GetUIntSize(element_id) + 1 + GetUIntSize(value); 55 } 56 57 static int StringElementSize(int element_id, const std::string& value) { 58 return GetUIntSize(element_id) + 59 GetUIntMkvSize(value.length()) + 60 value.length(); 61 } 62 63 static void SerializeInt(uint8** buf_ptr, int* buf_size_ptr, 64 int64 value, int size) { 65 uint8*& buf = *buf_ptr; 66 int& buf_size = *buf_size_ptr; 67 68 for (int idx = 1; idx <= size; ++idx) { 69 *buf++ = static_cast<uint8>(value >> ((size - idx) * 8)); 70 --buf_size; 71 } 72 } 73 74 static void WriteElementId(uint8** buf, int* buf_size, int element_id) { 75 SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id)); 76 } 77 78 static void WriteUInt(uint8** buf, int* buf_size, uint64 value) { 79 const int size = GetUIntMkvSize(value); 80 value |= (1ULL << (size * 7)); // Matroska formatting 81 SerializeInt(buf, buf_size, value, size); 82 } 83 84 static void WriteMasterElement(uint8** buf, int* buf_size, 85 int element_id, int payload_size) { 86 WriteElementId(buf, buf_size, element_id); 87 WriteUInt(buf, buf_size, payload_size); 88 } 89 90 static void WriteIntElement(uint8** buf, int* buf_size, 91 int element_id, int value) { 92 WriteElementId(buf, buf_size, element_id); 93 94 const int size = GetUIntSize(value); 95 WriteUInt(buf, buf_size, size); 96 97 SerializeInt(buf, buf_size, value, size); 98 } 99 100 static void WriteStringElement(uint8** buf_ptr, int* buf_size_ptr, 101 int element_id, const std::string& value) { 102 uint8*& buf = *buf_ptr; 103 int& buf_size = *buf_size_ptr; 104 105 WriteElementId(&buf, &buf_size, element_id); 106 107 const uint64 size = value.length(); 108 WriteUInt(&buf, &buf_size, size); 109 110 memcpy(buf, value.data(), size); 111 buf += size; 112 buf_size -= size; 113 } 114 115 TracksBuilder::TracksBuilder() {} 116 TracksBuilder::~TracksBuilder() {} 117 118 void TracksBuilder::AddTrack( 119 int track_num, 120 int track_type, 121 int track_uid, 122 const std::string& codec_id, 123 const std::string& name, 124 const std::string& language) { 125 tracks_.push_back(Track(track_num, track_type, track_uid, codec_id, name, 126 language)); 127 } 128 129 std::vector<uint8> TracksBuilder::Finish() { 130 // Allocate the storage 131 std::vector<uint8> buffer; 132 buffer.resize(GetTracksSize()); 133 134 // Populate the storage with a tracks header 135 WriteTracks(&buffer[0], buffer.size()); 136 137 return buffer; 138 } 139 140 int TracksBuilder::GetTracksSize() const { 141 return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize()); 142 } 143 144 int TracksBuilder::GetTracksPayloadSize() const { 145 int payload_size = 0; 146 147 for (TrackList::const_iterator itr = tracks_.begin(); 148 itr != tracks_.end(); ++itr) { 149 payload_size += itr->GetSize(); 150 } 151 152 return payload_size; 153 } 154 155 void TracksBuilder::WriteTracks(uint8* buf, int buf_size) const { 156 WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize()); 157 158 for (TrackList::const_iterator itr = tracks_.begin(); 159 itr != tracks_.end(); ++itr) { 160 itr->Write(&buf, &buf_size); 161 } 162 } 163 164 TracksBuilder::Track::Track(int track_num, int track_type, int track_uid, 165 const std::string& codec_id, 166 const std::string& name, 167 const std::string& language) 168 : track_num_(track_num), 169 track_type_(track_type), 170 track_uid_(track_uid), 171 codec_id_(codec_id), 172 name_(name), 173 language_(language) { 174 } 175 176 int TracksBuilder::Track::GetSize() const { 177 return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize()); 178 } 179 180 int TracksBuilder::Track::GetPayloadSize() const { 181 int size = 0; 182 183 size += IntElementSize(kWebMIdTrackNumber, track_num_); 184 size += IntElementSize(kWebMIdTrackType, track_type_); 185 size += IntElementSize(kWebMIdTrackUID, track_uid_); 186 187 if (!codec_id_.empty()) 188 size += StringElementSize(kWebMIdCodecID, codec_id_); 189 190 if (!name_.empty()) 191 size += StringElementSize(kWebMIdName, name_); 192 193 if (!language_.empty()) 194 size += StringElementSize(kWebMIdLanguage, language_); 195 196 return size; 197 } 198 199 void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const { 200 WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize()); 201 202 WriteIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_); 203 WriteIntElement(buf, buf_size, kWebMIdTrackType, track_type_); 204 WriteIntElement(buf, buf_size, kWebMIdTrackUID, track_uid_); 205 206 if (!codec_id_.empty()) 207 WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_); 208 209 if (!name_.empty()) 210 WriteStringElement(buf, buf_size, kWebMIdName, name_); 211 212 if (!language_.empty()) 213 WriteStringElement(buf, buf_size, kWebMIdLanguage, language_); 214 } 215 216 } // namespace media 217