This source file includes following definitions.
- gf_bs_new
 
- gf_bs_from_file
 
- bs_flush_cache
 
- gf_bs_set_output_buffering
 
- gf_bs_get_output_buffering
 
- gf_bs_del
 
- BS_IsAlign
 
- BS_ReadByte
 
- gf_bs_read_bit
 
- gf_bs_read_int
 
- gf_bs_read_u8
 
- gf_bs_read_u8_until_delimiter
 
- gf_bs_read_u16
 
- gf_bs_read_u24
 
- gf_bs_read_u32
 
- gf_bs_read_u64
 
- gf_bs_read_long_int
 
- gf_bs_read_float
 
- gf_bs_read_double
 
- gf_bs_read_data
 
- BS_WriteByte
 
- BS_WriteBit
 
- gf_bs_write_int
 
- gf_bs_write_long_int
 
- gf_bs_write_u8
 
- gf_bs_write_u16
 
- gf_bs_write_u24
 
- gf_bs_write_u32
 
- gf_bs_write_u64
 
- gf_bs_write_byte
 
- gf_bs_write_float
 
- gf_bs_write_double
 
- gf_bs_write_data
 
- gf_bs_align
 
- gf_bs_available
 
- BS_CutBuffer
 
- gf_bs_get_content
 
- gf_bs_skip_bytes
 
- gf_bs_rewind_bits
 
- BS_SeekIntern
 
- gf_bs_seek
 
- gf_bs_peek_bits
 
- gf_bs_get_refreshed_size
 
- gf_bs_get_size
 
- gf_bs_get_position
 
- gf_bs_bits_available
 
- gf_bs_set_eos_callback
 
- gf_bs_read_u32_le
 
- gf_bs_read_u16_le
 
- gf_bs_write_u32_le
 
- gf_bs_write_u16_le
 
- gf_bs_get_bit_offset
 
- gf_bs_get_bit_position
 
- gf_bs_read_vluimsbf5
 
- gf_bs_truncate
 
- gf_bs_transfer
 
- gf_bs_flush
 
- gf_bs_reassign
 
#include <gpac/bitstream.h>
#define BS_MEM_BLOCK_ALLOC_SIZE         4096
enum
{
        GF_BITSTREAM_FILE_READ = GF_BITSTREAM_WRITE + 1,
        GF_BITSTREAM_FILE_WRITE,
        
        GF_BITSTREAM_WRITE_DYN
};
struct __tag_bitstream
{
        
        FILE *stream;
        
        char *original;
        
        u64 size;
        
        u64 position;
        
        u32 current;
        
        u32 nbBits;
        
