Chromium Code Reviews| 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 | |
| 9 namespace media { | |
| 10 | |
| 11 static const uint8 kClusterHeader[] = { | |
| 12 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.
| |
| 13 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cluster(size = 0) | |
| 14 0xE7, // Timecode ID | |
| 15 0x88, // timecode(size=8) | |
| 16 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value | |
| 17 }; | |
| 18 | |
| 19 const int kClusterHeaderSize = sizeof(kClusterHeader); | |
| 20 const int kClusterSizeOffset = 4; | |
| 21 const int kClusterTimecodeOffset = 14; | |
| 22 | |
| 23 static const uint8 kSimpleBlockHeader[] = { | |
| 24 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.
| |
| 25 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0) | |
| 26 }; | |
| 27 | |
| 28 const int kSimpleBlockHeaderSize = sizeof(kSimpleBlockHeader); | |
| 29 const int kSimpleBlockSizeOffset = 1; | |
| 30 | |
| 31 const int kInitialBufferSize = 32768; | |
| 32 | |
| 33 ClusterBuilder::ClusterBuilder(int64 cluster_timecode) | |
| 34 : buffer_(new uint8[kInitialBufferSize]), | |
| 35 buffer_size_(kInitialBufferSize), | |
| 36 bytes_used_(kClusterHeaderSize), | |
| 37 cluster_timecode_(cluster_timecode), | |
| 38 finished_(false) { | |
| 39 memcpy(buffer_.get(), kClusterHeader, kClusterHeaderSize); | |
| 40 | |
| 41 // Write the timecode into the header. | |
| 42 uint8* buf = buffer_.get() + kClusterTimecodeOffset; | |
| 43 for (int i = 7; i >= 0; --i) { | |
| 44 buf[i] = cluster_timecode & 0xff; | |
| 45 cluster_timecode >>= 8; | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags, | |
| 50 const uint8* data, int size) { | |
| 51 DCHECK_GE(track_num, 0); | |
| 52 DCHECK_LE(track_num, 126); | |
| 53 DCHECK_GE(flags, 0); | |
| 54 DCHECK_LE(flags, 0xff); | |
| 55 DCHECK(data); | |
| 56 DCHECK_GT(size, 0); | |
| 57 DCHECK(!finished_); | |
| 58 | |
| 59 int64 timecode_delta = timecode - cluster_timecode_; | |
| 60 DCHECK_GE(timecode_delta, -32768); | |
| 61 DCHECK_LE(timecode_delta, 32767); | |
| 62 | |
| 63 int block_size = 4 + size; | |
| 64 int bytes_needed = kSimpleBlockHeaderSize + block_size; | |
| 65 if (bytes_needed > (buffer_size_ - bytes_used_)) | |
| 66 ExtendBuffer(bytes_needed); | |
| 67 | |
| 68 uint8* buf = buffer_.get() + bytes_used_; | |
| 69 int block_offset = bytes_used_; | |
| 70 memcpy(buf, kSimpleBlockHeader, kSimpleBlockHeaderSize); | |
| 71 UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size); | |
| 72 buf += kSimpleBlockHeaderSize; | |
| 73 | |
| 74 buf[0] = 0x80 | (track_num & 0x7F); | |
| 75 buf[1] = (timecode_delta >> 8) & 0xff; | |
| 76 buf[2] = timecode_delta & 0xff; | |
| 77 buf[3] = flags & 0xff; | |
| 78 memcpy(buf + 4, data, size); | |
| 79 | |
| 80 bytes_used_ += bytes_needed; | |
| 81 } | |
| 82 | |
| 83 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
| |
| 84 UpdateUInt64(kClusterSizeOffset, bytes_used_ - (kClusterSizeOffset + 8)); | |
| 85 finished_ = true; | |
| 86 } | |
| 87 | |
| 88 const uint8* ClusterBuilder::GetClusterData() const { | |
| 89 DCHECK(finished_) << "Finish() MUST be called before GetClusterData()"; | |
| 90 return buffer_.get(); | |
| 91 } | |
| 92 | |
| 93 const int ClusterBuilder::GetClusterDataSize() const { | |
| 94 DCHECK(finished_) << "Finish() MUST be called before GetClusterDataSize()"; | |
| 95 return bytes_used_; | |
| 96 } | |
| 97 | |
| 98 void ClusterBuilder::ExtendBuffer(int bytes_needed) { | |
| 99 int new_buffer_size = 2 * buffer_size_; | |
| 100 | |
| 101 while ((new_buffer_size - bytes_used_) < bytes_needed) | |
| 102 new_buffer_size *= 2; | |
| 103 | |
| 104 scoped_array<uint8> new_buffer(new uint8[new_buffer_size]); | |
| 105 | |
| 106 memcpy(new_buffer.get(), buffer_.get(), bytes_used_); | |
| 107 buffer_.reset(new_buffer.release()); | |
| 108 buffer_size_ = new_buffer_size; | |
| 109 } | |
| 110 | |
| 111 void ClusterBuilder::UpdateUInt64(int offset, int64 value) { | |
| 112 DCHECK_LE(offset + 7, buffer_size_); | |
| 113 uint8* buf = buffer_.get() + offset; | |
| 114 | |
| 115 // Fill the last 7 bytes of size field in big-endian order. | |
| 116 for (int i = 7; i > 0; i--) { | |
| 117 buf[i] = value & 0xff; | |
| 118 value >>= 8; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 } // namespace media | |
| OLD | NEW |