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.
5 #include "media/formats/webm/tracks_builder.h"
7 #include "base/logging.h"
8 #include "media/formats/webm/webm_constants.h"
12 // Returns size of an integer, formatted using Matroska serialization.
13 static int GetUIntMkvSize(uint64 value
) {
16 if (value
< 0x03FFFULL
)
18 if (value
< 0x01FFFFFULL
)
20 if (value
< 0x0FFFFFFFULL
)
22 if (value
< 0x07FFFFFFFFULL
)
24 if (value
< 0x03FFFFFFFFFFULL
)
26 if (value
< 0x01FFFFFFFFFFFFULL
)
31 // Returns the minimium size required to serialize an integer value.
32 static int GetUIntSize(uint64 value
) {
33 if (value
< 0x0100ULL
)
35 if (value
< 0x010000ULL
)
37 if (value
< 0x01000000ULL
)
39 if (value
< 0x0100000000ULL
)
41 if (value
< 0x010000000000ULL
)
43 if (value
< 0x01000000000000ULL
)
45 if (value
< 0x0100000000000000ULL
)
50 static int MasterElementSize(int element_id
, int payload_size
) {
51 return GetUIntSize(element_id
) + GetUIntMkvSize(payload_size
) + payload_size
;
54 static int UIntElementSize(int element_id
, uint64 value
) {
55 return GetUIntSize(element_id
) + 1 + GetUIntSize(value
);
58 static int DoubleElementSize(int element_id
) {
59 return GetUIntSize(element_id
) + 1 + 8;
62 static int StringElementSize(int element_id
, const std::string
& value
) {
63 return GetUIntSize(element_id
) +
64 GetUIntMkvSize(value
.length()) +
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
;
73 for (int idx
= 1; idx
<= size
; ++idx
) {
74 *buf
++ = static_cast<uint8
>(value
>> ((size
- idx
) * 8));
79 static void SerializeDouble(uint8
** buf_ptr
, int* buf_size_ptr
,
81 // Use a union to convert |value| to native endian integer bit pattern.
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);
92 static void WriteElementId(uint8
** buf
, int* buf_size
, int element_id
) {
93 SerializeInt(buf
, buf_size
, element_id
, GetUIntSize(element_id
));
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
);
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
);
108 static void WriteUIntElement(uint8
** buf
,
112 WriteElementId(buf
, buf_size
, element_id
);
114 const int size
= GetUIntSize(value
);
115 WriteUInt(buf
, buf_size
, size
);
117 SerializeInt(buf
, buf_size
, value
, size
);
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
);
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
;
132 WriteElementId(&buf
, &buf_size
, element_id
);
134 const uint64 size
= value
.length();
135 WriteUInt(&buf
, &buf_size
, size
);
137 memcpy(buf
, value
.data(), size
);
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() {}
148 void TracksBuilder::AddVideoTrack(int track_num
,
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);
161 void TracksBuilder::AddAudioTrack(int track_num
,
163 const std::string
& codec_id
,
164 const std::string
& name
,
165 const std::string
& language
,
166 int default_duration
,
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
);
174 void TracksBuilder::AddTextTrack(int track_num
,
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);
183 std::vector
<uint8
> TracksBuilder::Finish() {
184 // Allocate the storage
185 std::vector
<uint8
> buffer
;
186 buffer
.resize(GetTracksSize());
188 // Populate the storage with a tracks header
189 WriteTracks(&buffer
[0], buffer
.size());
194 void TracksBuilder::AddTrackInternal(int track_num
,
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
,
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_
));
211 int TracksBuilder::GetTracksSize() const {
212 return MasterElementSize(kWebMIdTracks
, GetTracksPayloadSize());
215 int TracksBuilder::GetTracksPayloadSize() const {
216 int payload_size
= 0;
218 for (TrackList::const_iterator itr
= tracks_
.begin();
219 itr
!= tracks_
.end(); ++itr
) {
220 payload_size
+= itr
->GetSize();
226 void TracksBuilder::WriteTracks(uint8
* buf
, int buf_size
) const {
227 WriteMasterElement(&buf
, &buf_size
, kWebMIdTracks
, GetTracksPayloadSize());
229 for (TrackList::const_iterator itr
= tracks_
.begin();
230 itr
!= tracks_
.end(); ++itr
) {
231 itr
->Write(&buf
, &buf_size
);
235 TracksBuilder::Track::Track(int track_num
,
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
,
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
),
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);
267 CHECK(default_duration_
== -1 || default_duration_
> 0);
270 if (track_type
== kWebMTrackTypeVideo
) {
271 CHECK_GT(video_pixel_width_
, 0);
272 CHECK_GT(video_pixel_height_
, 0);
274 CHECK_EQ(video_pixel_width_
, -1);
275 CHECK_EQ(video_pixel_height_
, -1);
278 if (track_type
== kWebMTrackTypeAudio
) {
279 CHECK_GT(audio_channels_
, 0);
280 CHECK_GT(audio_sampling_frequency_
, 0.0);
282 CHECK_EQ(audio_channels_
, -1);
283 CHECK_EQ(audio_sampling_frequency_
, -1.0);
288 int TracksBuilder::Track::GetSize() const {
289 return MasterElementSize(kWebMIdTrackEntry
, GetPayloadSize());
292 int TracksBuilder::Track::GetVideoPayloadSize() const {
293 int payload_size
= 0;
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_
);
303 int TracksBuilder::Track::GetAudioPayloadSize() const {
304 int payload_size
= 0;
306 if (audio_channels_
>= 0)
307 payload_size
+= UIntElementSize(kWebMIdChannels
, audio_channels_
);
308 if (audio_sampling_frequency_
>= 0)
309 payload_size
+= DoubleElementSize(kWebMIdSamplingFrequency
);
314 int TracksBuilder::Track::GetPayloadSize() const {
317 size
+= UIntElementSize(kWebMIdTrackNumber
, track_num_
);
318 size
+= UIntElementSize(kWebMIdTrackType
, track_type_
);
319 size
+= UIntElementSize(kWebMIdTrackUID
, track_uid_
);
321 if (default_duration_
>= 0)
322 size
+= UIntElementSize(kWebMIdDefaultDuration
, default_duration_
);
324 if (!codec_id_
.empty())
325 size
+= StringElementSize(kWebMIdCodecID
, codec_id_
);
328 size
+= StringElementSize(kWebMIdName
, name_
);
330 if (!language_
.empty())
331 size
+= StringElementSize(kWebMIdLanguage
, language_
);
333 if (GetVideoPayloadSize() > 0) {
334 size
+= MasterElementSize(kWebMIdVideo
, GetVideoPayloadSize());
337 if (GetAudioPayloadSize() > 0) {
338 size
+= MasterElementSize(kWebMIdAudio
, GetAudioPayloadSize());
344 void TracksBuilder::Track::Write(uint8
** buf
, int* buf_size
) const {
345 WriteMasterElement(buf
, buf_size
, kWebMIdTrackEntry
, GetPayloadSize());
347 WriteUIntElement(buf
, buf_size
, kWebMIdTrackNumber
, track_num_
);
348 WriteUIntElement(buf
, buf_size
, kWebMIdTrackType
, track_type_
);
349 WriteUIntElement(buf
, buf_size
, kWebMIdTrackUID
, track_uid_
);
351 if (default_duration_
>= 0)
352 WriteUIntElement(buf
, buf_size
, kWebMIdDefaultDuration
, default_duration_
);
354 if (!codec_id_
.empty())
355 WriteStringElement(buf
, buf_size
, kWebMIdCodecID
, codec_id_
);
358 WriteStringElement(buf
, buf_size
, kWebMIdName
, name_
);
360 if (!language_
.empty())
361 WriteStringElement(buf
, buf_size
, kWebMIdLanguage
, language_
);
363 if (GetVideoPayloadSize() > 0) {
364 WriteMasterElement(buf
, buf_size
, kWebMIdVideo
, GetVideoPayloadSize());
366 if (video_pixel_width_
>= 0)
367 WriteUIntElement(buf
, buf_size
, kWebMIdPixelWidth
, video_pixel_width_
);
369 if (video_pixel_height_
>= 0)
370 WriteUIntElement(buf
, buf_size
, kWebMIdPixelHeight
, video_pixel_height_
);
373 if (GetAudioPayloadSize() > 0) {
374 WriteMasterElement(buf
, buf_size
, kWebMIdAudio
, GetAudioPayloadSize());
376 if (audio_channels_
>= 0)
377 WriteUIntElement(buf
, buf_size
, kWebMIdChannels
, audio_channels_
);
379 if (audio_sampling_frequency_
>= 0) {
380 WriteDoubleElement(buf
, buf_size
, kWebMIdSamplingFrequency
,
381 audio_sampling_frequency_
);