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.
5 #include "media/webm/tracks_builder.h"
7 #include "media/webm/webm_constants.h"
11 // Returns size of an integer, formatted using Matroska serialization.
12 static int GetUIntMkvSize(uint64 value) {
15 if (value < 0x03FFFULL)
17 if (value < 0x01FFFFFULL)
19 if (value < 0x0FFFFFFFULL)
21 if (value < 0x07FFFFFFFFULL)
23 if (value < 0x03FFFFFFFFFFULL)
25 if (value < 0x01FFFFFFFFFFFFULL)
30 // Returns the minimium size required to serialize an integer value.
31 static int GetUIntSize(uint64 value) {
32 if (value < 0x0100ULL)
34 if (value < 0x010000ULL)
36 if (value < 0x01000000ULL)
38 if (value < 0x0100000000ULL)
40 if (value < 0x010000000000ULL)
42 if (value < 0x01000000000000ULL)
44 if (value < 0x0100000000000000ULL)
49 static int MasterElementSize(int element_id, int payload_size) {
50 return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
53 static int IntElementSize(int element_id, int value) {
54 return GetUIntSize(element_id) + 1 + GetUIntSize(value);
57 static int StringElementSize(int element_id, const std::string& value) {
58 return GetUIntSize(element_id) +
59 GetUIntMkvSize(value.length()) +
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;
68 for (int idx = 1; idx <= size; ++idx) {
69 *buf++ = static_cast<uint8>(value >> ((size - idx) * 8));
74 static void WriteElementId(uint8** buf, int* buf_size, int element_id) {
75 SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
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);
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);
90 static void WriteIntElement(uint8** buf, int* buf_size,
91 int element_id, int value) {
92 WriteElementId(buf, buf_size, element_id);
94 const int size = GetUIntSize(value);
95 WriteUInt(buf, buf_size, size);
97 SerializeInt(buf, buf_size, value, size);
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;
105 WriteElementId(&buf, &buf_size, element_id);
107 const uint64 size = value.length();
108 WriteUInt(&buf, &buf_size, size);
110 memcpy(buf, value.data(), size);
115 TracksBuilder::TracksBuilder() {}
116 TracksBuilder::~TracksBuilder() {}
118 void TracksBuilder::AddTrack(
121 const std::string& codec_id,
122 const std::string& name,
123 const std::string& language) {
124 tracks_.push_back(Track(track_num, track_type, codec_id, name, language));
127 std::vector<uint8> TracksBuilder::Finish() {
128 // Allocate the storage
129 std::vector<uint8> buffer;
130 buffer.resize(GetTracksSize());
132 // Populate the storage with a tracks header
133 WriteTracks(&buffer[0], buffer.size());
138 int TracksBuilder::GetTracksSize() const {
139 return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
142 int TracksBuilder::GetTracksPayloadSize() const {
143 int payload_size = 0;
145 for (TrackList::const_iterator itr = tracks_.begin();
146 itr != tracks_.end(); ++itr) {
147 payload_size += itr->GetSize();
153 void TracksBuilder::WriteTracks(uint8* buf, int buf_size) const {
154 WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
156 for (TrackList::const_iterator itr = tracks_.begin();
157 itr != tracks_.end(); ++itr) {
158 itr->Write(&buf, &buf_size);
162 TracksBuilder::Track::Track(int track_num, int track_type,
163 const std::string& codec_id,
164 const std::string& name,
165 const std::string& language)
166 : track_num_(track_num),
167 track_type_(track_type),
170 language_(language) {
173 int TracksBuilder::Track::GetSize() const {
174 return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
177 int TracksBuilder::Track::GetPayloadSize() const {
180 size += IntElementSize(kWebMIdTrackNumber, track_num_);
181 size += IntElementSize(kWebMIdTrackType, track_type_);
183 if (!codec_id_.empty())
184 size += StringElementSize(kWebMIdCodecID, codec_id_);
187 size += StringElementSize(kWebMIdName, name_);
189 if (!language_.empty())
190 size += StringElementSize(kWebMIdLanguage, language_);
195 void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const {
196 WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
198 WriteIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
199 WriteIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
201 if (!codec_id_.empty())
202 WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
205 WriteStringElement(buf, buf_size, kWebMIdName, name_);
207 if (!language_.empty())
208 WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);