OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/webm/cluster_builder.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "media/base/data_buffer.h" |
| 9 |
| 10 namespace media { |
| 11 |
| 12 static const uint8 kClusterHeader[] = { |
| 13 0x1F, 0x43, 0xB6, 0x75, // CLUSTER ID |
| 14 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cluster(size = 0) |
| 15 0xE7, // Timecode ID |
| 16 0x88, // timecode(size=8) |
| 17 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value |
| 18 }; |
| 19 |
| 20 const int kClusterHeaderSize = sizeof(kClusterHeader); |
| 21 const int kClusterSizeOffset = 4; |
| 22 const int kClusterTimecodeOffset = 14; |
| 23 |
| 24 static const uint8 kSimpleBlockHeader[] = { |
| 25 0xA3, // SimpleBlock ID |
| 26 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0) |
| 27 }; |
| 28 |
| 29 const int kSimpleBlockHeaderSize = sizeof(kSimpleBlockHeader); |
| 30 const int kSimpleBlockSizeOffset = 1; |
| 31 |
| 32 const int kInitialBufferSize = 32768; |
| 33 |
| 34 Cluster::Cluster(const uint8* data, int size) : data_(data), size_(size) {} |
| 35 Cluster::~Cluster() {} |
| 36 |
| 37 ClusterBuilder::ClusterBuilder() { Reset(); } |
| 38 |
| 39 void ClusterBuilder::SetClusterTimecode(int64 cluster_timecode) { |
| 40 DCHECK_EQ(cluster_timecode_, -1); |
| 41 |
| 42 cluster_timecode_ = cluster_timecode; |
| 43 |
| 44 // Write the timecode into the header. |
| 45 uint8* buf = buffer_.get() + kClusterTimecodeOffset; |
| 46 for (int i = 7; i >= 0; --i) { |
| 47 buf[i] = cluster_timecode & 0xff; |
| 48 cluster_timecode >>= 8; |
| 49 } |
| 50 } |
| 51 |
| 52 void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags, |
| 53 const uint8* data, int size) { |
| 54 DCHECK_GE(track_num, 0); |
| 55 DCHECK_LE(track_num, 126); |
| 56 DCHECK_GE(flags, 0); |
| 57 DCHECK_LE(flags, 0xff); |
| 58 DCHECK(data); |
| 59 DCHECK_GT(size, 0); |
| 60 DCHECK_NE(cluster_timecode_, -1); |
| 61 |
| 62 int64 timecode_delta = timecode - cluster_timecode_; |
| 63 DCHECK_GE(timecode_delta, -32768); |
| 64 DCHECK_LE(timecode_delta, 32767); |
| 65 |
| 66 int block_size = 4 + size; |
| 67 int bytes_needed = kSimpleBlockHeaderSize + block_size; |
| 68 if (bytes_needed > (buffer_size_ - bytes_used_)) |
| 69 ExtendBuffer(bytes_needed); |
| 70 |
| 71 uint8* buf = buffer_.get() + bytes_used_; |
| 72 int block_offset = bytes_used_; |
| 73 memcpy(buf, kSimpleBlockHeader, kSimpleBlockHeaderSize); |
| 74 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size); |
| 75 buf += kSimpleBlockHeaderSize; |
| 76 |
| 77 buf[0] = 0x80 | (track_num & 0x7F); |
| 78 buf[1] = (timecode_delta >> 8) & 0xff; |
| 79 buf[2] = timecode_delta & 0xff; |
| 80 buf[3] = flags & 0xff; |
| 81 memcpy(buf + 4, data, size); |
| 82 |
| 83 bytes_used_ += bytes_needed; |
| 84 } |
| 85 |
| 86 Cluster* ClusterBuilder::Finish() { |
| 87 DCHECK_NE(cluster_timecode_, -1); |
| 88 |
| 89 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8)); |
| 90 |
| 91 scoped_ptr<Cluster> ret(new Cluster(buffer_.release(), bytes_used_)); |
| 92 Reset(); |
| 93 return ret.release(); |
| 94 } |
| 95 |
| 96 void ClusterBuilder::Reset() { |
| 97 buffer_size_ = kInitialBufferSize; |
| 98 buffer_.reset(new uint8[buffer_size_]); |
| 99 memcpy(buffer_.get(), kClusterHeader, kClusterHeaderSize); |
| 100 bytes_used_ = kClusterHeaderSize; |
| 101 cluster_timecode_ = -1; |
| 102 } |
| 103 |
| 104 void ClusterBuilder::ExtendBuffer(int bytes_needed) { |
| 105 int new_buffer_size = 2 * buffer_size_; |
| 106 |
| 107 while ((new_buffer_size - bytes_used_) < bytes_needed) |
| 108 new_buffer_size *= 2; |
| 109 |
| 110 scoped_array<uint8> new_buffer(new uint8[new_buffer_size]); |
| 111 |
| 112 memcpy(new_buffer.get(), buffer_.get(), bytes_used_); |
| 113 buffer_.reset(new_buffer.release()); |
| 114 buffer_size_ = new_buffer_size; |
| 115 } |
| 116 |
| 117 void ClusterBuilder::UpdateUInt64(int offset, int64 value) { |
| 118 DCHECK_LE(offset + 7, buffer_size_); |
| 119 uint8* buf = buffer_.get() + offset; |
| 120 |
| 121 // Fill the last 7 bytes of size field in big-endian order. |
| 122 for (int i = 7; i > 0; i--) { |
| 123 buf[i] = value & 0xff; |
| 124 value >>= 8; |
| 125 } |
| 126 } |
| 127 |
| 128 } // namespace media |
OLD | NEW |