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>
15static const uint8_t kClusterHeader[] = {
17 0x1F, 0x43, 0xB6, 0x75,
18 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25static const uint8_t kSimpleBlockHeader[] = {
28 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32static const uint8_t kBlockGroupHeader[] = {
35 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44static const uint8_t kBlockGroupHeaderWithoutBlockDuration[] = {
47 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53static const uint8_t kBlockGroupReferenceBlock[] = {
61 kClusterSizeOffset = 4,
62 kClusterTimecodeOffset = 14,
64 kSimpleBlockSizeOffset = 1,
66 kBlockGroupSizeOffset = 1,
67 kBlockGroupWithoutBlockDurationBlockSizeOffset = 10,
68 kBlockGroupDurationOffset = 11,
69 kBlockGroupBlockSizeOffset = 20,
71 kInitialBufferSize = 32768,
74Cluster::Cluster(std::unique_ptr<uint8_t[]> data,
int size)
75 : data_(std::move(data)), size_(size) {}
78ClusterBuilder::ClusterBuilder() {
81ClusterBuilder::~ClusterBuilder() {}
83void ClusterBuilder::SetClusterTimecode(int64_t cluster_timecode) {
84 DCHECK_EQ(cluster_timecode_, -1);
86 cluster_timecode_ = cluster_timecode;
89 uint8_t* buf = buffer_.get() + kClusterTimecodeOffset;
90 for (
int i = 7; i >= 0; --i) {
91 buf[i] = cluster_timecode & 0xff;
92 cluster_timecode >>= 8;
96void ClusterBuilder::AddSimpleBlock(
int track_num,
101 int block_size = size + 4;
102 int bytes_needed =
sizeof(kSimpleBlockHeader) + block_size;
103 if (bytes_needed > (buffer_size_ - bytes_used_))
104 ExtendBuffer(bytes_needed);
106 uint8_t* buf = buffer_.get() + bytes_used_;
107 int block_offset = bytes_used_;
108 memcpy(buf, kSimpleBlockHeader,
sizeof(kSimpleBlockHeader));
109 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
110 buf +=
sizeof(kSimpleBlockHeader);
112 WriteBlock(buf, track_num, timecode, flags, data, size);
114 bytes_used_ += bytes_needed;
117void ClusterBuilder::AddBlockGroup(
int track_num,
124 AddBlockGroupInternal(track_num, timecode,
true, duration, flags,
125 is_key_frame, data, size);
128void ClusterBuilder::AddBlockGroupWithoutBlockDuration(
int track_num,
134 AddBlockGroupInternal(track_num, timecode,
false, 0, flags, is_key_frame,
138void ClusterBuilder::AddBlockGroupInternal(
int track_num,
140 bool include_block_duration,
146 int block_size = size + 4;
147 int bytes_needed = block_size;
148 if (include_block_duration) {
149 bytes_needed +=
sizeof(kBlockGroupHeader);
151 bytes_needed +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
154 bytes_needed +=
sizeof(kBlockGroupReferenceBlock);
157 int block_group_size = bytes_needed - 9;
159 if (bytes_needed > (buffer_size_ - bytes_used_))
160 ExtendBuffer(bytes_needed);
162 uint8_t* buf = buffer_.get() + bytes_used_;
163 int block_group_offset = bytes_used_;
164 if (include_block_duration) {
165 memcpy(buf, kBlockGroupHeader,
sizeof(kBlockGroupHeader));
166 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
167 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
168 buf +=
sizeof(kBlockGroupHeader);
170 memcpy(buf, kBlockGroupHeaderWithoutBlockDuration,
171 sizeof(kBlockGroupHeaderWithoutBlockDuration));
173 block_group_offset + kBlockGroupWithoutBlockDurationBlockSizeOffset,
175 buf +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
178 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
184 WriteBlock(buf, track_num, timecode, flags, data, size);
188 memcpy(buf, kBlockGroupReferenceBlock,
sizeof(kBlockGroupReferenceBlock));
189 bytes_used_ += bytes_needed;
192void ClusterBuilder::WriteBlock(uint8_t* buf,
198 DCHECK_GE(track_num, 0);
199 DCHECK_LE(track_num, 126);
201 DCHECK_LE(flags, 0xff);
204 DCHECK_NE(cluster_timecode_, -1);
206 int64_t timecode_delta = timecode - cluster_timecode_;
207 DCHECK_GE(timecode_delta, -32768);
208 DCHECK_LE(timecode_delta, 32767);
210 buf[0] = 0x80 | (track_num & 0x7F);
211 buf[1] = (timecode_delta >> 8) & 0xff;
212 buf[2] = timecode_delta & 0xff;
213 buf[3] = flags & 0xff;
214 memcpy(buf + 4, data, size);
217std::unique_ptr<Cluster> ClusterBuilder::Finish() {
218 DCHECK_NE(cluster_timecode_, -1);
220 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
222 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
227std::unique_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() {
228 DCHECK_NE(cluster_timecode_, -1);
230 UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize);
232 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
237void ClusterBuilder::Reset() {
238 buffer_size_ = kInitialBufferSize;
239 buffer_.reset(
new uint8_t[buffer_size_]);
240 memcpy(buffer_.get(), kClusterHeader,
sizeof(kClusterHeader));
241 bytes_used_ =
sizeof(kClusterHeader);
242 cluster_timecode_ = -1;
245void ClusterBuilder::ExtendBuffer(
int bytes_needed) {
246 int new_buffer_size = 2 * buffer_size_;
248 while ((new_buffer_size - bytes_used_) < bytes_needed)
249 new_buffer_size *= 2;
251 std::unique_ptr<uint8_t[]> new_buffer(
new uint8_t[new_buffer_size]);
253 memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
254 buffer_.reset(new_buffer.release());
255 buffer_size_ = new_buffer_size;
258void ClusterBuilder::UpdateUInt64(
int offset, int64_t value) {
259 DCHECK_LE(offset + 7, buffer_size_);
260 uint8_t* buf = buffer_.get() + offset;
263 for (
int i = 7; i > 0; i--) {
264 buf[i] = value & 0xff;
All the methods that are virtual are virtual for mocking.