blob: 05b7e2f0a2ac4fc7d86e3be9e09c96b6b0ee55dd [file] [log] [blame]
/*
* 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