vlc_bits.h 8.21 KB
Newer Older
1
/*****************************************************************************
Pere Orga's avatar
Pere Orga committed
2
 * vlc_bits.h : Bit handling helpers
3
 *****************************************************************************
4
 * Copyright (C) 2001, 2002, 2003, 2006, 2015 VLC authors and VideoLAN
5
 * $Id$
6 7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 9
 *          Gildas Bazin <gbazin at videolan dot org>
 *          Rafaël Carré <funman at videolan dot org>
10
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
11 12 13
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
14 15 16 17
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
20
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
21 22 23
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 25
 *****************************************************************************/

26 27
#ifndef VLC_BITS_H
#define VLC_BITS_H 1
28

29
#include <vlc_common.h>
30 31
#include <vlc_block.h>

32 33 34 35 36
/**
 * \file
 * This file defines functions, structures for handling streams of bits in vlc
 */

37 38 39 40 41 42
typedef struct bo_t
{
    block_t     *b;
    size_t      basesize;
} bo_t;

43 44 45 46 47 48
typedef struct bs_s
{
    uint8_t *p_start;
    uint8_t *p;
    uint8_t *p_end;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
49
    ssize_t  i_left;    /* i_count number of available bits */
50
} bs_t;
51

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
52
static inline void bs_init( bs_t *s, const void *p_data, size_t i_data )
53
{
54
    s->p_start = (uint8_t *)p_data;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
55 56
    s->p       = s->p_start;
    s->p_end   = s->p_start + i_data;
57 58
    s->i_left  = 8;
}
59

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
60
static inline int bs_pos( const bs_t *s )
61 62 63
{
    return( 8 * ( s->p - s->p_start ) + 8 - s->i_left );
}
64

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
65
static inline int bs_eof( const bs_t *s )
66 67 68
{
    return( s->p >= s->p_end ? 1: 0 );
}
69

