Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / media / formats / webm / cluster_builder.cc
blob1a3b358ef99c64989b658bdd67149710446556f6
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/cluster_builder.h"
7 #include "base/logging.h"
8 #include "media/base/data_buffer.h"
9 #include "media/formats/webm/webm_constants.h"
11 namespace media {
13 static const uint8 kClusterHeader[] = {
14 0x1F, 0x43, 0xB6, 0x75, // CLUSTER ID
15 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cluster(size = 0)
16 0xE7, // Timecode ID
17 0x88, // timecode(size=8)
18 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value
21 static const uint8 kSimpleBlockHeader[] = {
22 0xA3, // SimpleBlock ID
23 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0)
26 static const uint8 kBlockGroupHeader[] = {
27 0xA0, // BlockGroup ID
28 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // BlockGroup(size = 0)
29 0x9B, // BlockDuration ID
30 0x88, // BlockDuration(size = 8)
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // duration
32 0xA1, // Block ID
33 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block(size = 0)
36 static const uint8 kBlockGroupHeaderWithoutBlockDuration[] = {
37 0xA0, // BlockGroup ID
38 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // BlockGroup(size = 0)
39 0xA1, // Block ID
40 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block(size = 0)
43 enum {
44 kClusterSizeOffset = 4,
45 kClusterTimecodeOffset = 14,
47 kSimpleBlockSizeOffset = 1,
49 kBlockGroupSizeOffset = 1,
50 kBlockGroupWithoutBlockDurationBlockSizeOffset = 10,
51 kBlockGroupDurationOffset = 11,
52 kBlockGroupBlockSizeOffset = 20,
54 kInitialBufferSize = 32768,
57 Cluster::Cluster(scoped_ptr<uint8[]> data, int size)
58 : data_(data.Pass()), size_(size) {}
59 Cluster::~Cluster() {}
61 ClusterBuilder::ClusterBuilder() { Reset(); }
62 ClusterBuilder::~ClusterBuilder() {}
64 void ClusterBuilder::SetClusterTimecode(int64 cluster_timecode) {
65 DCHECK_EQ(cluster_timecode_, -1);
67 cluster_timecode_ = cluster_timecode;
69 // Write the timecode into the header.
70 uint8* buf = buffer_.get() + kClusterTimecodeOffset;
71 for (int i = 7; i >= 0; --i) {
72 buf[i] = cluster_timecode & 0xff;
73 cluster_timecode >>= 8;
77 void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags,
78 const uint8* data, int size) {
79 int block_size = size + 4;
80 int bytes_needed = sizeof(kSimpleBlockHeader) + block_size;
81 if (bytes_needed > (buffer_size_ - bytes_used_))
82 ExtendBuffer(bytes_needed);
84 uint8* buf = buffer_.get() + bytes_used_;
85 int block_offset = bytes_used_;
86 memcpy(buf, kSimpleBlockHeader, sizeof(kSimpleBlockHeader));
87 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
88 buf += sizeof(kSimpleBlockHeader);
90 WriteBlock(buf, track_num, timecode, flags, data, size);
92 bytes_used_ += bytes_needed;
95 void ClusterBuilder::AddBlockGroup(int track_num, int64 timecode, int duration,
96 int flags, const uint8* data, int size) {
97 AddBlockGroupInternal(track_num, timecode, true, duration, flags, data, size);
100 void ClusterBuilder::AddBlockGroupWithoutBlockDuration(int track_num,
101 int64 timecode,
102 int flags,
103 const uint8* data,
104 int size) {
105 AddBlockGroupInternal(track_num, timecode, false, 0, flags, data, size);
109 void ClusterBuilder::AddBlockGroupInternal(int track_num, int64 timecode,
110 bool include_block_duration,
111 int duration, int flags,
112 const uint8* data, int size) {
113 int block_size = size + 4;
114 int bytes_needed = block_size;
115 if (include_block_duration) {
116 bytes_needed += sizeof(kBlockGroupHeader);
117 } else {
118 bytes_needed += sizeof(kBlockGroupHeaderWithoutBlockDuration);
121 int block_group_size = bytes_needed - 9;
123 if (bytes_needed > (buffer_size_ - bytes_used_))
124 ExtendBuffer(bytes_needed);
126 uint8* buf = buffer_.get() + bytes_used_;
127 int block_group_offset = bytes_used_;
128 if (include_block_duration) {
129 memcpy(buf, kBlockGroupHeader, sizeof(kBlockGroupHeader));
130 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
131 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
132 buf += sizeof(kBlockGroupHeader);
133 } else {
134 memcpy(buf, kBlockGroupHeaderWithoutBlockDuration,
135 sizeof(kBlockGroupHeaderWithoutBlockDuration));
136 UpdateUInt64(
137 block_group_offset + kBlockGroupWithoutBlockDurationBlockSizeOffset,
138 block_size);
139 buf += sizeof(kBlockGroupHeaderWithoutBlockDuration);
142 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
144 // Make sure the 4 most-significant bits are 0.
145 // http://www.matroska.org/technical/specs/index.html#block_structure
146 flags &= 0x0f;
148 WriteBlock(buf, track_num, timecode, flags, data, size);
150 bytes_used_ += bytes_needed;
153 void ClusterBuilder::WriteBlock(uint8* buf, int track_num, int64 timecode,
154 int flags, const uint8* data, int size) {
155 DCHECK_GE(track_num, 0);
156 DCHECK_LE(track_num, 126);
157 DCHECK_GE(flags, 0);
158 DCHECK_LE(flags, 0xff);
159 DCHECK(data);
160 DCHECK_GT(size, 0);
161 DCHECK_NE(cluster_timecode_, -1);
163 int64 timecode_delta = timecode - cluster_timecode_;
164 DCHECK_GE(timecode_delta, -32768);
165 DCHECK_LE(timecode_delta, 32767);
167 buf[0] = 0x80 | (track_num & 0x7F);
168 buf[1] = (timecode_delta >> 8) & 0xff;
169 buf[2] = timecode_delta & 0xff;
170 buf[3] = flags & 0xff;
171 memcpy(buf + 4, data, size);
174 scoped_ptr<Cluster> ClusterBuilder::Finish() {
175 DCHECK_NE(cluster_timecode_, -1);
177 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
179 scoped_ptr<Cluster> ret(new Cluster(buffer_.Pass(), bytes_used_));
180 Reset();
181 return ret.Pass();
184 scoped_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() {
185 DCHECK_NE(cluster_timecode_, -1);
187 UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize);
189 scoped_ptr<Cluster> ret(new Cluster(buffer_.Pass(), bytes_used_));
190 Reset();
191 return ret.Pass();
194 void ClusterBuilder::Reset() {
195 buffer_size_ = kInitialBufferSize;
196 buffer_.reset(new uint8[buffer_size_]);
197 memcpy(buffer_.get(), kClusterHeader, sizeof(kClusterHeader));
198 bytes_used_ = sizeof(kClusterHeader);
199 cluster_timecode_ = -1;
202 void ClusterBuilder::ExtendBuffer(int bytes_needed) {
203 int new_buffer_size = 2 * buffer_size_;
205 while ((new_buffer_size - bytes_used_) < bytes_needed)
206 new_buffer_size *= 2;
208 scoped_ptr<uint8[]> new_buffer(new uint8[new_buffer_size]);
210 memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
211 buffer_.reset(new_buffer.release());
212 buffer_size_ = new_buffer_size;
215 void ClusterBuilder::UpdateUInt64(int offset, int64 value) {
216 DCHECK_LE(offset + 7, buffer_size_);
217 uint8* buf = buffer_.get() + offset;
219 // Fill the last 7 bytes of size field in big-endian order.
220 for (int i = 7; i > 0; i--) {
221 buf[i] = value & 0xff;
222 value >>= 8;
226 } // namespace media