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.
GetUIntMkvSize(uint64 value)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.
GetUIntSize(uint64 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
MasterElementSize(int element_id,int payload_size)49 static int MasterElementSize(int element_id, int payload_size) {
50 return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
51 }
52
IntElementSize(int element_id,int value)53 static int IntElementSize(int element_id, int value) {
54 return GetUIntSize(element_id) + 1 + GetUIntSize(value);
55 }
56
StringElementSize(int element_id,const std::string & value)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
SerializeInt(uint8 ** buf_ptr,int * buf_size_ptr,int64 value,int size)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
WriteElementId(uint8 ** buf,int * buf_size,int element_id)74 static void WriteElementId(uint8** buf, int* buf_size, int element_id) {
75 SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
76 }
77
WriteUInt(uint8 ** buf,int * buf_size,uint64 value)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
WriteMasterElement(uint8 ** buf,int * buf_size,int element_id,int payload_size)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
WriteIntElement(uint8 ** buf,int * buf_size,int element_id,int value)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
WriteStringElement(uint8 ** buf_ptr,int * buf_size_ptr,int element_id,const std::string & value)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
TracksBuilder()115 TracksBuilder::TracksBuilder() {}
~TracksBuilder()116 TracksBuilder::~TracksBuilder() {}
117
AddTrack(int track_num,int track_type,int track_uid,const std::string & codec_id,const std::string & name,const std::string & language)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
Finish()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
GetTracksSize() const140 int TracksBuilder::GetTracksSize() const {
141 return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
142 }
143
GetTracksPayloadSize() const144 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
WriteTracks(uint8 * buf,int buf_size) const155 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
Track(int track_num,int track_type,int track_uid,const std::string & codec_id,const std::string & name,const std::string & language)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
GetSize() const176 int TracksBuilder::Track::GetSize() const {
177 return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
178 }
179
GetPayloadSize() const180 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
Write(uint8 ** buf,int * buf_size) const199 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