cc: Fix logic for detecting when raster tasks were throttled
[chromium-blink-merge.git] / media / webm / cluster_builder.cc
blobe320cbb665374e28a0554b6aec3f73459a675c01
1 // Copyright (c) 2012 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/cluster_builder.h"
7 #include "base/logging.h"
8 #include "media/base/data_buffer.h"
10 namespace media {
12 static const uint8 kClusterHeader[] = {
13 0x1F, 0x43, 0xB6, 0x75, // CLUSTER ID
14 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cluster(size = 0)
15 0xE7, // Timecode ID
16 0x88, // timecode(size=8)
17 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value
20 static const uint8 kSimpleBlockHeader[] = {
21 0xA3, // SimpleBlock ID
22 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0)
25 static const uint8 kBlockGroupHeader[] = {
26 0xA0, // BlockGroup ID
27 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // BlockGroup(size = 0)
28 0x9B, // BlockDuration ID
29 0x88, // BlockDuration(size = 8)
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // duration
31 0xA1, // Block ID
32 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block(size = 0)
35 enum {
36 kClusterSizeOffset = 4,
37 kClusterTimecodeOffset = 14,
39 kSimpleBlockSizeOffset = 1,
41 kBlockGroupSizeOffset = 1,
42 kBlockGroupDurationOffset = 11,
43 kBlockGroupBlockSizeOffset = 20,
45 kInitialBufferSize = 32768,
48 Cluster::Cluster(scoped_ptr<uint8[]> data, int size)
49 : data_(data.Pass()), size_(size) {}
50 Cluster::~Cluster() {}
52 ClusterBuilder::ClusterBuilder() { Reset(); }
53 ClusterBuilder::~ClusterBuilder() {}
55 void ClusterBuilder::SetClusterTimecode(int64 cluster_timecode) {
56 DCHECK_EQ(cluster_timecode_, -1);
58 cluster_timecode_ = cluster_timecode;
60 // Write the timecode into the header.
61 uint8* buf = buffer_.get() + kClusterTimecodeOffset;
62 for (int i = 7; i >= 0; --i) {
63 buf[i] = cluster_timecode & 0xff;
64 cluster_timecode >>= 8;
68 void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags,
69 const uint8* data, int size) {
70 int block_size = size + 4;
71 int bytes_needed = sizeof(kSimpleBlockHeader) + block_size;
72 if (bytes_needed > (buffer_size_ - bytes_used_))
73 ExtendBuffer(bytes_needed);
75 uint8* buf = buffer_.get() + bytes_used_;
76 int block_offset = bytes_used_;
77 memcpy(buf, kSimpleBlockHeader, sizeof(kSimpleBlockHeader));
78 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
79 buf += sizeof(kSimpleBlockHeader);
81 WriteBlock(buf, track_num, timecode, flags, data, size);
83 bytes_used_ += bytes_needed;
86 void ClusterBuilder::AddBlockGroup(int track_num, int64 timecode, int duration,
87 int flags, const uint8* data, int size) {
88 int block_size = size + 4;
89 int bytes_needed = sizeof(kBlockGroupHeader) + block_size;
90 int block_group_size = bytes_needed - 9;
92 if (bytes_needed > (buffer_size_ - bytes_used_))
93 ExtendBuffer(bytes_needed);
95 uint8* buf = buffer_.get() + bytes_used_;
96 int block_group_offset = bytes_used_;
97 memcpy(buf, kBlockGroupHeader, sizeof(kBlockGroupHeader));
98 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
99 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
100 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
101 buf += sizeof(kBlockGroupHeader);
103 // Make sure the 4 most-significant bits are 0.
104 // http://www.matroska.org/technical/specs/index.html#block_structure
105 flags &= 0x0f;
107 WriteBlock(buf, track_num, timecode, flags, data, size);
109 bytes_used_ += bytes_needed;
112 void ClusterBuilder::WriteBlock(uint8* buf, int track_num, int64 timecode,
113 int flags, const uint8* data, int size) {
114 DCHECK_GE(track_num, 0);
115 DCHECK_LE(track_num, 126);
116 DCHECK_GE(flags, 0);
117 DCHECK_LE(flags, 0xff);
118 DCHECK(data);
119 DCHECK_GT(size, 0);
120 DCHECK_NE(cluster_timecode_, -1);
122 int64 timecode_delta = timecode - cluster_timecode_;
123 DCHECK_GE(timecode_delta, -32768);
124 DCHECK_LE(timecode_delta, 32767);
126 buf[0] = 0x80 | (track_num & 0x7F);
127 buf[1] = (timecode_delta >> 8) & 0xff;
128 buf[2] = timecode_delta & 0xff;
129 buf[3] = flags & 0xff;
130 memcpy(buf + 4, data, size);
133 scoped_ptr<Cluster> ClusterBuilder::Finish() {
134 DCHECK_NE(cluster_timecode_, -1);
136 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
138 scoped_ptr<Cluster> ret(new Cluster(buffer_.Pass(), bytes_used_));
139 Reset();
140 return ret.Pass();
143 void ClusterBuilder::Reset() {
144 buffer_size_ = kInitialBufferSize;
145 buffer_.reset(new uint8[buffer_size_]);
146 memcpy(buffer_.get(), kClusterHeader, sizeof(kClusterHeader));
147 bytes_used_ = sizeof(kClusterHeader);
148 cluster_timecode_ = -1;
151 void ClusterBuilder::ExtendBuffer(int bytes_needed) {
152 int new_buffer_size = 2 * buffer_size_;
154 while ((new_buffer_size - bytes_used_) < bytes_needed)
155 new_buffer_size *= 2;
157 scoped_ptr<uint8[]> new_buffer(new uint8[new_buffer_size]);
159 memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
160 buffer_.reset(new_buffer.release());
161 buffer_size_ = new_buffer_size;
164 void ClusterBuilder::UpdateUInt64(int offset, int64 value) {
165 DCHECK_LE(offset + 7, buffer_size_);
166 uint8* buf = buffer_.get() + offset;
168 // Fill the last 7 bytes of size field in big-endian order.
169 for (int i = 7; i > 0; i--) {
170 buf[i] = value & 0xff;
171 value >>= 8;
175 } // namespace media