This source file includes following definitions.
- size_
- SetClusterTimecode
- AddSimpleBlock
- AddBlockGroup
- WriteBlock
- Finish
- Reset
- ExtendBuffer
- UpdateUInt64
#include "media/formats/webm/cluster_builder.h"
#include "base/logging.h"
#include "media/base/data_buffer.h"
namespace media {
static const uint8 kClusterHeader[] = {
0x1F, 0x43, 0xB6, 0x75,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE7,
0x88,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8 kSimpleBlockHeader[] = {
0xA3,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8 kBlockGroupHeader[] = {
0xA0,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9B,
0x88,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xA1,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
enum {
kClusterSizeOffset = 4,
kClusterTimecodeOffset = 14,
kSimpleBlockSizeOffset = 1,
kBlockGroupSizeOffset = 1,
kBlockGroupDurationOffset = 11,
kBlockGroupBlockSizeOffset = 20,
kInitialBufferSize = 32768,
};
Cluster::Cluster(scoped_ptr<uint8[]> data, int size)
: data_(data.Pass()), size_(size) {}
Cluster::~Cluster() {}
ClusterBuilder::ClusterBuilder() { Reset(); }
ClusterBuilder::~ClusterBuilder() {}
void ClusterBuilder::SetClusterTimecode(int64 cluster_timecode) {
DCHECK_EQ(cluster_timecode_, -1);
cluster_timecode_ = cluster_timecode;
uint8* buf = buffer_.get() + kClusterTimecodeOffset;
for (int i = 7; i >= 0; --i) {
buf[i] = cluster_timecode & 0xff;
cluster_timecode >>= 8;
}
}
void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags,
const uint8* data, int size) {
int block_size = size + 4;
int bytes_needed = sizeof(kSimpleBlockHeader) + block_size;
if (bytes_needed > (buffer_size_ - bytes_used_))
ExtendBuffer(bytes_needed);
uint8* buf = buffer_.get() + bytes_used_;
int block_offset = bytes_used_;
memcpy(buf, kSimpleBlockHeader, sizeof(kSimpleBlockHeader));
UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
buf += sizeof(kSimpleBlockHeader);
WriteBlock(buf, track_num, timecode, flags, data, size);
bytes_used_ += bytes_needed;
}
void ClusterBuilder::AddBlockGroup(int track_num, int64 timecode, int duration,
int flags, const uint8* data, int size) {
int block_size = size + 4;
int bytes_needed = sizeof(kBlockGroupHeader) + block_size;
int block_group_size = bytes_needed - 9;
if (bytes_needed > (buffer_size_ - bytes_used_))
ExtendBuffer(bytes_needed);
uint8* buf = buffer_.get() + bytes_used_;
int block_group_offset = bytes_used_;
memcpy(buf, kBlockGroupHeader, sizeof(kBlockGroupHeader));
UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
buf += sizeof(kBlockGroupHeader);
flags &= 0x0f;
WriteBlock(buf, track_num, timecode, flags, data, size);
bytes_used_ += bytes_needed;
}
void ClusterBuilder::WriteBlock(uint8* buf, int track_num, int64 timecode,
int flags, const uint8* data, int size) {
DCHECK_GE(track_num, 0);
DCHECK_LE(track_num, 126);
DCHECK_GE(flags, 0);
DCHECK_LE(flags, 0xff);
DCHECK(data);
DCHECK_GT(size, 0);
DCHECK_NE(cluster_timecode_, -1);
int64 timecode_delta = timecode - cluster_timecode_;
DCHECK_GE(timecode_delta, -32768);
DCHECK_LE(timecode_delta, 32767);
buf[0] = 0x80 | (track_num & 0x7F);
buf[1] = (timecode_delta >> 8) & 0xff;
buf[2] = timecode_delta & 0xff;
buf[3] = flags & 0xff;
memcpy(buf + 4, data, size);
}
scoped_ptr<Cluster> ClusterBuilder::Finish() {
DCHECK_NE(cluster_timecode_, -1);
UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8));
scoped_ptr<Cluster> ret(new Cluster(buffer_.Pass(), bytes_used_));
Reset();
return ret.Pass();
}
void ClusterBuilder::Reset() {
buffer_size_ = kInitialBufferSize;
buffer_.reset(new uint8[buffer_size_]);
memcpy(buffer_.get(), kClusterHeader, sizeof(kClusterHeader));
bytes_used_ = sizeof(kClusterHeader);
cluster_timecode_ = -1;
}
void ClusterBuilder::ExtendBuffer(int bytes_needed) {
int new_buffer_size = 2 * buffer_size_;
while ((new_buffer_size - bytes_used_) < bytes_needed)
new_buffer_size *= 2;
scoped_ptr<uint8[]> new_buffer(new uint8[new_buffer_size]);
memcpy(new_buffer.get(), buffer_.get(), bytes_used_);
buffer_.reset(new_buffer.release());
buffer_size_ = new_buffer_size;
}
void ClusterBuilder::UpdateUInt64(int offset, int64 value) {
DCHECK_LE(offset + 7, buffer_size_);
uint8* buf = buffer_.get() + offset;
for (int i = 7; i > 0; i--) {
buf[i] = value & 0xff;
value >>= 8;
}
}
}