202 lines
4.6 KiB
C
202 lines
4.6 KiB
C
#ifndef _mpeg4_bits_h_
|
|
#define _mpeg4_bits_h_
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <assert.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
struct mpeg4_bits_t
|
|
{
|
|
uint8_t* data;
|
|
size_t size;
|
|
size_t bits; // offset bit
|
|
int error;
|
|
};
|
|
|
|
#define mpeg4_bits_read_uint8(bits, n) (uint8_t)mpeg4_bits_read_n(bits, n)
|
|
#define mpeg4_bits_read_uint16(bits, n) (uint16_t)mpeg4_bits_read_n(bits, n)
|
|
#define mpeg4_bits_read_uint32(bits, n) (uint32_t)mpeg4_bits_read_n(bits, n)
|
|
#define mpeg4_bits_read_uint64(bits, n) (uint64_t)mpeg4_bits_read_n(bits, n)
|
|
#define mpeg4_bits_write_uint8(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
|
#define mpeg4_bits_write_uint16(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
|
#define mpeg4_bits_write_uint32(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
|
#define mpeg4_bits_write_uint64(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
|
|
|
static inline void mpeg4_bits_init(struct mpeg4_bits_t* bits, void* data, size_t size)
|
|
{
|
|
bits->data = (uint8_t*)data;
|
|
bits->size = size;
|
|
bits->bits = 0;
|
|
bits->error = 0;
|
|
}
|
|
|
|
/// @return 1-error, 0-no error
|
|
static inline int mpeg4_bits_error(struct mpeg4_bits_t* bits)
|
|
{
|
|
//return bits->bits >= bits->size * 8 ? 1 : 0;
|
|
return bits->error;
|
|
}
|
|
|
|
static inline void mpeg4_bits_aligment(struct mpeg4_bits_t* bits, int n)
|
|
{
|
|
bits->bits = (bits->bits + n - 1) / n * n;
|
|
}
|
|
|
|
static inline size_t mpeg4_bits_remain(struct mpeg4_bits_t* bits)
|
|
{
|
|
return bits->error ? 0 : (bits->size * 8 - bits->bits);
|
|
}
|
|
|
|
static inline void mpeg4_bits_skip(struct mpeg4_bits_t* bits, size_t n)
|
|
{
|
|
bits->bits += n;
|
|
if (bits->bits > bits->size * 8)
|
|
{
|
|
bits->error = -1;
|
|
}
|
|
}
|
|
|
|
/// read 1-bit from bit stream(offset position)
|
|
/// @param[in] bits bit stream
|
|
/// @return -1-error, 1-value, 0-value
|
|
static inline int mpeg4_bits_read(struct mpeg4_bits_t* bits)
|
|
{
|
|
uint8_t bit;
|
|
assert(bits && bits->data && bits->size > 0);
|
|
if (bits->bits >= bits->size * 8)
|
|
{
|
|
bits->error = -1;
|
|
return 0; // throw exception
|
|
}
|
|
|
|
bit = bits->data[bits->bits/8] & (0x80U >> (bits->bits%8));
|
|
bits->bits += 1; // update offset
|
|
return bit ? 1 : 0;
|
|
}
|
|
|
|
/// read n-bit(n <= 64) from bit stream(offset position)
|
|
/// @param[in] bits bit stream
|
|
/// @return -1-error, other-value
|
|
static inline uint64_t mpeg4_bits_read_n(struct mpeg4_bits_t* bits, int n)
|
|
{
|
|
int m;
|
|
size_t i;
|
|
uint64_t v;
|
|
|
|
assert(n > 0 && n <= 64);
|
|
assert(bits && bits->data && bits->size > 0);
|
|
if (bits->bits + n > bits->size * 8 || n > 64 || n < 0)
|
|
{
|
|
bits->error = -1;
|
|
return 0; // throw exception
|
|
}
|
|
|
|
m = n;
|
|
v = bits->data[bits->bits / 8] & (0xFFU >> (bits->bits%8)); // remain valid value
|
|
if (n <= 8 - (int)(bits->bits % 8))
|
|
{
|
|
v = v >> (8 - (bits->bits % 8) - n); // shift right value
|
|
bits->bits += n;
|
|
return v;
|
|
}
|
|
|
|
n -= 8 - (int)(bits->bits % 8);
|
|
for (i = 1; n >= 8; i++)
|
|
{
|
|
assert(bits->bits / 8 + i < bits->size);
|
|
v <<= 8;
|
|
v += bits->data[bits->bits / 8 + i];
|
|
n -= 8;
|
|
}
|
|
|
|
if (n > 0)
|
|
{
|
|
v <<= n;
|
|
v += bits->data[bits->bits / 8 + i] >> (8 - n);
|
|
}
|
|
|
|
bits->bits += m;
|
|
return v;
|
|
}
|
|
|
|
// http://aomedia.org/av1/specification/conventions/#descriptors
|
|
static inline uint64_t mpeg4_bits_read_uvlc(struct mpeg4_bits_t* bits)
|
|
{
|
|
uint64_t value;
|
|
int leadingZeros;
|
|
for (leadingZeros = 0; !mpeg4_bits_read(bits); ++leadingZeros)
|
|
{
|
|
}
|
|
|
|
if (leadingZeros >= 32)
|
|
return (1ULL << 32) - 1;
|
|
|
|
value = mpeg4_bits_read_n(bits, leadingZeros);
|
|
return (1ULL << leadingZeros) - 1 + value;
|
|
}
|
|
|
|
static inline uint64_t mpeg4_bits_read_latm(struct mpeg4_bits_t* bits)
|
|
{
|
|
int len;
|
|
len = (int)mpeg4_bits_read_n(bits, 2);
|
|
return mpeg4_bits_read_n(bits, (len + 1) * 8);
|
|
}
|
|
|
|
/// write 1-bit
|
|
/// @param[in] v write 0 if v value 0, other, write 1
|
|
static inline int mpeg4_bits_write(struct mpeg4_bits_t* bits, int v)
|
|
{
|
|
assert(bits && bits->data && bits->size > 0);
|
|
if (bits->bits >= bits->size * 8)
|
|
{
|
|
bits->error = -1;
|
|
return -1; // throw exception
|
|
}
|
|
|
|
if(v)
|
|
bits->data[bits->bits / 8] |= (0x80U >> (bits->bits % 8));
|
|
bits->bits += 1; // update offset
|
|
return 0;
|
|
}
|
|
|
|
static inline int mpeg4_bits_write_n(struct mpeg4_bits_t* bits, uint64_t v, int n)
|
|
{
|
|
int m;
|
|
size_t i;
|
|
|
|
assert(n > 0 && n <= 64);
|
|
assert(bits && bits->data && bits->size > 0);
|
|
if (bits->bits + n > bits->size * 8 || n > 64 || n < 0)
|
|
{
|
|
bits->error = -1;
|
|
return -1; // throw exception
|
|
}
|
|
|
|
m = n;
|
|
v = v << (64 - n); // left shift to first bit
|
|
|
|
bits->data[bits->bits / 8] |= v >> (56 + (bits->bits % 8)); // remain valid value
|
|
v <<= 8 - (bits->bits % 8);
|
|
n -= 8 - (int)(bits->bits % 8);
|
|
|
|
for (i = 1; n > 0; i++)
|
|
{
|
|
assert(bits->bits / 8 + i < bits->size);
|
|
bits->data[bits->bits / 8 + i] = (uint8_t)(v >> 56);
|
|
v <<= 8;
|
|
n -= 8;
|
|
}
|
|
|
|
bits->bits += m;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* !_mpeg4_bits_h_ */
|