tsMuxer/tsMuxer/bitStream.h

244 lines
6.8 KiB
C++

#ifndef __BITSTREAM_H
#define __BITSTREAM_H
#include <assert.h>
#include <limits.h>
#include <types/types.h>
constexpr static unsigned INT_BIT = CHAR_BIT * sizeof(unsigned);
class BitStreamException : public std::exception
{
public:
// BitStreamException(const char* str): std::exception(str) {}
// BitStreamException(const std::string& str): std::exception(str.c_str()) {}
BitStreamException() : std::exception() {}
};
//#define THROW_BITSTREAM_ERR throw BitStreamException(std::string(__FILE__) + std::string(" ") +
// std::string(__FUNCTION__) + std::string(" at line ") + int32ToStr(__LINE__))
#define THROW_BITSTREAM_ERR throw BitStreamException()
class BitStream
{
public:
inline uint8_t* getBuffer() const { return (uint8_t*)m_initBuffer; }
inline unsigned getBitsLeft() const { return m_totalBits; }
protected:
inline void setBuffer(uint8_t* buffer, uint8_t* end)
{
if (buffer >= end)
THROW_BITSTREAM_ERR;
m_totalBits = (unsigned)(end - buffer) * 8;
m_initBuffer = m_buffer = (unsigned*)buffer;
}
unsigned m_totalBits;
unsigned* m_buffer;
unsigned* m_initBuffer;
constexpr static unsigned int m_masks[] = {
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff,
0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff,
0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, UINT_MAX};
};
class BitStreamReader : public BitStream
{
private:
inline unsigned getCurVal(unsigned* buff)
{
auto tmpBuf = (uint8_t*)buff;
if (m_totalBits - m_bitLeft >= 32)
return my_ntohl(*buff);
else if (m_totalBits - m_bitLeft >= 24)
return (tmpBuf[0] << 24) + (tmpBuf[1] << 16) + (tmpBuf[2] << 8);
else if (m_totalBits - m_bitLeft >= 16)
return (tmpBuf[0] << 24) + (tmpBuf[1] << 16);
else if (m_totalBits - m_bitLeft >= 8)
return tmpBuf[0] << 24;
else
THROW_BITSTREAM_ERR;
}
public:
inline void setBuffer(uint8_t* buffer, uint8_t* end)
{
BitStream::setBuffer(buffer, end);
m_bitLeft = 0;
m_curVal = getCurVal(m_buffer);
m_bitLeft = INT_BIT;
}
inline unsigned getBits(unsigned num)
{
if (num > INT_BIT)
THROW_BITSTREAM_ERR;
if (m_totalBits < num)
THROW_BITSTREAM_ERR;
unsigned prevVal = 0;
if (num <= m_bitLeft)
m_bitLeft -= num;
else
{
if (!(num == INT_BIT && m_bitLeft == 0))
{
prevVal = (m_curVal & m_masks[m_bitLeft]) << (num - m_bitLeft);
}
m_buffer++;
m_curVal = getCurVal(m_buffer);
m_bitLeft += INT_BIT - num;
}
m_totalBits -= num;
return prevVal + (m_curVal >> m_bitLeft) & m_masks[num];
}
inline unsigned showBits(unsigned num)
{
assert(num <= INT_BIT);
if (m_totalBits < num)
THROW_BITSTREAM_ERR;
unsigned prevVal = 0;
unsigned bitLeft = m_bitLeft;
unsigned curVal = m_curVal;
if (num <= bitLeft)
bitLeft -= num;
else
{
if (!(num == INT_BIT && bitLeft == 0))
{
prevVal = (curVal & m_masks[bitLeft]) << (num - bitLeft);
}
curVal = getCurVal(m_buffer + 1);
bitLeft += INT_BIT - num;
}
return prevVal + (curVal >> bitLeft) & m_masks[num];
}
inline unsigned getBit()
{
if (m_totalBits < 1)
THROW_BITSTREAM_ERR;
if (m_bitLeft > 0)
m_bitLeft--;
else
{
m_buffer++;
m_curVal = getCurVal(m_buffer);
m_bitLeft = INT_BIT - 1;
}
m_totalBits--;
return (m_curVal >> m_bitLeft) & 1;
}
inline void skipBits(unsigned num)
{
if (m_totalBits < num)
THROW_BITSTREAM_ERR;
assert(num <= INT_BIT);
if (num <= m_bitLeft)
m_bitLeft -= num;
else
{
m_buffer++;
m_curVal = getCurVal(m_buffer);
m_bitLeft += INT_BIT - num;
}
m_totalBits -= num;
}
inline void skipBit()
{
if (m_totalBits < 1)
THROW_BITSTREAM_ERR;
if (m_bitLeft > 0)
m_bitLeft--;
else
{
m_buffer++;
m_curVal = getCurVal(m_buffer);
m_bitLeft = INT_BIT - 1;
}
m_totalBits--;
}
inline unsigned getBitsCount() const { return (unsigned)(m_buffer - m_initBuffer) * INT_BIT + INT_BIT - m_bitLeft; }
private:
unsigned m_curVal;
unsigned m_bitLeft;
};
class BitStreamWriter : public BitStream
{
public:
inline void setBuffer(uint8_t* buffer, uint8_t* end)
{
BitStream::setBuffer(buffer, end);
m_curVal = 0;
m_bitWrited = 0;
}
inline void skipBits(unsigned cnt)
{
assert(m_bitWrited % INT_BIT == 0);
BitStreamReader reader{};
reader.setBuffer((uint8_t*)m_buffer, (uint8_t*)(m_buffer + 1));
putBits(cnt, reader.getBits(cnt));
}
inline void putBits(unsigned num, unsigned value)
{
if (m_totalBits < num)
THROW_BITSTREAM_ERR;
value &= m_masks[num];
if (m_bitWrited + num < INT_BIT)
{
m_bitWrited += num;
m_curVal <<= num;
m_curVal += value;
}
else
{
if (m_bitWrited != 0)
{
m_curVal <<= (INT_BIT - m_bitWrited);
m_bitWrited += num - INT_BIT;
}
m_curVal += value >> m_bitWrited;
*m_buffer++ = my_htonl(m_curVal);
m_curVal = value & m_masks[m_bitWrited];
}
m_totalBits -= num;
}
inline void putBit(unsigned value) { putBits(1, value); }
inline void flushBits()
{
if (m_bitWrited != 0)
{
m_curVal <<= (INT_BIT - m_bitWrited);
}
unsigned prevVal = my_ntohl(*m_buffer);
prevVal &= m_masks[INT_BIT - m_bitWrited];
prevVal |= m_curVal;
*m_buffer = my_htonl(prevVal);
}
inline unsigned getBitsCount() { return (unsigned)(m_buffer - m_initBuffer) * INT_BIT + m_bitWrited; }
private:
unsigned m_curVal;
unsigned m_bitWrited;
};
void updateBits(const BitStreamReader& bitReader, int bitOffset, int bitLen, int value);
void updateBits(const uint8_t* buffer, int bitOffset, int bitLen, int value);
// move len bits from oldBitOffset position to newBitOffset
void moveBits(uint8_t* buffer, int oldBitOffset, int newBitOffset, int len);
#endif