        u32 bsmode;
        void (*EndOfStream)(void *par);
        void *par;
        char *buffer_io;
        u32 buffer_io_size, buffer_written;
};
GF_EXPORT
GF_BitStream *gf_bs_new(const char *buffer, u64 BufferSize, u32 mode)
{
        GF_BitStream *tmp;
        if ( (buffer && ! BufferSize)) return NULL;
        tmp = (GF_BitStream *)gf_malloc(sizeof(GF_BitStream));
        if (!tmp) return NULL;
        memset(tmp, 0, sizeof(GF_BitStream));
        tmp->original = (char*)buffer;
        tmp->size = BufferSize;
        tmp->position = 0;
        tmp->current = 0;
        tmp->bsmode = mode;
        tmp->stream = NULL;
        switch (tmp->bsmode) {
        case GF_BITSTREAM_READ:
                tmp->nbBits = 8;
                tmp->current = 0;
                break;
        case GF_BITSTREAM_WRITE:
                tmp->nbBits = 0;
                if (! buffer) {
                        
                        if (BufferSize) {
                                tmp->size = BufferSize;
                        } else {
                                tmp->size = BS_MEM_BLOCK_ALLOC_SIZE;
                        }
                        tmp->original = (char *) gf_malloc(sizeof(char) * ((u32) tmp->size));
                        if (! tmp->original) {
                                gf_free(tmp);
                                return NULL;
                        }
                        tmp->bsmode = GF_BITSTREAM_WRITE_DYN;
                } else {
                        tmp->original = (char*)buffer;
                        tmp->size = BufferSize;
                }
                break;
        default:
                
                gf_free(tmp);
                return NULL;
        }
        return tmp;
}
GF_EXPORT
GF_BitStream *gf_bs_from_file(FILE *f, u32 mode)
{
        GF_BitStream *tmp;
        if (!f) return NULL;
        tmp = (GF_BitStream *)gf_malloc(sizeof(GF_BitStream));
        if (!tmp) return NULL;
        memset(tmp, 0, sizeof(GF_BitStream));
        
        mode = (mode==GF_BITSTREAM_READ) ? GF_BITSTREAM_FILE_READ : GF_BITSTREAM_FILE_WRITE;
        tmp->bsmode = mode;
        tmp->current = 0;
        tmp->nbBits = (mode == GF_BITSTREAM_FILE_READ) ? 8 : 0;
        tmp->original = NULL;
        tmp->position = 0;
        tmp->stream = f;
        
        tmp->position = gf_ftell(f);
        gf_fseek(f, 0, SEEK_END);
        tmp->size = gf_ftell(f);
        gf_fseek(f, tmp->position, SEEK_SET);
        return tmp;
}
static void bs_flush_cache(GF_BitStream *bs)
{
        if (bs->buffer_written) {
                u32 nb_write = (u32) fwrite(bs->buffer_io, 1, bs->buffer_written, bs->stream);
                bs->size += nb_write;
                bs->position += nb_write;
                bs->buffer_written = 0;
        }
}
GF_EXPORT
GF_Err gf_bs_set_output_buffering(GF_BitStream *bs, u32 size)
{
        if (!bs->stream) return GF_OK;
        if (bs->bsmode != GF_BITSTREAM_FILE_WRITE) {
                return GF_OK;
        }
        bs_flush_cache(bs);
        bs->buffer_io = (char*)gf_realloc(bs->buffer_io, size);
        if (!bs->buffer_io) return GF_IO_ERR;
        bs->buffer_io_size = size;
        bs->buffer_written = 0;
        return GF_OK;
}
GF_EXPORT
u32 gf_bs_get_output_buffering(GF_BitStream *bs)
{
        return bs ? bs->buffer_io_size : 0;
}
GF_EXPORT
void gf_bs_del(GF_BitStream *bs)
{
        if (!bs) return;
        
        if ((bs->bsmode == GF_BITSTREAM_WRITE_DYN) && bs->original) gf_free(bs->original);
        if (bs->buffer_io)
                bs_flush_cache(bs);
        gf_free(bs);
}
static Bool BS_IsAlign(GF_BitStream *bs)
{
        switch (bs->bsmode) {
        case GF_BITSTREAM_READ:
        case GF_BITSTREAM_FILE_READ:
                return ( (8 == bs->nbBits) ? GF_TRUE : GF_FALSE);
        default:
                return !bs->nbBits;
        }
}
static u8 BS_ReadByte(GF_BitStream *bs)
{
        if (bs->bsmode == GF_BITSTREAM_READ) {
                if (bs->position >= bs->size) {
                        if (bs->EndOfStream) bs->EndOfStream(bs->par);
                        return 0;
                }
                return (u32) bs->original[bs->position++];
        }
        if (bs->buffer_io)
                bs_flush_cache(bs);
        
        if (!feof(bs->stream)) {
                assert(bs->position<=bs->size);
                bs->position++;
                return (u32) fgetc(bs->stream);
        }
        if (bs->EndOfStream) bs->EndOfStream(bs->par);
        else {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[BS] Attempt to overread bitstream\n"));
        }
        assert(bs->position <= 1+bs->size);
        return 0;
}
#define NO_OPTS
#ifndef NO_OPTS
static u32 bit_mask[] = {0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
static u32 bits_mask[] = {0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F};
#endif
GF_EXPORT
u8 gf_bs_read_bit(GF_BitStream *bs)
{
        if (bs->nbBits == 8) {
                bs->current = BS_ReadByte(bs);
                bs->nbBits = 0;
        }
#ifdef NO_OPTS
        {
                s32 ret;
                bs->current <<= 1;
                bs->nbBits++;
                ret = (bs->current & 0x100) >> 8;
                return (u8) ret;
        }
#else
        return (u8) (bs->current & bit_mask[bs->nbBits++]) ? 1 : 0;
#endif
}
GF_EXPORT
u32 gf_bs_read_int(GF_BitStream *bs, u32 nBits)
{
        u32 ret;
#ifndef NO_OPTS
        if (nBits + bs->nbBits <= 8) {
                bs->nbBits += nBits;
                ret = (bs->current >> (8 - bs->nbBits) ) & bits_mask[nBits];
                return ret;
        }
#endif
        ret = 0;
        while (nBits-- > 0) {
                ret <<= 1;
                ret |= gf_bs_read_bit(bs);
        }
        return ret;
}
GF_EXPORT
u32 gf_bs_read_u8(GF_BitStream *bs)
{
        assert(bs->nbBits==8);
        return (u32) BS_ReadByte(bs);
}
GF_EXPORT
u32 gf_bs_read_u8_until_delimiter(GF_BitStream *bs, u8 delimiter, u8* out, u32 max_length) {
        u32 i = 0;
        char token=0;
        u64 cur_pos = gf_bs_get_position(bs);
        if (!max_length) out = NULL;
        while(gf_bs_available(bs) && (!max_length || i < max_length)) {
                gf_bs_read_data(bs, &token, 1);
                if (token == delimiter) goto found;
                if (out) out[i] = token;
                i++;
        }
        
        gf_bs_seek(bs, cur_pos);
        return 0;
found:
        return i;
}
GF_EXPORT
u32 gf_bs_read_u16(GF_BitStream *bs)
{
        u32 ret;
        assert(bs->nbBits==8);
        ret = BS_ReadByte(bs);
        ret<<=8;
        ret |= BS_ReadByte(bs);
        return ret;
}
GF_EXPORT
u32 gf_bs_read_u24(GF_BitStream *bs)
{
        u32 ret;
        assert(bs->nbBits==8);
        ret = BS_ReadByte(bs);
        ret<<=8;
        ret |= BS_ReadByte(bs);
        ret<<=8;
        ret |= BS_ReadByte(bs);
        return ret;
}
GF_EXPORT
u32 gf_bs_read_u32(GF_BitStream *bs)
{
        u32 ret;
        assert(bs->nbBits==8);
        ret = BS_ReadByte(bs);
        ret<<=8;
        ret |= BS_ReadByte(bs);
        ret<<=8;
        ret |= BS_ReadByte(bs);
        ret<<=8;
        ret |= BS_ReadByte(bs);
        return ret;
}
GF_EXPORT
u64 gf_bs_read_u64(GF_BitStream *bs)
{
        u64 ret;
        ret = gf_bs_read_u32(bs);
        ret<<=32;
        ret |= gf_bs_read_u32(bs);
        return ret;
}
GF_EXPORT
u64 gf_bs_read_long_int(GF_BitStream *bs, u32 nBits)
{
        u64 ret = 0;
        if (nBits>64) {
                gf_bs_read_long_int(bs, nBits-64);
                ret = gf_bs_read_long_int(bs, 64);
        } else {
                while (nBits-- > 0) {
                        ret <<= 1;
                        ret |= gf_bs_read_bit(bs);
                }
        }
        return ret;
}
GF_EXPORT
Float gf_bs_read_float(GF_BitStream *bs)
{
        char buf [4] = "\0\0\0";
#ifdef NO_OPTS
        s32 i;
        for (i = 0; i < 32; i++)
                buf[3-i/8] |= gf_bs_read_bit(bs) << (7 - i%8);
#else
        buf[3] = gf_bs_read_int(bs, 8);
        buf[2] = gf_bs_read_int(bs, 8);
        buf[1] = gf_bs_read_int(bs, 8);
        buf[0] = gf_bs_read_int(bs, 8);
#endif
        return (* (Float *) buf);
}
GF_EXPORT
Double gf_bs_read_double(GF_BitStream *bs)
{
        char buf [8] = "\0\0\0\0\0\0\0";
        s32 i;
        for (i = 0; i < 64; i++)
                buf[7-i/8] |= gf_bs_read_bit(bs) << (7 - i%8);
        return (* (Double *) buf);
}
GF_EXPORT
u32 gf_bs_read_data(GF_BitStream *bs, char *data, u32 nbBytes)
{
        u64 orig = bs->position;
        if (bs->position+nbBytes > bs->size) return 0;
        if (BS_IsAlign(bs)) {
                s32 bytes_read;
                switch (bs->bsmode) {
                case GF_BITSTREAM_READ:
                case GF_BITSTREAM_WRITE:
                case GF_BITSTREAM_WRITE_DYN:
                        memcpy(data, bs->original + bs->position, nbBytes);
                        bs->position += nbBytes;
                        return nbBytes;
                case GF_BITSTREAM_FILE_READ:
                case GF_BITSTREAM_FILE_WRITE:
                        if (bs->buffer_io)
                                bs_flush_cache(bs);
                        bytes_read = (s32) fread(data, 1, nbBytes, bs->stream);
                        if (bytes_read<0) return 0;
                        bs->position += bytes_read;
                        return bytes_read;
                default:
                        return 0;
                }
        }
        while (nbBytes-- > 0) {
                *data++ = gf_bs_read_int(bs, 8);
        }
        return (u32) (bs->position - orig);
}
static void BS_WriteByte(GF_BitStream *bs, u8 val)
{
        
        if ( (bs->bsmode == GF_BITSTREAM_READ) || (bs->bsmode == GF_BITSTREAM_FILE_READ) ) return;
        if (!bs->original && !bs->stream) return;
        
        if ( (bs->bsmode == GF_BITSTREAM_WRITE) || (bs->bsmode == GF_BITSTREAM_WRITE_DYN) ) {
                if (bs->position == bs->size) {
                        
                        if (bs->bsmode != GF_BITSTREAM_WRITE_DYN) return;
                        
                        if (bs->size > 0xFFFFFFFF) return;
                        bs->original = (char*)gf_realloc(bs->original, (u32) (bs->size * 2));
                        if (!bs->original) return;
                        bs->size *= 2;
                }
                if (bs->original)
                        bs->original[bs->position] = val;
                bs->position++;
                return;
        }
        if (bs->buffer_io) {
                if (bs->buffer_written == bs->buffer_io_size) {
                        bs_flush_cache(bs);
                }
                bs->buffer_io[bs->buffer_written] = val;
                bs->buffer_written++;
                if (bs->buffer_written == bs->buffer_io_size) {
                        bs_flush_cache(bs);
                }
                return;
        }
        
        fputc(val, bs->stream);
        
        if (bs->size == bs->position) bs->size++;
        bs->position += 1;
}
static void BS_WriteBit(GF_BitStream *bs, u32 bit)
{
        bs->current <<= 1;
        bs->current |= bit;
        if (++ bs->nbBits == 8) {
                bs->nbBits = 0;
                BS_WriteByte(bs, (u8) bs->current);
                bs->current = 0;
        }
}
GF_EXPORT
void gf_bs_write_int(GF_BitStream *bs, s32 value, s32 nBits)
{
        value <<= sizeof (s32) * 8 - nBits;
        while (--nBits >= 0) {
                BS_WriteBit (bs, value < 0);
                value <<= 1;
        }
}
GF_EXPORT
void gf_bs_write_long_int(GF_BitStream *bs, s64 value, s32 nBits)
{
        if (nBits>64) {
                gf_bs_write_int(bs, 0, nBits-64);
                gf_bs_write_long_int(bs, value, 64);
        } else {
                value <<= sizeof (s64) * 8 - nBits;
                while (--nBits >= 0) {
                        BS_WriteBit (bs, value < 0);
                        value <<= 1;
                }
        }
}
GF_EXPORT
void gf_bs_write_u8(GF_BitStream *bs, u32 value)
{
        assert(!bs->nbBits);
        BS_WriteByte(bs, (u8) value);
}
GF_EXPORT
void gf_bs_write_u16(GF_BitStream *bs, u32 value)
{
        assert(!bs->nbBits);
        BS_WriteByte(bs, (u8) ((value>>8)&0xff));
        BS_WriteByte(bs, (u8) ((value)&0xff));
}
GF_EXPORT
void gf_bs_write_u24(GF_BitStream *bs, u32 value)
{
        assert(!bs->nbBits);
        BS_WriteByte(bs, (u8) ((value>>16)&0xff));
        BS_WriteByte(bs, (u8) ((value>>8)&0xff));
        BS_WriteByte(bs, (u8) ((value)&0xff));
}
GF_EXPORT
void gf_bs_write_u32(GF_BitStream *bs, u32 value)
{
        assert(!bs->nbBits);
        BS_WriteByte(bs, (u8) ((value>>24)&0xff));
        BS_WriteByte(bs, (u8) ((value>>16)&0xff));
        BS_WriteByte(bs, (u8) ((value>>8)&0xff));
        BS_WriteByte(bs, (u8) ((value)&0xff));
}
GF_EXPORT
void gf_bs_write_u64(GF_BitStream *bs, u64 value)
{
        assert(!bs->nbBits);
        gf_bs_write_u32(bs, (u32) ((value>>32)&0xffffffff));
        gf_bs_write_u32(bs, (u32) (value&0xffffffff));
}
GF_EXPORT
u32 gf_bs_write_byte(GF_BitStream *bs, u8 byte, u32 repeat_count)
{
        if (!BS_IsAlign(bs) || bs->buffer_io) {
                u32 count = 0;
                while (count<repeat_count) {
                        gf_bs_write_int(bs, byte, 8);
                        count++;
                }
                return count;
        }
        switch (bs->bsmode) {
        case GF_BITSTREAM_WRITE:
                if (bs->position + repeat_count > bs->size)
                        return 0;
                memset(bs->original + bs->position, byte, repeat_count);
                bs->position += repeat_count;
                return repeat_count;
        case GF_BITSTREAM_WRITE_DYN:
                
                if (bs->position+repeat_count> bs->size) {
                        u32 new_size = (u32) (bs->size*2);
                        if (!new_size) new_size = BS_MEM_BLOCK_ALLOC_SIZE;
                        if (bs->size + repeat_count > 0xFFFFFFFF)
                                return 0;
                        while (new_size < (u32) ( bs->size + repeat_count))
                                new_size *= 2;
                        bs->original = (char*)gf_realloc(bs->original, sizeof(u32)*new_size);
                        if (!bs->original)
                                return 0;
                        bs->size = new_size;
                }
                memset(bs->original + bs->position, byte, repeat_count);
                bs->position += repeat_count;
                return repeat_count;
        case GF_BITSTREAM_FILE_READ:
        case GF_BITSTREAM_FILE_WRITE:
                if (gf_fwrite(&byte, 1, repeat_count, bs->stream) != repeat_count) return 0;
                if (bs->size == bs->position) bs->size += repeat_count;
                bs->position += repeat_count;
                return repeat_count;
        default:
                return 0;
        }
}
GF_EXPORT
void gf_bs_write_float(GF_BitStream *bs, Float value)
{
        u32 i;
        union
        {       float f;
                char sz [4];
        } float_value;
        float_value.f = value;
        for (i = 0; i < 32; i++)
                BS_WriteBit(bs, (float_value.sz [3 - i / 8] & 1 << (7 - i % 8)) != 0);
}
GF_EXPORT
void gf_bs_write_double (GF_BitStream *bs, Double value)
{
        u32 i;
        union
        {       Double d;
                char sz [8];
        } double_value;
        double_value.d = value;
        for (i = 0; i < 64; i++) {
                BS_WriteBit(bs, (double_value.sz [7 - i / 8] & 1 << (7 - i % 8)) != 0);
        }
}
GF_EXPORT
u32 gf_bs_write_data(GF_BitStream *bs, const char *data, u32 nbBytes)
{
        
        u64 begin = bs->position;
        if (!nbBytes) return 0;
        if (BS_IsAlign(bs)) {
                switch (bs->bsmode) {
                case GF_BITSTREAM_WRITE:
                        if (bs->position+nbBytes > bs->size)
                                return 0;
                        memcpy(bs->original + bs->position, data, nbBytes);
                        bs->position += nbBytes;
                        return nbBytes;
                case GF_BITSTREAM_WRITE_DYN:
                        
                        if (bs->position+nbBytes > bs->size) {
                                u32 new_size = (u32) (bs->size*2);
                                if (!new_size) new_size = BS_MEM_BLOCK_ALLOC_SIZE;
                                if (bs->size + nbBytes > 0xFFFFFFFF)
                                        return 0;
                                while (new_size < (u32) ( bs->size + nbBytes))
                                        new_size *= 2;
                                bs->original = (char*)gf_realloc(bs->original, sizeof(u32)*new_size);
                                if (!bs->original)
                                        return 0;
                                bs->size = new_size;
                        }
                        memcpy(bs->original + bs->position, data, nbBytes);
                        bs->position += nbBytes;
                        return nbBytes;
                case GF_BITSTREAM_FILE_READ:
                case GF_BITSTREAM_FILE_WRITE:
                        if (bs->buffer_io) {
                                if (bs->buffer_written + nbBytes > bs->buffer_io_size) {
                                        bs_flush_cache(bs);
                                        if (nbBytes>bs->buffer_io_size) {
                                                bs->buffer_io = (char*)gf_realloc(bs->buffer_io, 2*nbBytes);
                                                bs->buffer_io_size = 2*nbBytes;
                                        }
                                }
                                memcpy(bs->buffer_io+bs->buffer_written, data, nbBytes);
                                bs->buffer_written+=nbBytes;
                                return nbBytes;
                        }
                        if (gf_fwrite(data, nbBytes, 1, bs->stream) != 1) return 0;
                        if (bs->size == bs->position) bs->size += nbBytes;
                        bs->position += nbBytes;
                        return nbBytes;
                default:
                        return 0;
                }
        }
        while (nbBytes) {
                gf_bs_write_int(bs, (s32) *data, 8);
                data++;
                nbBytes--;
        }
        return (u32) (bs->position - begin);
}
GF_EXPORT
u8 gf_bs_align(GF_BitStream *bs)
{
        u8 res = 8 - bs->nbBits;
        if ( (bs->bsmode == GF_BITSTREAM_READ) || (bs->bsmode == GF_BITSTREAM_FILE_READ)) {
                if (res > 0) {
                        gf_bs_read_int(bs, res);
                }
                return res;
        }
        if (bs->nbBits > 0) {
                gf_bs_write_int (bs, 0, res);
                return res;
        }
        return 0;
}
GF_EXPORT
u64 gf_bs_available(GF_BitStream *bs)
{
        s64 cur, end;
        
        if ( (bs->bsmode == GF_BITSTREAM_WRITE)
                || (bs->bsmode == GF_BITSTREAM_WRITE_DYN)
           )
                return (u64) -1;
        
        if (bs->bsmode == GF_BITSTREAM_READ) {
                if (bs->size < bs->position)
                        return 0;
                else
                        return (bs->size - bs->position);
        }
        
        if (bs->bsmode==GF_BITSTREAM_FILE_READ) {
                if (bs->position>bs->size) return 0;
                return (bs->size - bs->position);
        }
        if (bs->buffer_io)
                bs_flush_cache(bs);
        cur = gf_ftell(bs->stream);
        gf_fseek(bs->stream, 0, SEEK_END);
        end = gf_ftell(bs->stream);
        gf_fseek(bs->stream, cur, SEEK_SET);
        return (u64) (end - cur);
}
static s32 BS_CutBuffer(GF_BitStream *bs)
{
        s32 nbBytes;
        if ( (bs->bsmode != GF_BITSTREAM_WRITE_DYN) && (bs->bsmode != GF_BITSTREAM_WRITE)) return (u32) -1;
        
        gf_bs_align(bs);
        nbBytes = (u32) (bs->size - bs->position);
        if (!nbBytes || (nbBytes == 0xFFFFFFFF) || (bs->position >= 0xFFFFFFFF)) return 0;
        
        
        bs->size = bs->position;
        return nbBytes;
}
GF_EXPORT
void gf_bs_get_content(GF_BitStream *bs, char **output, u32 *outSize)
{
        
        if (bs->bsmode != GF_BITSTREAM_WRITE_DYN) return;
        if (!bs->position && !bs->nbBits) {
                *output = NULL;
                *outSize = 0;
                gf_free(bs->original);
        } else {
                s32 copy = BS_CutBuffer(bs);
                if (copy < 0) {
                        *output = NULL;
                } else
                        *output = bs->original;
                *outSize = (u32) bs->size;
        }
        bs->original = NULL;
        bs->size = 0;
        bs->position = 0;
}
GF_EXPORT
void gf_bs_skip_bytes(GF_BitStream *bs, u64 nbBytes)
{
        if (!bs || !nbBytes) return;
        gf_bs_align(bs);
        
        if ((bs->bsmode == GF_BITSTREAM_FILE_WRITE) || (bs->bsmode == GF_BITSTREAM_FILE_READ)) {
                if (bs->buffer_io)
                        bs_flush_cache(bs);
                gf_fseek(bs->stream, nbBytes, SEEK_CUR);
                bs->position += nbBytes;
                return;
        }
        
        if (bs->bsmode == GF_BITSTREAM_READ) {
                bs->position += nbBytes;
                return;
        }
        
        while (nbBytes) {
                gf_bs_write_int(bs, 0, 8);
                nbBytes--;
        }
}
GF_EXPORT
void gf_bs_rewind_bits(GF_BitStream *bs, u64 nbBits)
{
        u64 nbBytes;
        if (bs->bsmode != GF_BITSTREAM_READ) return;
        nbBits -= (bs->nbBits);
        nbBytes = (nbBits+8)>>3;
        nbBits = nbBytes*8 - nbBits;
        gf_bs_align(bs);
        assert(bs->position >= nbBytes);
        bs->position -= nbBytes + 1;
        gf_bs_read_int(bs, (u32)nbBits);
        return;
}
static GF_Err BS_SeekIntern(GF_BitStream *bs, u64 offset)
{
        u32 i;
        
        if ((bs->bsmode == GF_BITSTREAM_READ) || (bs->bsmode == GF_BITSTREAM_WRITE) || (bs->bsmode == GF_BITSTREAM_WRITE_DYN)) {
                if (offset > 0xFFFFFFFF) return GF_IO_ERR;
                if (!bs->original) return GF_BAD_PARAM;
                
                if (offset >= bs->size) {
                        if ( (bs->bsmode == GF_BITSTREAM_READ) || (bs->bsmode == GF_BITSTREAM_WRITE) ) return GF_BAD_PARAM;
                        
                        bs->original = (char*)gf_realloc(bs->original, (u32) (offset + 1));
                        if (!bs->original)
                                return GF_OUT_OF_MEM;
                        for (i = 0; i < (u32) (offset + 1 - bs->size); i++) {
                                bs->original[bs->size + i] = 0;
                        }
                        bs->size = offset + 1;
                }
                bs->current = bs->original[offset];
                bs->position = offset;
                bs->nbBits = (bs->bsmode == GF_BITSTREAM_READ) ? 8 : 0;
                return GF_OK;
        }
        if (bs->buffer_io)
                bs_flush_cache(bs);
        gf_fseek(bs->stream, offset, SEEK_SET);
        bs->position = offset;
        bs->current = 0;
        
        bs->nbBits = (bs->bsmode == GF_BITSTREAM_FILE_READ) ? 8 : 0;
        return GF_OK;
}
GF_EXPORT
GF_Err gf_bs_seek(GF_BitStream *bs, u64 offset)
{
        
        if (offset > bs->size) return GF_BAD_PARAM;
        gf_bs_align(bs);
        return BS_SeekIntern(bs, offset);
}
GF_EXPORT
u32 gf_bs_peek_bits(GF_BitStream *bs, u32 numBits, u64 byte_offset)
{
        u64 curPos;
        u32 curBits, ret, current;
        if ( (bs->bsmode != GF_BITSTREAM_READ) && (bs->bsmode != GF_BITSTREAM_FILE_READ)) return 0;
        if (!numBits || (bs->size < bs->position + byte_offset)) return 0;
        
        curPos = bs->position;
        curBits = bs->nbBits;
        current = bs->current;
        if (byte_offset) gf_bs_seek(bs, bs->position + byte_offset);
        ret = gf_bs_read_int(bs, numBits);
        
        gf_bs_seek(bs, curPos);
        
        bs->nbBits = curBits;
        bs->current = current;
        return ret;
}
GF_EXPORT
u64 gf_bs_get_refreshed_size(GF_BitStream *bs)
{
        s64 offset;
        switch (bs->bsmode) {
        case GF_BITSTREAM_READ:
        case GF_BITSTREAM_WRITE:
                return bs->size;
        default:
                if (bs->buffer_io)
                        bs_flush_cache(bs);
                offset = gf_ftell(bs->stream);
                gf_fseek(bs->stream, 0, SEEK_END);
                bs->size = gf_ftell(bs->stream);
                gf_fseek(bs->stream, offset, SEEK_SET);
                return bs->size;
        }
}
GF_EXPORT
u64 gf_bs_get_size(GF_BitStream *bs)
{
        if (bs->buffer_io)
                return bs->size + bs->buffer_written;
        return bs->size;
}
GF_EXPORT
u64 gf_bs_get_position(GF_BitStream *bs)
{
        if (bs->buffer_io)
                return bs->position + bs->buffer_written;
        return bs->position;
}
GF_EXPORT
u8 gf_bs_bits_available(GF_BitStream *bs)
{
        if (bs->size > bs->position) return 8;
        if (bs->nbBits < 8) return (8-bs->nbBits);
        return 0;
}
GF_EXPORT
void gf_bs_set_eos_callback(GF_BitStream *bs, void (*EndOfStream)(void *par), void *par)
{
        bs->EndOfStream = EndOfStream;
        bs->par = par;
}
GF_EXPORT
u32 gf_bs_read_u32_le(GF_BitStream *bs)
{
        u32 ret, v;
        ret = gf_bs_read_int(bs, 8);
        v = gf_bs_read_int(bs, 8);
        v<<=8;
        ret |= v;
        v = gf_bs_read_int(bs, 8);
        v<<=16;
        ret |= v;
        v = gf_bs_read_int(bs, 8);
        v<<=24;
        ret |= v;
        return ret;
}
GF_EXPORT
u16 gf_bs_read_u16_le(GF_BitStream *bs)
{
        u32 ret, v;
        ret = gf_bs_read_int(bs, 8);
        v = gf_bs_read_int(bs, 8);
        v<<=8;
        ret |= v;
        return ret;
}
GF_EXPORT
void gf_bs_write_u32_le(GF_BitStream *bs, u32 val)
{
        gf_bs_write_int(bs, val & 0xFF, 8);
        gf_bs_write_int(bs, val>>8, 8);
        gf_bs_write_int(bs, val>>16, 8);
        gf_bs_write_int(bs, val>>24, 8);
}
GF_EXPORT
void gf_bs_write_u16_le(GF_BitStream *bs, u32 val)
{
        gf_bs_write_int(bs, val & 0xFF, 8);
        gf_bs_write_int(bs, val>>8, 8);
}
GF_EXPORT
u32 gf_bs_get_bit_offset(GF_BitStream *bs)
{
        if (bs->stream) return 0;
        if (bs->bsmode==GF_BITSTREAM_READ) return (u32) ( (bs->position - 1) * 8 + bs->nbBits);
        return (u32) ( (bs->position ) * 8 + bs->nbBits);
}
GF_EXPORT
u32 gf_bs_get_bit_position(GF_BitStream *bs)
{
        if (bs->stream) return 0;
        return bs->nbBits;
}
u32 gf_bs_read_vluimsbf5(GF_BitStream *bs)
{
        u32 nb_words = 0;
        while (gf_bs_read_int(bs, 1)) nb_words++;
        nb_words++;
        return gf_bs_read_int(bs, 4*nb_words);
}
GF_EXPORT
void gf_bs_truncate(GF_BitStream *bs)
{
        bs->size = bs->position;
        if (bs->stream) return;
}
GF_EXPORT
GF_Err gf_bs_transfer(GF_BitStream *dst, GF_BitStream *src)
{
        char *data;
        u32 data_len, written;
        data = NULL;
        data_len = 0;
        gf_bs_get_content(src, &data, &data_len);
        if (!data || !data_len)
        {
                if (data) {
                        gf_free(data);
                        return GF_IO_ERR;
                }
                return GF_OK;
        }
        written = gf_bs_write_data(dst, data, data_len);
        gf_free(data);
        if (written<data_len) return GF_IO_ERR;
        return GF_OK;
}
GF_EXPORT
void gf_bs_flush(GF_BitStream *bs)
{
        if (bs->buffer_io)
                bs_flush_cache(bs);
        if (!bs->stream) return;
        if (bs->bsmode != GF_BITSTREAM_FILE_WRITE) return;
        fflush(bs->stream);
}
void gf_bs_reassign(GF_BitStream *bs, FILE *stream)
{
        if (!bs) return;
        switch (bs->bsmode) {
        case GF_BITSTREAM_FILE_WRITE:
        case GF_BITSTREAM_FILE_READ:
                bs->stream = stream;
                if (gf_ftell(stream) != bs->position)
                        gf_bs_seek(bs, bs->position);
                break;
        }
}