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..eb5fbfb0e84d2e2d94d28f7fddf68f120ebc6b21 |
--- /dev/null |
+++ b/media/webm/cluster_builder.cc |
@@ -0,0 +1,128 @@ |
+// 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" |
+#include "media/base/data_buffer.h" |
+ |
+namespace media { |
+ |
+static const uint8 kClusterHeader[] = { |
+ 0x1F, 0x43, 0xB6, 0x75, // CLUSTER ID |
+ 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 |
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0) |
+}; |
+ |
+const int kSimpleBlockHeaderSize = sizeof(kSimpleBlockHeader); |
+const int kSimpleBlockSizeOffset = 1; |
+ |
+const int kInitialBufferSize = 32768; |
+ |
+Cluster::Cluster(const uint8* data, int size) : data_(data), size_(size) {} |
+Cluster::~Cluster() {} |
+ |
+ClusterBuilder::ClusterBuilder() { Reset(); } |
+ |
+void ClusterBuilder::SetClusterTimecode(int64 cluster_timecode) { |
+ DCHECK_EQ(cluster_timecode_, -1); |
+ |
+ cluster_timecode_ = cluster_timecode; |
+ |
+ // 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_NE(cluster_timecode_, -1); |
+ |
+ 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; |
+} |
+ |
+Cluster* ClusterBuilder::Finish() { |
+ DCHECK_NE(cluster_timecode_, -1); |
+ |
+ UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8)); |
+ |
+ scoped_ptr<Cluster> ret(new Cluster(buffer_.release(), bytes_used_)); |
+ Reset(); |
+ return ret.release(); |
+} |
+ |
+void ClusterBuilder::Reset() { |
+ buffer_size_ = kInitialBufferSize; |
+ buffer_.reset(new uint8[buffer_size_]); |
+ memcpy(buffer_.get(), kClusterHeader, kClusterHeaderSize); |
+ bytes_used_ = kClusterHeaderSize; |
+ 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_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 |