| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "bitstream_builder.h" |
| |
| #include <string.h> |
| |
| namespace webrtc { |
| BitstreamBuilder::BitstreamBuilder(WebRtc_UWord8* data, const WebRtc_UWord32 dataSize) : |
| _data(data), |
| _dataSize(dataSize), |
| _byteOffset(0), |
| _bitOffset(0) |
| { |
| memset(data, 0, dataSize); |
| } |
| |
| WebRtc_UWord32 |
| BitstreamBuilder::Length() const |
| { |
| return _byteOffset+ (_bitOffset?1:0); |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add1Bit(const WebRtc_UWord8 bit) |
| { |
| // sanity |
| if(_bitOffset + 1 > 8) |
| { |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| } |
| Add1BitWithoutSanity(bit); |
| return 0; |
| } |
| |
| void |
| BitstreamBuilder::Add1BitWithoutSanity(const WebRtc_UWord8 bit) |
| { |
| if(bit & 0x1) |
| { |
| _data[_byteOffset] += (1 << (7-_bitOffset)); |
| } |
| |
| if(_bitOffset == 7) |
| { |
| // last bit in byte |
| _bitOffset = 0; |
| _byteOffset++; |
| } else |
| { |
| _bitOffset++; |
| } |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add2Bits(const WebRtc_UWord8 bits) |
| { |
| // sanity |
| if(_bitOffset + 2 > 8) |
| { |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| } |
| Add1BitWithoutSanity(bits >> 1); |
| Add1BitWithoutSanity(bits); |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add3Bits(const WebRtc_UWord8 bits) |
| { |
| // sanity |
| if(_bitOffset + 3 > 8) |
| { |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| } |
| Add1BitWithoutSanity(bits >> 2); |
| Add1BitWithoutSanity(bits >> 1); |
| Add1BitWithoutSanity(bits); |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add4Bits(const WebRtc_UWord8 bits) |
| { |
| // sanity |
| if(_bitOffset + 4 > 8) |
| { |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| } |
| Add1BitWithoutSanity(bits >> 3); |
| Add1BitWithoutSanity(bits >> 2); |
| Add1BitWithoutSanity(bits >> 1); |
| Add1BitWithoutSanity(bits); |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add5Bits(const WebRtc_UWord8 bits) |
| { |
| // sanity |
| if(_bitOffset + 5 > 8) |
| { |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| } |
| Add1BitWithoutSanity(bits >> 4); |
| Add1BitWithoutSanity(bits >> 3); |
| Add1BitWithoutSanity(bits >> 2); |
| Add1BitWithoutSanity(bits >> 1); |
| Add1BitWithoutSanity(bits); |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add6Bits(const WebRtc_UWord8 bits) |
| { |
| // sanity |
| if(_bitOffset + 6 > 8) |
| { |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| } |
| Add1BitWithoutSanity(bits >> 5); |
| Add1BitWithoutSanity(bits >> 4); |
| Add1BitWithoutSanity(bits >> 3); |
| Add1BitWithoutSanity(bits >> 2); |
| Add1BitWithoutSanity(bits >> 1); |
| Add1BitWithoutSanity(bits); |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add7Bits(const WebRtc_UWord8 bits) |
| { |
| // sanity |
| if(_bitOffset + 7 > 8) |
| { |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| } |
| Add1BitWithoutSanity(bits >> 6); |
| Add1BitWithoutSanity(bits >> 5); |
| Add1BitWithoutSanity(bits >> 4); |
| Add1BitWithoutSanity(bits >> 3); |
| Add1BitWithoutSanity(bits >> 2); |
| Add1BitWithoutSanity(bits >> 1); |
| Add1BitWithoutSanity(bits); |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add8Bits(const WebRtc_UWord8 bits) |
| { |
| // sanity |
| if(_dataSize < Length()+1) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| if(_bitOffset == 0) |
| { |
| _data[_byteOffset] = bits; |
| } else |
| { |
| _data[_byteOffset] += (bits >> _bitOffset); |
| _data[_byteOffset+1] += (bits << (8-_bitOffset)); |
| } |
| _byteOffset++; |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add16Bits(const WebRtc_UWord16 bits) |
| { |
| // sanity |
| if(_dataSize < Length()+2) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| if(_bitOffset == 0) |
| { |
| _data[_byteOffset] = (WebRtc_UWord8)(bits >> 8); |
| _data[_byteOffset+1] = (WebRtc_UWord8)(bits); |
| } else |
| { |
| _data[_byteOffset] += (WebRtc_UWord8)(bits >> (_bitOffset + 8)); |
| _data[_byteOffset+1] += (WebRtc_UWord8)(bits >> _bitOffset); |
| _data[_byteOffset+2] += (WebRtc_UWord8)(bits << (8-_bitOffset)); |
| } |
| _byteOffset += 2; |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add24Bits(const WebRtc_UWord32 bits) |
| { |
| // sanity |
| if(_dataSize < Length()+3) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| if(_bitOffset == 0) |
| { |
| _data[_byteOffset] = (WebRtc_UWord8)(bits >> 16); |
| _data[_byteOffset+1] = (WebRtc_UWord8)(bits >> 8); |
| _data[_byteOffset+2] = (WebRtc_UWord8)(bits); |
| } else |
| { |
| _data[_byteOffset] += (WebRtc_UWord8)(bits >> (_bitOffset+16)); |
| _data[_byteOffset+1] += (WebRtc_UWord8)(bits >> (_bitOffset+8)); |
| _data[_byteOffset+2] += (WebRtc_UWord8)(bits >> (_bitOffset)); |
| _data[_byteOffset+3] += (WebRtc_UWord8)(bits << (8-_bitOffset)); |
| } |
| _byteOffset += 3; |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::Add32Bits(const WebRtc_UWord32 bits) |
| { |
| // sanity |
| if(_dataSize < Length()+4) |
| { |
| // not enough space in buffer |
| return -1; |
| } |
| if(_bitOffset == 0) |
| { |
| _data[_byteOffset] = (WebRtc_UWord8)(bits >> 24); |
| _data[_byteOffset+1] = (WebRtc_UWord8)(bits >> 16); |
| _data[_byteOffset+2] = (WebRtc_UWord8)(bits >> 8); |
| _data[_byteOffset+3] = (WebRtc_UWord8)(bits); |
| } else |
| { |
| _data[_byteOffset] += (WebRtc_UWord8)(bits >> (_bitOffset+24)); |
| _data[_byteOffset+1] += (WebRtc_UWord8)(bits >> (_bitOffset+16)); |
| _data[_byteOffset+2] += (WebRtc_UWord8)(bits >> (_bitOffset+8)); |
| _data[_byteOffset+3] += (WebRtc_UWord8)(bits >> (_bitOffset)); |
| _data[_byteOffset+4] += (WebRtc_UWord8)(bits << (8-_bitOffset)); |
| } |
| _byteOffset += 4; |
| return 0; |
| } |
| |
| // Exp-Golomb codes |
| /* |
| with "prefix" and "suffix" bits and assignment to codeNum ranges (informative) |
| Bit string form Range of codeNum |
| 1 0 |
| 0 1 x0 1..2 2bits-1 |
| 0 0 1 x1 x0 3..6 3bits-1 |
| 0 0 0 1 x2 x1 x0 7..14 4bits-1 |
| 0 0 0 0 1 x3 x2 x1 x0 15..30 |
| 0 0 0 0 0 1 x4 x3 x2 x1 x0 31..62 |
| */ |
| WebRtc_Word32 |
| BitstreamBuilder::AddUE(const WebRtc_UWord32 value) |
| { |
| // un-rolled on 8 bit base to avoid too deep if else chain |
| if(value < 0x0000ffff) |
| { |
| if(value < 0x000000ff) |
| { |
| if(value == 0) |
| { |
| if(AddPrefix(0) != 0) |
| { |
| return -1; |
| } |
| } else if(value < 3) |
| { |
| if(AddPrefix(1) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(1, value-1); |
| } else if(value < 7) |
| { |
| if(AddPrefix(2) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(2, value-3); |
| } else if(value < 15) |
| { |
| if(AddPrefix(3) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(3, value-7); |
| } else if(value < 31) |
| { |
| if(AddPrefix(4) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(4, value-15); |
| } else if(value < 63) |
| { |
| if(AddPrefix(5) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(5, value-31); |
| } else if(value < 127) |
| { |
| if(AddPrefix(6) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(6, value-63); |
| } else |
| { |
| if(AddPrefix(7) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(7, value-127); |
| } |
| }else |
| { |
| if(value < 0x000001ff) |
| { |
| if(AddPrefix(8) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(8, value-0x000000ff); |
| } else if(value < 0x000003ff) |
| { |
| if(AddPrefix(9) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(9, value-0x000001ff); |
| } else if(value < 0x000007ff) |
| { |
| if(AddPrefix(10) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(10, value-0x000003ff); |
| } else if(value < 0x00000fff) |
| { |
| if(AddPrefix(11) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(1, value-0x000007ff); |
| } else if(value < 0x00001fff) |
| { |
| if(AddPrefix(12) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(12, value-0x00000fff); |
| } else if(value < 0x00003fff) |
| { |
| if(AddPrefix(13) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(13, value-0x00001fff); |
| } else if(value < 0x00007fff) |
| { |
| if(AddPrefix(14) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(14, value-0x00003fff); |
| } else |
| { |
| if(AddPrefix(15) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(15, value-0x00007fff); |
| } |
| } |
| }else |
| { |
| if(value < 0x00ffffff) |
| { |
| if(value < 0x0001ffff) |
| { |
| if(AddPrefix(16) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(16, value-0x0000ffff); |
| } else if(value < 0x0003ffff) |
| { |
| if(AddPrefix(17) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(17, value-0x0001ffff); |
| } else if(value < 0x0007ffff) |
| { |
| if(AddPrefix(18) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(18, value-0x0003ffff); |
| } else if(value < 0x000fffff) |
| { |
| if(AddPrefix(19) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(19, value-0x0007ffff); |
| } else if(value < 0x001fffff) |
| { |
| if(AddPrefix(20) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(20, value-0x000fffff); |
| } else if(value < 0x003fffff) |
| { |
| if(AddPrefix(21) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(21, value-0x001fffff); |
| } else if(value < 0x007fffff) |
| { |
| if(AddPrefix(22) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(22, value-0x003fffff); |
| } else |
| { |
| if(AddPrefix(23) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(23, value-0x007fffff); |
| } |
| } else |
| { |
| if(value < 0x01ffffff) |
| { |
| if(AddPrefix(24) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(24, value-0x00ffffff); |
| } else if(value < 0x03ffffff) |
| { |
| if(AddPrefix(25) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(25, value-0x01ffffff); |
| } else if(value < 0x07ffffff) |
| { |
| if(AddPrefix(26) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(26, value-0x03ffffff); |
| } else if(value < 0x0fffffff) |
| { |
| if(AddPrefix(27) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(27, value-0x07ffffff); |
| } else if(value < 0x1fffffff) |
| { |
| if(AddPrefix(28) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(28, value-0x0fffffff); |
| } else if(value < 0x3fffffff) |
| { |
| if(AddPrefix(29) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(29, value-0x1fffffff); |
| } else if(value < 0x7fffffff) |
| { |
| if(AddPrefix(30) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(30, value-0x3fffffff); |
| } else if(value < 0xffffffff) |
| { |
| if(AddPrefix(31) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(31, value-0x7ffffff); |
| } else |
| { |
| if(AddPrefix(32) != 0) |
| { |
| return -1; |
| } |
| AddSuffix(32, 0); // exactly 0xffffffff |
| } |
| } |
| } |
| return 0; |
| } |
| |
| WebRtc_Word32 |
| BitstreamBuilder::AddPrefix(const WebRtc_UWord8 numZeros) |
| { |
| // sanity for the sufix too |
| WebRtc_UWord32 numBitsToAdd = numZeros * 2 + 1; |
| if(((_dataSize - _byteOffset) *8 + 8-_bitOffset) < numBitsToAdd) |
| { |
| return -1; |
| } |
| |
| // add numZeros |
| for (WebRtc_UWord32 i = 0; i < numZeros; i++) |
| { |
| Add1Bit(0); |
| } |
| Add1Bit(1); |
| return 0; |
| } |
| |
| void |
| BitstreamBuilder::AddSuffix(const WebRtc_UWord8 numBits, const WebRtc_UWord32 rest) |
| { |
| // most significant bit first |
| for(WebRtc_Word32 i = numBits - 1; i >= 0; i--) |
| { |
| if(( rest >> i) & 0x1) |
| { |
| Add1Bit(1); |
| }else |
| { |
| Add1Bit(0); |
| } |
| } |
| } |
| } // namespace webrtc |