1 // Copyright 2014 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/formats/webm/cluster_builder.h" 6 7 #include "base/logging.h" 8 #include "media/base/data_buffer.h" 9 #include "media/formats/webm/webm_constants.h" 10 11 namespace media { 12 13 static const uint8 kClusterHeader[] = { 14 0x1F, 0x43, 0xB6, 0x75, // CLUSTER ID 15 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cluster(size = 0) 16 0xE7, // Timecode ID 17 0x88, // timecode(size=8) 18 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value 19 }; 20 21 static const uint8 kSimpleBlockHeader[] = { 22 0xA3, // SimpleBlock ID 23 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0) 24 }; 25 26 static const uint8 kBlockGroupHeader[] = { 27 0xA0, // BlockGroup ID 28 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // BlockGroup(size = 0) 29 0x9B, // BlockDuration ID 30 0x88, // BlockDuration(size = 8) 31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // duration 32 0xA1, // Block ID 33 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block(size = 0) 34 }; 35 36 static const uint8 kBlockGroupHeaderWithoutBlockDuration[] = { 37 0xA0, // BlockGroup ID 38 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // BlockGroup(size = 0) 39 0xA1, // Block ID 40 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block(size = 0) 41 }; 42 43 enum { 44 kClusterSizeOffset = 4, 45 kClusterTimecodeOffset = 14, 46 47 kSimpleBlockSizeOffset = 1, 48 49 kBlockGroupSizeOffset = 1, 50 kBlockGroupWithoutBlockDurationBlockSizeOffset = 10, 51 kBlockGroupDurationOffset = 11, 52 kBlockGroupBlockSizeOffset = 20, 53 54 kInitialBufferSize = 32768, 55 }; 56 57 Cluster::Cluster(scoped_ptr<uint8[]> data, int size) 58 : data_(data.Pass()), size_(size) {} 59 Cluster::~Cluster() {} 60 61 ClusterBuilder::ClusterBuilder() { Reset(); } 62 ClusterBuilder::~ClusterBuilder() {} 63 64 void ClusterBuilder::SetClusterTimecode(int64 cluster_timecode) { 65 DCHECK_EQ(cluster_timecode_, -1); 66 67 cluster_timecode_ = cluster_timecode; 68 69 // Write the timecode into the header. 70 uint8* buf = buffer_.get() + kClusterTimecodeOffset; 71 for (int i = 7; i >= 0; --i) { 72 buf[i] = cluster_timecode & 0xff; 73 cluster_timecode >>= 8; 74 } 75 } 76 77 void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags, 78 const uint8* data, int size) { 79 int block_size = size + 4; 80 int bytes_needed = sizeof(kSimpleBlockHeader) + block_size; 81 if (bytes_needed > (buffer_size_ - bytes_used_)) 82 ExtendBuffer(bytes_needed); 83 84 uint8* buf = buffer_.get() + bytes_used_; 85 int block_offset = bytes_used_; 86 memcpy(buf, kSimpleBlockHeader, sizeof(kSimpleBlockHeader)); 87 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size); 88 buf += sizeof(kSimpleBlockHeader); 89 90 WriteBlock(buf, track_num, timecode, flags, data, size); 91 92 bytes_used_ += bytes_needed; 93 } 94 95 void ClusterBuilder::AddBlockGroup(int track_num, int64 timecode, int duration, 96 int flags, const uint8* data, int size) { 97 AddBlockGroupInternal(track_num, timecode, true, duration, flags, data, size); 98 } 99 100 void ClusterBuilder::AddBlockGroupWithoutBlockDuration(int track_num, 101 int64 timecode, 102 int flags, 103 const uint8* data, 104 int size) { 105 AddBlockGroupInternal(track_num, timecode, false, 0, flags, data, size); 106 } 107 108 109 void ClusterBuilder::AddBlockGroupInternal(int track_num, int64 timecode, 110 bool include_block_duration, 111 int duration, int flags, 112 const uint8* data, int size) { 113 int block_size = size + 4; 114 int bytes_needed = block_size; 115 if (include_block_duration) { 116 bytes_needed += sizeof(kBlockGroupHeader); 117 } else { 118 bytes_needed += sizeof(kBlockGroupHeaderWithoutBlockDuration); 119 } 120 121 int block_group_size = bytes_needed - 9; 122 123 if (bytes_needed > (buffer_size_ - bytes_used_)) 124 ExtendBuffer(bytes_needed); 125 126 uint8* buf = buffer_.get() + bytes_used_; 127 int block_group_offset = bytes_used_; 128 if (include_block_duration) { 129 memcpy(buf, kBlockGroupHeader, sizeof(kBlockGroupHeader)); 130 UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration); 131 UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size); 132 buf += sizeof(kBlockGroupHeader); 133 } else { 134 memcpy(buf, kBlockGroupHeaderWithoutBlockDuration, 135 sizeof(kBlockGroupHeaderWithoutBlockDuration)); 136 UpdateUInt64( 137 block_group_offset + kBlockGroupWithoutBlockDurationBlockSizeOffset, 138 block_size); 139 buf += sizeof(kBlockGroupHeaderWithoutBlockDuration); 140 } 141 142 UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size); 143 144 // Make sure the 4 most-significant bits are 0. 145 // http://www.matroska.org/technical/specs/index.html#block_structure 146 flags &= 0x0f; 147 148 WriteBlock(buf, track_num, timecode, flags, data, size); 149 150 bytes_used_ += bytes_needed; 151 } 152 153 void ClusterBuilder::WriteBlock(uint8* buf, int track_num, int64 timecode, 154 int flags, const uint8* data, int size) { 155 DCHECK_GE(track_num, 0); 156 DCHECK_LE(track_num, 126); 157 DCHECK_GE(flags, 0); 158 DCHECK_LE(flags, 0xff); 159 DCHECK(data); 160 DCHECK_GT(size, 0); 161 DCHECK_NE(cluster_timecode_, -1); 162 163 int64 timecode_delta = timecode - cluster_timecode_; 164 DCHECK_GE(timecode_delta, -32768); 165 DCHECK_LE(timecode_delta, 32767); 166 167 buf[0] = 0x80 | (track_num & 0x7F); 168 buf[1] = (timecode_delta >> 8) & 0xff; 169 buf[2] = timecode_delta & 0xff; 170 buf[3] = flags & 0xff; 171 memcpy(buf + 4, data, size); 172 } 173 174 scoped_ptr<Cluster> ClusterBuilder::Finish() { 175 DCHECK_NE(cluster_timecode_, -1); 176 177 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8)); 178 179 scoped_ptr<Cluster> ret(new Cluster(buffer_.Pass(), bytes_used_)); 180 Reset(); 181 return ret.Pass(); 182 } 183 184 scoped_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() { 185 DCHECK_NE(cluster_timecode_, -1); 186 187 UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize); 188 189 scoped_ptr<Cluster> ret(new Cluster(buffer_.Pass(), bytes_used_)); 190 Reset(); 191 return ret.Pass(); 192 } 193 194 void ClusterBuilder::Reset() { 195 buffer_size_ = kInitialBufferSize; 196 buffer_.reset(new uint8[buffer_size_]); 197 memcpy(buffer_.get(), kClusterHeader, sizeof(kClusterHeader)); 198 bytes_used_ = sizeof(kClusterHeader); 199 cluster_timecode_ = -1; 200 } 201 202 void ClusterBuilder::ExtendBuffer(int bytes_needed) { 203 int new_buffer_size = 2 * buffer_size_; 204 205 while ((new_buffer_size - bytes_used_) < bytes_needed) 206 new_buffer_size *= 2; 207 208 scoped_ptr<uint8[]> new_buffer(new uint8[new_buffer_size]); 209 210 memcpy(new_buffer.get(), buffer_.get(), bytes_used_); 211 buffer_.reset(new_buffer.release()); 212 buffer_size_ = new_buffer_size; 213 } 214 215 void ClusterBuilder::UpdateUInt64(int offset, int64 value) { 216 DCHECK_LE(offset + 7, buffer_size_); 217 uint8* buf = buffer_.get() + offset; 218 219 // Fill the last 7 bytes of size field in big-endian order. 220 for (int i = 7; i > 0; i--) { 221 buf[i] = value & 0xff; 222 value >>= 8; 223 } 224 } 225 226 } // namespace media 227