Chromium Code Reviews| Index: media/webm/cluster_builder.cc |
| diff --git a/media/webm/cluster_builder.cc b/media/webm/cluster_builder.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2371ed71ec602c37875afee5e9288017a4cc710a |
| --- /dev/null |
| +++ b/media/webm/cluster_builder.cc |
| @@ -0,0 +1,122 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "media/webm/cluster_builder.h" |
| + |
| +#include "base/logging.h" |
| + |
| +namespace media { |
| + |
| +static const uint8 kClusterHeader[] = { |
| + 0x1F, 0x43, 0xB6, 0x75, // CLUSTER ID |
|
scherkus (not reviewing)
2011/06/28 20:03:29
two spaces
acolwell GONE FROM CHROMIUM
2011/06/29 16:38:43
Done.
|
| + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cluster(size = 0) |
| + 0xE7, // Timecode ID |
| + 0x88, // timecode(size=8) |
| + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value |
| +}; |
| + |
| +const int kClusterHeaderSize = sizeof(kClusterHeader); |
| +const int kClusterSizeOffset = 4; |
| +const int kClusterTimecodeOffset = 14; |
| + |
| +static const uint8 kSimpleBlockHeader[] = { |
| + 0xA3, // SimpleBlock ID |
|
scherkus (not reviewing)
2011/06/28 20:03:29
two spaces
acolwell GONE FROM CHROMIUM
2011/06/29 16:38:43
Done.
|
| + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0) |
| +}; |
| + |
| +const int kSimpleBlockHeaderSize = sizeof(kSimpleBlockHeader); |
| +const int kSimpleBlockSizeOffset = 1; |
| + |
| +const int kInitialBufferSize = 32768; |
| + |
| +ClusterBuilder::ClusterBuilder(int64 cluster_timecode) |
| + : buffer_(new uint8[kInitialBufferSize]), |
| + buffer_size_(kInitialBufferSize), |
| + bytes_used_(kClusterHeaderSize), |
| + cluster_timecode_(cluster_timecode), |
| + finished_(false) { |
| + memcpy(buffer_.get(), kClusterHeader, kClusterHeaderSize); |
| + |
| + // Write the timecode into the header. |
| + 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) { |
| + 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(!finished_); |
| + |
| + int64 timecode_delta = timecode - cluster_timecode_; |
| + DCHECK_GE(timecode_delta, -32768); |
| + DCHECK_LE(timecode_delta, 32767); |
| + |
| + int block_size = 4 + size; |
| + int bytes_needed = kSimpleBlockHeaderSize + 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, kSimpleBlockHeaderSize); |
| + UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size); |
| + buf += kSimpleBlockHeaderSize; |
| + |
| + 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); |
| + |
| + bytes_used_ += bytes_needed; |
| +} |
| + |
| +void ClusterBuilder::Finish() { |
|
scherkus (not reviewing)
2011/06/28 20:03:29
any checks for calling Finish twice?
also what if
acolwell GONE FROM CHROMIUM
2011/06/29 16:38:43
Added a DCHECK, created Cluster object, & updated
|
| + UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8)); |
| + finished_ = true; |
| +} |
| + |
| +const uint8* ClusterBuilder::GetClusterData() const { |
| + DCHECK(finished_) << "Finish() MUST be called before GetClusterData()"; |
| + return buffer_.get(); |
| +} |
| + |
| +const int ClusterBuilder::GetClusterDataSize() const { |
| + DCHECK(finished_) << "Finish() MUST be called before GetClusterDataSize()"; |
| + return bytes_used_; |
| +} |
| + |
| +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_array<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; |
| + |
| + // Fill the last 7 bytes of size field in big-endian order. |
| + for (int i = 7; i > 0; i--) { |
| + buf[i] = value & 0xff; |
| + value >>= 8; |
| + } |
| +} |
| + |
| +} // namespace media |