70 71
static inline uint32_t bs_read( bs_t *s, int i_count )
{
72
     static const uint32_t i_mask[33] =
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
     {  0x00,
        0x01,      0x03,      0x07,      0x0f,
        0x1f,      0x3f,      0x7f,      0xff,
        0x1ff,     0x3ff,     0x7ff,     0xfff,
        0x1fff,    0x3fff,    0x7fff,    0xffff,
        0x1ffff,   0x3ffff,   0x7ffff,   0xfffff,
        0x1fffff,  0x3fffff,  0x7fffff,  0xffffff,
        0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
        0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
    int      i_shr;
    uint32_t i_result = 0;

    while( i_count > 0 )
    {
        if( s->p >= s->p_end )
        {
            break;
        }

        if( ( i_shr = s->i_left - i_count ) >= 0 )
        {
            /* more in the buffer than requested */
            i_result |= ( *s->p >> i_shr )&i_mask[i_count];
            s->i_left -= i_count;
            if( s->i_left == 0 )
            {
                s->p++;
                s->i_left = 8;
            }
            return( i_result );
        }
        else
        {
            /* less in the buffer than requested */
           i_result |= (*s->p&i_mask[s->i_left]) << -i_shr;
           i_count  -= s->i_left;
           s->p++;
           s->i_left = 8;
        }
    }

    return( i_result );
}

static inline uint32_t bs_read1( bs_t *s )
{
    if( s->p < s->p_end )
    {
        unsigned int i_result;

        s->i_left--;
        i_result = ( *s->p >> s->i_left )&0x01;
        if( s->i_left == 0 )
        {
            s->p++;
            s->i_left = 8;
        }
        return i_result;
    }

    return 0;
}

static inline uint32_t bs_show( bs_t *s, int i_count )
{
    bs_t     s_tmp = *s;
    return bs_read( &s_tmp, i_count );
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
142
static inline void bs_skip( bs_t *s, ssize_t i_count )
143 144 145
{
    s->i_left -= i_count;

Laurent Aimar's avatar
Laurent Aimar committed
146
    if( s->i_left <= 0 )
147
    {
Laurent Aimar's avatar
Laurent Aimar committed
148 149 150 151
        const int i_bytes = ( -s->i_left + 8 ) / 8;

        s->p += i_bytes;
        s->i_left += 8 * i_bytes;
152 153 154
    }
}

155
static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
156 157 158 159
{
    while( i_count > 0 )
    {
        if( s->p >= s->p_end )
160
        {
161
            break;
162
        }
163 164 165 166

        i_count--;

        if( ( i_bits >> i_count )&0x01 )
167
        {
168
            *s->p |= 1 << ( s->i_left - 1 );
169
        }
170
        else
171
        {
172
            *s->p &= ~( 1 << ( s->i_left - 1 ) );
173
        }
174 175 176 177 178 179 180 181 182
        s->i_left--;
        if( s->i_left == 0 )
        {
            s->p++;
            s->i_left = 8;
        }
    }
}

183
static inline void bs_align( bs_t *s )
184 185 186 187 188 189 190
{
    if( s->i_left != 8 )
    {
        s->i_left = 8;
        s->p++;
    }
}
191

192
static inline void bs_align_0( bs_t *s )
193 194
{
    if( s->i_left != 8 )
195 196 197
    {
        bs_write( s, s->i_left, 0 );
    }
198
}
199

200
static inline void bs_align_1( bs_t *s )
201 202
{
    while( s->i_left != 8 )
203 204 205
    {
        bs_write( s, 1, 1 );
    }
206 207
}

208
static inline bool bo_init(bo_t *p_bo, int i_size)
209 210
{
    p_bo->b = block_Alloc(i_size);
Felix Paul Kühne's avatar
Felix Paul Kühne committed
211
    if (p_bo->b == NULL)
212
        return false;
213

214
    p_bo->b->i_buffer = 0;
215
    p_bo->basesize = i_size;
216

217
    return true;
218 219
}

Thomas Guillem's avatar
Thomas Guillem committed
220 221 222 223 224 225
static inline void bo_deinit(bo_t *p_bo)
{
    if(p_bo->b)
        block_Release(p_bo->b);
}

226
static inline void bo_free(bo_t *p_bo)
227
{
228 229
    if(!p_bo)
        return;
Thomas Guillem's avatar
Thomas Guillem committed
230
    bo_deinit(p_bo);
231 232 233 234 235 236 237 238 239
    free(p_bo);
}

static inline int bo_extend(bo_t *p_bo, size_t i_total)
{
    if(!p_bo->b)
        return false;
    const size_t i_size = p_bo->b->i_size - (p_bo->b->p_buffer - p_bo->b->p_start);
    if (i_total >= i_size)
240 241
    {
        int i_growth = p_bo->basesize;
242
        while(i_total >= i_size + i_growth)
243 244 245
            i_growth += p_bo->basesize;

        int i = p_bo->b->i_buffer; /* Realloc would set payload size == buffer size */
246
        p_bo->b = block_Realloc(p_bo->b, 0, i_size + i_growth);
247
        if (!p_bo->b)
248
            return false;
249 250
        p_bo->b->i_buffer = i;
    }
251
    return true;
252 253
}

254 255 256 257 258 259 260
#define BO_SET_DECL_S(func, handler, type) static inline bool func(bo_t *p_bo, size_t i_offset, type val)\
    {\
        if (!bo_extend(p_bo, i_offset + sizeof(type)))\
            return false;\
        handler(&p_bo->b->p_buffer[i_offset], val);\
        return true;\
    }
261

262 263 264 265 266 267 268
#define BO_ADD_DECL_S(func, handler, type) static inline bool func(bo_t *p_bo, type val)\
    {\
        if(!p_bo->b || !handler(p_bo, p_bo->b->i_buffer, val))\
            return false;\
        p_bo->b->i_buffer += sizeof(type);\
        return true;\
    }
269

270 271 272 273 274
#define BO_FUNC_DECL(suffix, handler, type ) \
    BO_SET_DECL_S( bo_set_ ## suffix ## be, handler ## BE, type )\
    BO_SET_DECL_S( bo_set_ ## suffix ## le, handler ## LE, type )\
    BO_ADD_DECL_S( bo_add_ ## suffix ## be, bo_set_ ## suffix ## be, type )\
    BO_ADD_DECL_S( bo_add_ ## suffix ## le, bo_set_ ## suffix ## le, type )
275

276
static inline bool bo_set_8(bo_t *p_bo, size_t i_offset, uint8_t i)
277
{
278 279 280 281
    if (!bo_extend(p_bo, i_offset + 1))
        return false;
    p_bo->b->p_buffer[i_offset] = i;
    return true;
282 283
}

284
static inline bool bo_add_8(bo_t *p_bo, uint8_t i)
285
{
286 287 288 289
    if(!p_bo->b || !bo_set_8( p_bo, p_bo->b->i_buffer, i ))
        return false;
    p_bo->b->i_buffer++;
    return true;
290 291
}

292 293 294 295
/* declares all bo_[set,add]_[16,32,64] */
BO_FUNC_DECL( 16, SetW,  uint16_t )
BO_FUNC_DECL( 32, SetDW, uint32_t )
BO_FUNC_DECL( 64, SetQW, uint64_t )
296

297 298 299
#undef BO_FUNC_DECL
#undef BO_SET_DECL_S
#undef BO_ADD_DECL_S
300

301
static inline bool bo_add_24be(bo_t *p_bo, uint32_t i)
302
{
303 304 305 306 307 308
    if(!p_bo->b || !bo_extend(p_bo, p_bo->b->i_buffer + 3))
        return false;
    p_bo->b->p_buffer[p_bo->b->i_buffer++] = ((i >> 16) & 0xff);
    p_bo->b->p_buffer[p_bo->b->i_buffer++] = ((i >> 8) & 0xff);
    p_bo->b->p_buffer[p_bo->b->i_buffer++] = (i & 0xff);
    return true;
309 310
}

311
static inline void bo_swap_32be (bo_t *p_bo, size_t i_pos, uint32_t i)
312
{
313 314
    if (!p_bo->b || p_bo->b->i_buffer < i_pos + 4)
        return;
315 316 317 318 319 320
    p_bo->b->p_buffer[i_pos    ] = (i >> 24)&0xff;
    p_bo->b->p_buffer[i_pos + 1] = (i >> 16)&0xff;
    p_bo->b->p_buffer[i_pos + 2] = (i >>  8)&0xff;
    p_bo->b->p_buffer[i_pos + 3] = (i      )&0xff;
}

321
static inline bool bo_add_mem(bo_t *p_bo, size_t i_size, const void *p_mem)
322
{
323 324 325 326 327
    if(!p_bo->b || !bo_extend(p_bo, p_bo->b->i_buffer + i_size))
        return false;
    memcpy(&p_bo->b->p_buffer[p_bo->b->i_buffer], p_mem, i_size);
    p_bo->b->i_buffer += i_size;
    return true;
328 329
}

330
#define bo_add_fourcc(p_bo, fcc) bo_add_mem(p_bo, 4, fcc)
331

332
#endif