#ifndef _AP4_BIT_STREAM_H_
#define _AP4_BIT_STREAM_H_
#include "Ap4Types.h"
#include "Ap4Results.h"
const int AP4_ERROR_BASE_BITSTREAM = -10000;
const unsigned int AP4_BITSTREAM_BUFFER_SIZE = 32768;
#define AP4_BITSTREAM_FLAG_EOS 0x01
const int AP4_ERROR_CORRUPTED_BITSTREAM = (AP4_ERROR_BASE_BITSTREAM - 0);
const int AP4_ERROR_NOT_ENOUGH_FREE_BUFFER = (AP4_ERROR_BASE_BITSTREAM - 1);
typedef unsigned int AP4_BitsWord;
#define AP4_WORD_BITS 32
#define AP4_WORD_BYTES 4
class AP4_BitStream
{
public:
AP4_BitStream();
~AP4_BitStream();
AP4_Result Reset();
AP4_Size GetContiguousBytesFree();
AP4_Size GetBytesFree();
AP4_Result WriteBytes(const AP4_UI08* bytes, AP4_Size byte_count);
AP4_Size GetContiguousBytesAvailable();
AP4_Size GetBytesAvailable();
AP4_Result ReadBytes(AP4_UI08* bytes, AP4_Size byte_count);
AP4_UI08 PeekByte();
AP4_Result PeekBytes(AP4_UI08* bytes, AP4_Size byte_count);
int ReadBit();
AP4_UI32 ReadBits(unsigned int bit_count);
int PeekBit();
AP4_UI32 PeekBits(unsigned int bit_count);
AP4_Result SkipBytes(AP4_Size byte_count);
void SkipBit();
void SkipBits(unsigned int bit_count);
AP4_Result ByteAlign();
AP4_UI08* m_Buffer;
unsigned int m_In;
unsigned int m_Out;
AP4_BitsWord m_Cache;
unsigned int m_BitsCached;
unsigned int m_Flags;
private:
AP4_BitsWord ReadCache() const;
};
#define AP4_BIT_MASK(_n) ((1<<(_n))-1)
#define AP4_BITSTREAM_POINTER_VAL(offset) \
((offset)&(AP4_BITSTREAM_BUFFER_SIZE-1))
#define AP4_BITSTREAM_POINTER_OFFSET(pointer, offset) \
(AP4_BITSTREAM_POINTER_VAL((pointer)+(offset)))
#define AP4_BITSTREAM_POINTER_ADD(pointer, offset) \
((pointer) = AP4_BITSTREAM_POINTER_OFFSET(pointer, offset))
inline AP4_BitsWord
AP4_BitStream::ReadCache() const
{
unsigned int pos = m_Out;
AP4_BitsWord cache;
#if AP4_WORD_BITS != 32
#error unsupported word size
#endif
if (pos <= AP4_BITSTREAM_BUFFER_SIZE - AP4_WORD_BYTES) {
unsigned char* out_ptr = &m_Buffer[pos];
cache = (((AP4_BitsWord) out_ptr[0]) << 24)
| (((AP4_BitsWord) out_ptr[1]) << 16)
| (((AP4_BitsWord) out_ptr[2]) << 8)
| (((AP4_BitsWord) out_ptr[3]) );
} else {
unsigned char* buf_ptr = m_Buffer;
cache = (((AP4_BitsWord) buf_ptr[ pos ]) << 24)
| (((AP4_BitsWord) buf_ptr[AP4_BITSTREAM_POINTER_OFFSET (pos, 1)]) << 16)
| (((AP4_BitsWord) buf_ptr[AP4_BITSTREAM_POINTER_OFFSET (pos, 2)]) << 8)
| (((AP4_BitsWord) buf_ptr[AP4_BITSTREAM_POINTER_OFFSET (pos, 3)]) );
}
return cache;
}
inline AP4_UI32
AP4_BitStream::ReadBits(unsigned int n)
{
AP4_BitsWord result;
if (m_BitsCached >= n) {
m_BitsCached -= n;
result = (m_Cache >> m_BitsCached) & AP4_BIT_MASK(n);
} else {
AP4_BitsWord word;
{
word = ReadCache();
m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES);
}
{
AP4_BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached);
n -= m_BitsCached;
m_BitsCached = AP4_WORD_BITS - n;
result = (word >> m_BitsCached) | (cache << n);
m_Cache = word;
}
}
return result;
}
inline int
AP4_BitStream::ReadBit()
{
AP4_BitsWord result;
if (m_BitsCached == 0) {
m_Cache = ReadCache();
m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES);
m_BitsCached = AP4_WORD_BITS - 1;
result = m_Cache >> (AP4_WORD_BITS - 1);
} else {
result = (m_Cache >> (--m_BitsCached)) & 1;
}
return result;
}
inline AP4_UI32
AP4_BitStream::PeekBits(unsigned int n)
{
if (m_BitsCached >= n) {
return (m_Cache >> (m_BitsCached - n)) & AP4_BIT_MASK(n);
} else {
AP4_BitsWord word = ReadCache();
AP4_BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached);
n -= m_BitsCached;
return (word >> (AP4_WORD_BITS - n)) | (cache << n);
}
}
inline int
AP4_BitStream::PeekBit()
{
if (m_BitsCached == 0) {
AP4_BitsWord cache = ReadCache();
return cache >> (AP4_WORD_BITS - 1);
} else {
return (m_Cache >> (m_BitsCached-1)) & 1;
}
}
inline void
AP4_BitStream::SkipBits(unsigned int n)
{
if (n <= m_BitsCached) {
m_BitsCached -= n;
} else {
n -= m_BitsCached;
while (n >= AP4_WORD_BITS) {
m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES);
n -= AP4_WORD_BITS;
}
if (n) {
m_Cache = ReadCache();
m_BitsCached = AP4_WORD_BITS-n;
m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES);
} else {
m_BitsCached = 0;
m_Cache = 0;
}
}
}
inline void
AP4_BitStream::SkipBit()
{
if (m_BitsCached == 0) {
m_Cache = ReadCache();
m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES);
m_BitsCached = AP4_WORD_BITS - 1;
} else {
--m_BitsCached;
}
}
inline AP4_UI08
AP4_BitStream::PeekByte()
{
unsigned int extra_bits = m_BitsCached & 7;
return (AP4_UI08)(PeekBits(extra_bits + 8)&0xFF);
}
#endif