/* * 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 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