5#include <packager/media/formats/webm/cluster_builder.h>
12#include <absl/log/check.h>
14#include <packager/media/formats/webm/webm_constants.h>
19static const uint8_t kClusterHeader[] = {
21 0x1F, 0x43, 0xB6, 0x75,
22 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29static const uint8_t kSimpleBlockHeader[] = {
32 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36static const uint8_t kBlockGroupHeader[] = {
39 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48static const uint8_t kBlockGroupHeaderWithoutBlockDuration[] = {
51 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57static const uint8_t kBlockGroupReferenceBlock[] = {
65 kClusterSizeOffset = 4,
66 kClusterTimecodeOffset = 14,
68 kSimpleBlockSizeOffset = 1,
70 kBlockGroupSizeOffset = 1,
71 kBlockGroupWithoutBlockDurationBlockSizeOffset = 10,
72 kBlockGroupDurationOffset = 11,
73 kBlockGroupBlockSizeOffset = 20,
75 kInitialBufferSize = 32768,
78Cluster::Cluster(std::unique_ptr<uint8_t[]> data,
int size)
79 : data_(std::move(data)), size_(size) {}
82ClusterBuilder::ClusterBuilder() {
85ClusterBuilder::~ClusterBuilder() {}
87void ClusterBuilder::SetClusterTimecode(int64_t cluster_timecode) {
88 DCHECK_EQ(cluster_timecode_, -1);
90 cluster_timecode_ = cluster_timecode;
93 uint8_t* buf = buffer_.get() + kClusterTimecodeOffset;
94 for (
int i = 7; i >= 0; --i) {
95 buf[i] = cluster_timecode & 0xff;
96 cluster_timecode >>= 8;
100void ClusterBuilder::AddSimpleBlock(
int track_num,
105 int block_size = size + 4;
106 int bytes_needed =
sizeof(kSimpleBlockHeader) + block_size;
107 if (bytes_needed > (buffer_size_ - bytes_used_))
108 ExtendBuffer(bytes_needed);
110 uint8_t* buf = buffer_.get() + bytes_used_;
111 int block_offset = bytes_used_;
112 memcpy(buf, kSimpleBlockHeader,
sizeof(kSimpleBlockHeader));
113 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
114 buf +=
sizeof(kSimpleBlockHeader);
116 WriteBlock(buf, track_num, timecode, flags, data, size);
118 bytes_used_ += bytes_needed;
121void ClusterBuilder::AddBlockGroup(
int track_num,
128 AddBlockGroupInternal(track_num, timecode,
true, duration, flags,
129 is_key_frame, data, size);
132void ClusterBuilder::AddBlockGroupWithoutBlockDuration(
int track_num,
138 AddBlockGroupInternal(track_num, timecode,
false, 0, flags, is_key_frame,
142void ClusterBuilder::AddBlockGroupInternal(
int track_num,
144 bool include_block_duration,
150 int block_size = size + 4;
151 int bytes_needed = block_size;
152 if (include_block_duration) {
153 bytes_needed +=
sizeof(kBlockGroupHeader);
155 bytes_needed +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
158 bytes_needed +=
sizeof(kBlockGroupReferenceBlock);
161 int block_group_size = bytes_needed - 9;
163 if (bytes_needed > (buffer_size_ - bytes_used_))
164 ExtendBuffer(bytes_needed);
166 uint8_t* buf = buffer_.get() + bytes_used_;
167 int block_group_offset = bytes_used_;
168 if (include_block_duration) {
169 memcpy(buf, kBlockGroupHeader,
sizeof(kBlockGroupHeader));
170 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
171 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
172 buf +=
sizeof(kBlockGroupHeader);
174 memcpy(buf, kBlockGroupHeaderWithoutBlockDuration,
175 sizeof(kBlockGroupHeaderWithoutBlockDuration));
177 block_group_offset + kBlockGroupWithoutBlockDurationBlockSizeOffset,
179 buf +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
182 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
188 WriteBlock(buf, track_num, timecode, flags, data, size);
192 memcpy(buf, kBlockGroupReferenceBlock,
sizeof(kBlockGroupReferenceBlock));
193 bytes_used_ += bytes_needed;
196void ClusterBuilder::WriteBlock(uint8_t* buf,
202 DCHECK_GE(track_num, 0);
203 DCHECK_LE(track_num, 126);
205 DCHECK_LE(flags, 0xff);
208 DCHECK_NE(cluster_timecode_, -1);
210 int64_t timecode_delta = timecode - cluster_timecode_;
211 DCHECK_GE(timecode_delta, -32768);
212 DCHECK_LE(timecode_delta, 32767);
214 buf[0] = 0x80 | (track_num & 0x7F);
215 buf[1] = (timecode_delta >> 8) & 0xff;
216 buf[2] = timecode_delta & 0xff;
217 buf[3] = flags & 0xff;
218 memcpy(buf + 4, data, size);
221std::unique_ptr<Cluster> ClusterBuilder::Finish() {
222 DCHECK_NE(cluster_timecode_, -1);
224 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
226 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
231std::unique_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() {
232 DCHECK_NE(cluster_timecode_, -1);
234 UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize);
236 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
241void ClusterBuilder::Reset() {
242 buffer_size_ = kInitialBufferSize;
243 buffer_.reset(
new uint8_t[buffer_size_]);
244 memcpy(buffer_.get(), kClusterHeader,
sizeof(kClusterHeader));
245 bytes_used_ =
sizeof(kClusterHeader);
246 cluster_timecode_ = -1;
249void ClusterBuilder::ExtendBuffer(
int bytes_needed) {
250 int new_buffer_size = 2 * buffer_size_;
252 while ((new_buffer_size - bytes_used_) < bytes_needed)
253 new_buffer_size *= 2;
255 std::unique_ptr<uint8_t[]> new_buffer(
new uint8_t[new_buffer_size]);
257 memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
258 buffer_.reset(new_buffer.release());
259 buffer_size_ = new_buffer_size;
262void ClusterBuilder::UpdateUInt64(
int offset, int64_t value) {
263 DCHECK_LE(offset + 7, buffer_size_);
264 uint8_t* buf = buffer_.get() + offset;
267 for (
int i = 7; i > 0; i--) {
268 buf[i] = value & 0xff;
All the methods that are virtual are virtual for mocking.