5 #include "packager/media/formats/webm/cluster_builder.h"
7 #include "packager/base/logging.h"
8 #include "packager/media/formats/webm/webm_constants.h"
10 namespace edash_packager {
13 static const uint8_t kClusterHeader[] = {
14 0x1F, 0x43, 0xB6, 0x75,
15 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
18 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21 static const uint8_t kSimpleBlockHeader[] = {
23 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26 static const uint8_t kBlockGroupHeader[] = {
28 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 static const uint8_t kBlockGroupHeaderWithoutBlockDuration[] = {
38 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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_t[]> data,
int size)
58 : data_(data.Pass()), size_(size) {}
59 Cluster::~Cluster() {}
61 ClusterBuilder::ClusterBuilder() { Reset(); }
62 ClusterBuilder::~ClusterBuilder() {}
64 void ClusterBuilder::SetClusterTimecode(int64_t cluster_timecode) {
65 DCHECK_EQ(cluster_timecode_, -1);
67 cluster_timecode_ = cluster_timecode;
70 uint8_t* 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,
82 int block_size = size + 4;
83 int bytes_needed =
sizeof(kSimpleBlockHeader) + block_size;
84 if (bytes_needed > (buffer_size_ - bytes_used_))
85 ExtendBuffer(bytes_needed);
87 uint8_t* buf = buffer_.get() + bytes_used_;
88 int block_offset = bytes_used_;
89 memcpy(buf, kSimpleBlockHeader,
sizeof(kSimpleBlockHeader));
90 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
91 buf +=
sizeof(kSimpleBlockHeader);
93 WriteBlock(buf, track_num, timecode, flags, data, size);
95 bytes_used_ += bytes_needed;
98 void ClusterBuilder::AddBlockGroup(
int track_num,
104 AddBlockGroupInternal(track_num, timecode,
true, duration, flags, data, size);
107 void ClusterBuilder::AddBlockGroupWithoutBlockDuration(
int track_num,
112 AddBlockGroupInternal(track_num, timecode,
false, 0, flags, data, size);
115 void ClusterBuilder::AddBlockGroupInternal(
int track_num,
117 bool include_block_duration,
122 int block_size = size + 4;
123 int bytes_needed = block_size;
124 if (include_block_duration) {
125 bytes_needed +=
sizeof(kBlockGroupHeader);
127 bytes_needed +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
130 int block_group_size = bytes_needed - 9;
132 if (bytes_needed > (buffer_size_ - bytes_used_))
133 ExtendBuffer(bytes_needed);
135 uint8_t* buf = buffer_.get() + bytes_used_;
136 int block_group_offset = bytes_used_;
137 if (include_block_duration) {
138 memcpy(buf, kBlockGroupHeader,
sizeof(kBlockGroupHeader));
139 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
140 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
141 buf +=
sizeof(kBlockGroupHeader);
143 memcpy(buf, kBlockGroupHeaderWithoutBlockDuration,
144 sizeof(kBlockGroupHeaderWithoutBlockDuration));
146 block_group_offset + kBlockGroupWithoutBlockDurationBlockSizeOffset,
148 buf +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
151 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
157 WriteBlock(buf, track_num, timecode, flags, data, size);
159 bytes_used_ += bytes_needed;
162 void ClusterBuilder::WriteBlock(uint8_t* buf,
168 DCHECK_GE(track_num, 0);
169 DCHECK_LE(track_num, 126);
171 DCHECK_LE(flags, 0xff);
174 DCHECK_NE(cluster_timecode_, -1);
176 int64_t timecode_delta = timecode - cluster_timecode_;
177 DCHECK_GE(timecode_delta, -32768);
178 DCHECK_LE(timecode_delta, 32767);
180 buf[0] = 0x80 | (track_num & 0x7F);
181 buf[1] = (timecode_delta >> 8) & 0xff;
182 buf[2] = timecode_delta & 0xff;
183 buf[3] = flags & 0xff;
184 memcpy(buf + 4, data, size);
187 scoped_ptr<Cluster> ClusterBuilder::Finish() {
188 DCHECK_NE(cluster_timecode_, -1);
190 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
192 scoped_ptr<Cluster> ret(
new Cluster(buffer_.Pass(), bytes_used_));
197 scoped_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() {
198 DCHECK_NE(cluster_timecode_, -1);
200 UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize);
202 scoped_ptr<Cluster> ret(
new Cluster(buffer_.Pass(), bytes_used_));
207 void ClusterBuilder::Reset() {
208 buffer_size_ = kInitialBufferSize;
209 buffer_.reset(
new uint8_t[buffer_size_]);
210 memcpy(buffer_.get(), kClusterHeader,
sizeof(kClusterHeader));
211 bytes_used_ =
sizeof(kClusterHeader);
212 cluster_timecode_ = -1;
215 void ClusterBuilder::ExtendBuffer(
int bytes_needed) {
216 int new_buffer_size = 2 * buffer_size_;
218 while ((new_buffer_size - bytes_used_) < bytes_needed)
219 new_buffer_size *= 2;
221 scoped_ptr<uint8_t[]> new_buffer(
new uint8_t[new_buffer_size]);
223 memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
224 buffer_.reset(new_buffer.release());
225 buffer_size_ = new_buffer_size;
228 void ClusterBuilder::UpdateUInt64(
int offset, int64_t value) {
229 DCHECK_LE(offset + 7, buffer_size_);
230 uint8_t* buf = buffer_.get() + offset;
233 for (
int i = 7; i > 0; i--) {
234 buf[i] = value & 0xff;