Temporarily remove DCHECK that triggers during hardware teardown.
[chromium-blink-merge.git] / media / formats / webm / tracks_builder.cc
blob927c2a4f2b9d0d2b88cdbeda47bd59d280c8b5c0
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"
10 namespace media {
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;
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;
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()) +
65 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));
75 --buf_size;
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;
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,
109 int* buf_size,
110 int element_id,
111 uint64 value) {
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);
138 buf += size;
139 buf_size -= 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,
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);
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);
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);
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());
191 return buffer;
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_));
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();
223 return payload_size;
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,
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);
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);
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);
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_);
300 return payload_size;
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);
311 return payload_size;
314 int TracksBuilder::Track::GetPayloadSize() const {
315 int size = 0;
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_);
327 if (!name_.empty())
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());
341 return size;
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_);
357 if (!name_.empty())
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_);
386 } // namespace media