5 #include "packager/media/formats/webm/cluster_builder.h" 7 #include "packager/base/logging.h" 8 #include "packager/media/formats/webm/webm_constants.h" 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,
43 static const uint8_t kBlockGroupReferenceBlock[] = {
49 kClusterSizeOffset = 4,
50 kClusterTimecodeOffset = 14,
52 kSimpleBlockSizeOffset = 1,
54 kBlockGroupSizeOffset = 1,
55 kBlockGroupWithoutBlockDurationBlockSizeOffset = 10,
56 kBlockGroupDurationOffset = 11,
57 kBlockGroupBlockSizeOffset = 20,
59 kInitialBufferSize = 32768,
62 Cluster::Cluster(std::unique_ptr<uint8_t[]> data,
int size)
63 : data_(
std::move(data)), size_(size) {}
64 Cluster::~Cluster() {}
66 ClusterBuilder::ClusterBuilder() { Reset(); }
67 ClusterBuilder::~ClusterBuilder() {}
69 void ClusterBuilder::SetClusterTimecode(int64_t cluster_timecode) {
70 DCHECK_EQ(cluster_timecode_, -1);
72 cluster_timecode_ = cluster_timecode;
75 uint8_t* buf = buffer_.get() + kClusterTimecodeOffset;
76 for (
int i = 7; i >= 0; --i) {
77 buf[i] = cluster_timecode & 0xff;
78 cluster_timecode >>= 8;
82 void ClusterBuilder::AddSimpleBlock(
int track_num,
87 int block_size = size + 4;
88 int bytes_needed =
sizeof(kSimpleBlockHeader) + block_size;
89 if (bytes_needed > (buffer_size_ - bytes_used_))
90 ExtendBuffer(bytes_needed);
92 uint8_t* buf = buffer_.get() + bytes_used_;
93 int block_offset = bytes_used_;
94 memcpy(buf, kSimpleBlockHeader,
sizeof(kSimpleBlockHeader));
95 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
96 buf +=
sizeof(kSimpleBlockHeader);
98 WriteBlock(buf, track_num, timecode, flags, data, size);
100 bytes_used_ += bytes_needed;
103 void ClusterBuilder::AddBlockGroup(
int track_num,
110 AddBlockGroupInternal(track_num, timecode,
true, duration, flags,
111 is_key_frame, data, size);
114 void ClusterBuilder::AddBlockGroupWithoutBlockDuration(
int track_num,
120 AddBlockGroupInternal(track_num, timecode,
false, 0, flags, is_key_frame,
124 void ClusterBuilder::AddBlockGroupInternal(
int track_num,
126 bool include_block_duration,
132 int block_size = size + 4;
133 int bytes_needed = block_size;
134 if (include_block_duration) {
135 bytes_needed +=
sizeof(kBlockGroupHeader);
137 bytes_needed +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
140 bytes_needed +=
sizeof(kBlockGroupReferenceBlock);
143 int block_group_size = bytes_needed - 9;
145 if (bytes_needed > (buffer_size_ - bytes_used_))
146 ExtendBuffer(bytes_needed);
148 uint8_t* buf = buffer_.get() + bytes_used_;
149 int block_group_offset = bytes_used_;
150 if (include_block_duration) {
151 memcpy(buf, kBlockGroupHeader,
sizeof(kBlockGroupHeader));
152 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
153 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
154 buf +=
sizeof(kBlockGroupHeader);
156 memcpy(buf, kBlockGroupHeaderWithoutBlockDuration,
157 sizeof(kBlockGroupHeaderWithoutBlockDuration));
159 block_group_offset + kBlockGroupWithoutBlockDurationBlockSizeOffset,
161 buf +=
sizeof(kBlockGroupHeaderWithoutBlockDuration);
164 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
170 WriteBlock(buf, track_num, timecode, flags, data, size);
174 memcpy(buf, kBlockGroupReferenceBlock,
sizeof(kBlockGroupReferenceBlock));
175 bytes_used_ += bytes_needed;
178 void ClusterBuilder::WriteBlock(uint8_t* buf,
184 DCHECK_GE(track_num, 0);
185 DCHECK_LE(track_num, 126);
187 DCHECK_LE(flags, 0xff);
190 DCHECK_NE(cluster_timecode_, -1);
192 int64_t timecode_delta = timecode - cluster_timecode_;
193 DCHECK_GE(timecode_delta, -32768);
194 DCHECK_LE(timecode_delta, 32767);
196 buf[0] = 0x80 | (track_num & 0x7F);
197 buf[1] = (timecode_delta >> 8) & 0xff;
198 buf[2] = timecode_delta & 0xff;
199 buf[3] = flags & 0xff;
200 memcpy(buf + 4, data, size);
203 std::unique_ptr<Cluster> ClusterBuilder::Finish() {
204 DCHECK_NE(cluster_timecode_, -1);
206 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
208 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
213 std::unique_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() {
214 DCHECK_NE(cluster_timecode_, -1);
216 UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize);
218 std::unique_ptr<Cluster> ret(
new Cluster(std::move(buffer_), bytes_used_));
223 void ClusterBuilder::Reset() {
224 buffer_size_ = kInitialBufferSize;
225 buffer_.reset(
new uint8_t[buffer_size_]);
226 memcpy(buffer_.get(), kClusterHeader,
sizeof(kClusterHeader));
227 bytes_used_ =
sizeof(kClusterHeader);
228 cluster_timecode_ = -1;
231 void ClusterBuilder::ExtendBuffer(
int bytes_needed) {
232 int new_buffer_size = 2 * buffer_size_;
234 while ((new_buffer_size - bytes_used_) < bytes_needed)
235 new_buffer_size *= 2;
237 std::unique_ptr<uint8_t[]> new_buffer(
new uint8_t[new_buffer_size]);
239 memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
240 buffer_.reset(new_buffer.release());
241 buffer_size_ = new_buffer_size;
244 void ClusterBuilder::UpdateUInt64(
int offset, int64_t value) {
245 DCHECK_LE(offset + 7, buffer_size_);
246 uint8_t* buf = buffer_.get() + offset;
249 for (
int i = 7; i > 0; i--) {
250 buf[i] = value & 0xff;
All the methods that are virtual are virtual for mocking.