5 #include <packager/media/formats/webm/cluster_builder.h>
7 #include <absl/log/check.h>
8 #include <absl/log/log.h>
10 #include <packager/media/formats/webm/webm_constants.h>
15 static const uint8_t kClusterHeader[] = {
16 0x1F, 0x43, 0xB6, 0x75,
17 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23 static const uint8_t kSimpleBlockHeader[] = {
25 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 static const uint8_t kBlockGroupHeader[] = {
30 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 static const uint8_t kBlockGroupHeaderWithoutBlockDuration[] = {
40 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 static const uint8_t kBlockGroupReferenceBlock[] = {
51 kClusterSizeOffset = 4,
52 kClusterTimecodeOffset = 14,
54 kSimpleBlockSizeOffset = 1,
56 kBlockGroupSizeOffset = 1,
57 kBlockGroupWithoutBlockDurationBlockSizeOffset = 10,
58 kBlockGroupDurationOffset = 11,
59 kBlockGroupBlockSizeOffset = 20,
61 kInitialBufferSize = 32768,
64 Cluster::Cluster(std::unique_ptr<uint8_t[]> data,
int size)
65 : data_(std::move(data)), size_(size) {}
66 Cluster::~Cluster() {}
68 ClusterBuilder::ClusterBuilder() { Reset(); }
69 ClusterBuilder::~ClusterBuilder() {}
71 void ClusterBuilder::SetClusterTimecode(int64_t cluster_timecode) {
72 DCHECK_EQ(cluster_timecode_, -1);
74 cluster_timecode_ = cluster_timecode;
77 uint8_t* buf = buffer_.get() + kClusterTimecodeOffset;
78 for (
int i = 7; i >= 0; --i) {
79 buf[i] = cluster_timecode & 0xff;
80 cluster_timecode >>= 8;
84 void ClusterBuilder::AddSimpleBlock(
int track_num,
89 int block_size = size + 4;
90 int bytes_needed =
sizeof(kSimpleBlockHeader) + block_size;
91 if (bytes_needed > (buffer_size_ - bytes_used_))
92 ExtendBuffer(bytes_needed);
94 uint8_t* buf = buffer_.get() + bytes_used_;
95 int block_offset = bytes_used_;
96 memcpy(buf, kSimpleBlockHeader,
sizeof(kSimpleBlockHeader));
97 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
98 buf +=
sizeof(kSimpleBlockHeader);
100 WriteBlock(buf, track_num, timecode, flags, data, size);
102 bytes_used_ += bytes_needed;
105 void ClusterBuilder::AddBlockGroup(
int track_num,
112 AddBlockGroupInternal(track_num, timecode,
true, duration, flags,
113 is_key_frame, data, size);
116 void ClusterBuilder::AddBlockGroupWithoutBlockDuration(
int track_num,
122 AddBlockGroupInternal(track_num, timecode,
false, 0, flags, is_key_frame,
126 void ClusterBuilder::AddBlockGroupInternal(
int track_num,
128 bool include_block_duration,
134 int block_size = size + 4;
135 int bytes_needed = block_size;
136 if (include_block_duration) {
137 bytes_needed +=
sizeof(kBlockGroupHeader);
139 bytes_needed +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
142 bytes_needed +=
sizeof(kBlockGroupReferenceBlock);
145 int block_group_size = bytes_needed - 9;
147 if (bytes_needed > (buffer_size_ - bytes_used_))
148 ExtendBuffer(bytes_needed);
150 uint8_t* buf = buffer_.get() + bytes_used_;
151 int block_group_offset = bytes_used_;
152 if (include_block_duration) {
153 memcpy(buf, kBlockGroupHeader,
sizeof(kBlockGroupHeader));
154 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
155 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
156 buf +=
sizeof(kBlockGroupHeader);
158 memcpy(buf, kBlockGroupHeaderWithoutBlockDuration,
159 sizeof(kBlockGroupHeaderWithoutBlockDuration));
161 block_group_offset + kBlockGroupWithoutBlockDurationBlockSizeOffset,
163 buf +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
166 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
172 WriteBlock(buf, track_num, timecode, flags, data, size);
176 memcpy(buf, kBlockGroupReferenceBlock,
sizeof(kBlockGroupReferenceBlock));
177 bytes_used_ += bytes_needed;
180 void ClusterBuilder::WriteBlock(uint8_t* buf,
186 DCHECK_GE(track_num, 0);
187 DCHECK_LE(track_num, 126);
189 DCHECK_LE(flags, 0xff);
192 DCHECK_NE(cluster_timecode_, -1);
194 int64_t timecode_delta = timecode - cluster_timecode_;
195 DCHECK_GE(timecode_delta, -32768);
196 DCHECK_LE(timecode_delta, 32767);
198 buf[0] = 0x80 | (track_num & 0x7F);
199 buf[1] = (timecode_delta >> 8) & 0xff;
200 buf[2] = timecode_delta & 0xff;
201 buf[3] = flags & 0xff;
202 memcpy(buf + 4, data, size);
205 std::unique_ptr<Cluster> ClusterBuilder::Finish() {
206 DCHECK_NE(cluster_timecode_, -1);
208 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
210 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
215 std::unique_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() {
216 DCHECK_NE(cluster_timecode_, -1);
218 UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize);
220 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
225 void ClusterBuilder::Reset() {
226 buffer_size_ = kInitialBufferSize;
227 buffer_.reset(
new uint8_t[buffer_size_]);
228 memcpy(buffer_.get(), kClusterHeader,
sizeof(kClusterHeader));
229 bytes_used_ =
sizeof(kClusterHeader);
230 cluster_timecode_ = -1;
233 void ClusterBuilder::ExtendBuffer(
int bytes_needed) {
234 int new_buffer_size = 2 * buffer_size_;
236 while ((new_buffer_size - bytes_used_) < bytes_needed)
237 new_buffer_size *= 2;
239 std::unique_ptr<uint8_t[]> new_buffer(
new uint8_t[new_buffer_size]);
241 memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
242 buffer_.reset(new_buffer.release());
243 buffer_size_ = new_buffer_size;
246 void ClusterBuilder::UpdateUInt64(
int offset, int64_t value) {
247 DCHECK_LE(offset + 7, buffer_size_);
248 uint8_t* buf = buffer_.get() + offset;
251 for (
int i = 7; i > 0; i--) {
252 buf[i] = value & 0xff;
All the methods that are virtual are virtual for mocking.