2012-06-04 10:47:12 +00:00
|
|
|
/**
|
2013-09-18 14:29:30 +00:00
|
|
|
* \file
|
|
|
|
*
|
|
|
|
* \author Marko Viitanen ( fador@iki.fi ),
|
|
|
|
* Tampere University of Technology,
|
|
|
|
* Department of Pervasive Computing.
|
|
|
|
* \author Ari Koivula ( ari@koivu.la ),
|
|
|
|
* Tampere University of Technology,
|
|
|
|
* Department of Pervasive Computing.
|
2012-06-04 10:47:12 +00:00
|
|
|
*/
|
|
|
|
|
2013-09-18 09:16:03 +00:00
|
|
|
#include "bitstream.h"
|
|
|
|
|
2012-05-30 12:37:42 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
2013-09-18 12:45:46 +00:00
|
|
|
//for hton
|
2013-09-23 14:32:07 +00:00
|
|
|
#ifdef _WIN32
|
2012-06-06 08:59:02 +00:00
|
|
|
#include <Winsock2.h>
|
|
|
|
#else
|
|
|
|
#include <net/hton.h>
|
|
|
|
#endif
|
2012-05-30 12:37:42 +00:00
|
|
|
|
2012-06-05 14:45:17 +00:00
|
|
|
|
|
|
|
//#define VERBOSE
|
|
|
|
|
2012-06-01 12:31:06 +00:00
|
|
|
#ifdef VERBOSE
|
2012-05-30 12:37:42 +00:00
|
|
|
void printf_bitstream(char *msg, ...)
|
2012-06-01 12:31:06 +00:00
|
|
|
{
|
|
|
|
va_list fmtargs;
|
|
|
|
char buffer[1024];
|
2012-05-30 12:37:42 +00:00
|
|
|
va_start(fmtargs,msg);
|
|
|
|
vsnprintf(buffer,sizeof(buffer)-1,msg,fmtargs);
|
|
|
|
va_end(fmtargs);
|
2013-09-18 12:45:46 +00:00
|
|
|
printf("%s",buffer);
|
2012-06-01 12:31:06 +00:00
|
|
|
}
|
|
|
|
#endif
|
2012-06-05 11:01:47 +00:00
|
|
|
|
2013-09-18 09:42:16 +00:00
|
|
|
bit_table *g_exp_table;
|
2012-06-05 11:01:47 +00:00
|
|
|
|
|
|
|
//From wikipedia
|
|
|
|
//http://en.wikipedia.org/wiki/Binary_logarithm#Algorithm
|
2013-09-18 09:42:16 +00:00
|
|
|
int floor_log2(unsigned int n) {
|
2012-06-05 11:01:47 +00:00
|
|
|
int pos = 0;
|
|
|
|
if (n >= 1<<16) { n >>= 16; pos += 16; }
|
|
|
|
if (n >= 1<< 8) { n >>= 8; pos += 8; }
|
|
|
|
if (n >= 1<< 4) { n >>= 4; pos += 4; }
|
|
|
|
if (n >= 1<< 2) { n >>= 2; pos += 2; }
|
|
|
|
if (n >= 1<< 1) { pos += 1; }
|
|
|
|
return ((n == 0) ? (-1) : pos);
|
|
|
|
}
|
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
/**
|
|
|
|
* \brief Initialize the Exp Golomb code table with desired number of values
|
|
|
|
* \param len table length to init
|
|
|
|
*
|
|
|
|
* Allocates g_exp_table with len*sizeof(bit_table) and fills it with exponential golomb codes
|
|
|
|
*/
|
2012-06-05 11:01:47 +00:00
|
|
|
void init_exp_golomb(uint32_t len)
|
|
|
|
{
|
2013-09-18 12:45:46 +00:00
|
|
|
uint32_t code_num;
|
|
|
|
uint32_t M;
|
|
|
|
uint32_t info;
|
|
|
|
g_exp_table = (bit_table*)malloc(len*sizeof(bit_table));
|
|
|
|
|
|
|
|
for (code_num = 0; code_num < len; code_num++) {
|
|
|
|
M = (uint32_t)floor_log2(code_num + 1);
|
|
|
|
info = code_num + 1 - (uint32_t)pow(2, M);
|
|
|
|
g_exp_table[code_num].len = M * 2 + 1;
|
|
|
|
g_exp_table[code_num].value = (1<<M) | info;
|
|
|
|
}
|
2012-06-05 11:01:47 +00:00
|
|
|
}
|
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
/**
|
|
|
|
* \brief Clear bitstream
|
2012-05-30 12:37:42 +00:00
|
|
|
*/
|
2013-09-18 12:45:46 +00:00
|
|
|
void bitstream_init(bitstream *stream)
|
2012-05-30 12:37:42 +00:00
|
|
|
{
|
2013-09-18 12:45:46 +00:00
|
|
|
stream->cur_byte = 0;
|
|
|
|
stream->cur_bit = 0;
|
|
|
|
memset(stream->data, 0, sizeof(uint32_t)*32);
|
2012-05-30 12:37:42 +00:00
|
|
|
}
|
2012-06-05 11:01:47 +00:00
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
/**
|
|
|
|
* \brief Allocate buffer
|
|
|
|
* \param stream pointer bitstream to put the data
|
|
|
|
* \param alloc size to allocate
|
2012-06-05 11:01:47 +00:00
|
|
|
*/
|
2013-09-18 12:45:46 +00:00
|
|
|
void bitstream_alloc(bitstream *stream, uint32_t alloc)
|
2012-06-05 11:01:47 +00:00
|
|
|
{
|
|
|
|
stream->buffer = (uint8_t*)malloc(alloc);
|
2012-06-06 10:42:02 +00:00
|
|
|
stream->bufferlen = alloc;
|
2012-06-05 11:01:47 +00:00
|
|
|
//Clear just to be sure
|
2012-06-06 10:42:02 +00:00
|
|
|
bitstream_clear_buffer(stream);
|
|
|
|
}
|
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
/**
|
|
|
|
* \brief clear output buffer
|
|
|
|
*/
|
|
|
|
void bitstream_clear_buffer(bitstream *stream)
|
2012-06-06 10:42:02 +00:00
|
|
|
{
|
2013-09-18 12:45:46 +00:00
|
|
|
memset(stream->buffer, 0, stream->bufferlen);
|
2012-06-05 11:01:47 +00:00
|
|
|
stream->buffer_pos = 0;
|
2013-09-18 12:45:46 +00:00
|
|
|
}
|
2012-05-30 12:37:42 +00:00
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
/**
|
|
|
|
* \brief Put bits to bitstream
|
|
|
|
* \param stream pointer bitstream to put the data
|
|
|
|
* \param data input data
|
|
|
|
* \param bits number of bits to write from data to stream
|
|
|
|
*/
|
|
|
|
void bitstream_put(bitstream *stream, uint32_t data, uint8_t bits)
|
2012-05-30 12:37:42 +00:00
|
|
|
{
|
2013-09-18 12:45:46 +00:00
|
|
|
uint32_t bitsleft = 32 - stream->cur_bit;
|
2012-06-05 14:45:17 +00:00
|
|
|
#ifdef VERBOSE
|
|
|
|
uint8_t i=0;
|
|
|
|
printf_bitstream("put: ");
|
2013-09-18 12:45:46 +00:00
|
|
|
for (i = 0; i < bits; i++) {
|
2012-06-05 14:45:17 +00:00
|
|
|
printf("%i",(data&(1<<(bits-i-1)))?1:0);
|
|
|
|
}
|
|
|
|
printf_bitstream("\n");
|
|
|
|
//printf_bitstream(" count: %i\n",bits);
|
|
|
|
#endif
|
2012-05-30 12:37:42 +00:00
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
//There's space for all the bits
|
|
|
|
if (bits <= bitsleft) {
|
2012-06-05 14:45:17 +00:00
|
|
|
stream->data[stream->cur_byte] |= (data<<((bitsleft-bits)));
|
2013-09-18 12:45:46 +00:00
|
|
|
stream->cur_bit += bits;
|
|
|
|
bits = 0;
|
|
|
|
} else { //No space for everything, store the bits we can and continue later
|
2012-06-05 14:45:17 +00:00
|
|
|
stream->data[stream->cur_byte] |= (data>>(bits-bitsleft));
|
2013-09-18 12:45:46 +00:00
|
|
|
stream->cur_bit = 32;
|
|
|
|
bits -= bitsleft;
|
2012-06-05 14:45:17 +00:00
|
|
|
}
|
2012-05-30 12:37:42 +00:00
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
//Check if the buffer is full, and flush to output if it is
|
|
|
|
if (stream->cur_bit == 32) {
|
|
|
|
bitsleft = 32;
|
2012-06-05 14:45:17 +00:00
|
|
|
stream->cur_byte++;
|
|
|
|
stream->cur_bit = 0;
|
2013-09-18 12:45:46 +00:00
|
|
|
if (stream->cur_byte == 32) {
|
|
|
|
//Flush data out
|
|
|
|
bitstream_flush(stream);
|
2012-05-30 12:37:42 +00:00
|
|
|
}
|
2012-06-05 14:45:17 +00:00
|
|
|
}
|
2012-05-30 12:37:42 +00:00
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
//Write the last of the bits (if buffer was full and flushed before)
|
|
|
|
if (bits != 0) {
|
2012-06-05 14:45:17 +00:00
|
|
|
stream->data[stream->cur_byte] |= (data<<(bitsleft-bits));
|
2013-09-18 12:45:46 +00:00
|
|
|
stream->cur_bit += bits;
|
2012-06-06 10:42:02 +00:00
|
|
|
}
|
2012-05-30 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
/**
|
|
|
|
* \brief Align the bitstream with one-bit padding
|
|
|
|
*/
|
|
|
|
void bitstream_align(bitstream *stream)
|
2013-02-21 14:45:22 +00:00
|
|
|
{
|
2013-09-18 12:45:46 +00:00
|
|
|
bitstream_put(stream, 1, 1);
|
|
|
|
if ((stream->cur_bit & 7) != 0) {
|
|
|
|
bitstream_put(stream, 0, 8 - (stream->cur_bit & 7));
|
2013-02-21 14:45:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
/**
|
|
|
|
* \brief Align the bitstream with zero
|
|
|
|
*/
|
|
|
|
void bitstream_align_zero(bitstream *stream)
|
2013-05-16 12:27:54 +00:00
|
|
|
{
|
2013-09-18 12:45:46 +00:00
|
|
|
if ((stream->cur_bit & 7) != 0) {
|
|
|
|
bitstream_put(stream, 0, 8 - (stream->cur_bit & 7));
|
2012-06-05 11:01:47 +00:00
|
|
|
}
|
2012-05-30 12:37:42 +00:00
|
|
|
}
|
2013-09-18 12:45:46 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Flush bitstream to output
|
|
|
|
*/
|
|
|
|
void bitstream_flush(bitstream *stream)
|
2012-05-30 12:37:42 +00:00
|
|
|
{
|
2012-06-08 12:26:07 +00:00
|
|
|
int i;
|
2012-06-06 08:59:02 +00:00
|
|
|
uint32_t correct_endian;
|
2013-09-18 12:45:46 +00:00
|
|
|
//If output open, write to output
|
|
|
|
if (stream->output) {
|
|
|
|
if (stream->cur_byte) fwrite(&stream->data[0], stream->cur_byte * 4, 1, stream->output);
|
|
|
|
if (stream->cur_bit>>3) fwrite(&stream->data[stream->cur_byte], stream->cur_bit>>3, 1, stream->output);
|
|
|
|
|
|
|
|
} else { //No file open, write to buffer
|
|
|
|
if (stream->cur_byte) {
|
|
|
|
//Handle endianness issue
|
|
|
|
for (i = 0; i < stream->cur_byte; i++) {
|
|
|
|
//"network" is big-endian
|
2012-06-06 08:59:02 +00:00
|
|
|
correct_endian = htonl(stream->data[i]);
|
2013-09-18 12:45:46 +00:00
|
|
|
memcpy((uint8_t*)&stream->buffer[stream->buffer_pos], &correct_endian, 4);
|
2012-06-06 08:59:02 +00:00
|
|
|
stream->buffer_pos += 4;
|
2012-06-05 14:45:17 +00:00
|
|
|
}
|
2012-06-05 11:01:47 +00:00
|
|
|
}
|
|
|
|
|
2013-09-18 12:45:46 +00:00
|
|
|
if (stream->cur_bit>>3) {
|
2012-06-06 08:59:02 +00:00
|
|
|
correct_endian = htonl(stream->data[stream->cur_byte]);
|
2013-09-18 12:45:46 +00:00
|
|
|
memcpy((uint8_t*)&stream->buffer[stream->buffer_pos], &correct_endian, stream->cur_bit>>3);
|
2012-06-05 14:45:17 +00:00
|
|
|
stream->buffer_pos += stream->cur_bit>>3;
|
2012-06-06 08:59:02 +00:00
|
|
|
}
|
2012-06-05 11:01:47 +00:00
|
|
|
}
|
2012-06-06 08:59:02 +00:00
|
|
|
//Stream flushed, zero out the values
|
|
|
|
bitstream_init(stream);
|
2012-05-30 12:37:42 +00:00
|
|
|
}
|
2012-06-05 11:01:47 +00:00
|
|
|
|