- add sources.
[platform/framework/web/crosswalk.git] / src / media / webm / tracks_builder.cc
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     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));
125 }
126
127 std::vector<uint8> TracksBuilder::Finish() {
128   // Allocate the storage
129   std::vector<uint8> buffer;
130   buffer.resize(GetTracksSize());
131
132   // Populate the storage with a tracks header
133   WriteTracks(&buffer[0], buffer.size());
134
135   return buffer;
136 }
137
138 int TracksBuilder::GetTracksSize() const {
139   return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
140 }
141
142 int TracksBuilder::GetTracksPayloadSize() const {
143   int payload_size = 0;
144
145   for (TrackList::const_iterator itr = tracks_.begin();
146        itr != tracks_.end(); ++itr) {
147     payload_size += itr->GetSize();
148   }
149
150   return payload_size;
151 }
152
153 void TracksBuilder::WriteTracks(uint8* buf, int buf_size) const {
154   WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
155
156   for (TrackList::const_iterator itr = tracks_.begin();
157        itr != tracks_.end(); ++itr) {
158     itr->Write(&buf, &buf_size);
159   }
160 }
161
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),
168       codec_id_(codec_id),
169       name_(name),
170       language_(language) {
171 }
172
173 int TracksBuilder::Track::GetSize() const {
174   return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
175 }
176
177 int TracksBuilder::Track::GetPayloadSize() const {
178   int size = 0;
179
180   size += IntElementSize(kWebMIdTrackNumber, track_num_);
181   size += IntElementSize(kWebMIdTrackType, track_type_);
182
183   if (!codec_id_.empty())
184     size += StringElementSize(kWebMIdCodecID, codec_id_);
185
186   if (!name_.empty())
187     size += StringElementSize(kWebMIdName, name_);
188
189   if (!language_.empty())
190     size += StringElementSize(kWebMIdLanguage, language_);
191
192   return size;
193 }
194
195 void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const {
196   WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
197
198   WriteIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
199   WriteIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
200
201   if (!codec_id_.empty())
202     WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
203
204   if (!name_.empty())
205     WriteStringElement(buf, buf_size, kWebMIdName, name_);
206
207   if (!language_.empty())
208     WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);
209 }
210
211 }  // namespace media