vl: improve vlc functions and handling

Only initialize vlc in MPEG2 decoding once for all slices,
add more sanity checks to vlc decoding functions, support
multiple vlc input buffer, improve documentation of the
vlc functions.

v2: also implement multiple inputs for the vlc functions
v3: some bug fixes for buffer size and alignment corner cases
v4: rework of the patch, some more improvements

Signed-off-by: Maarten Lankhorst <m.b.lankhorst@gmail.com>
Signed-off-by: Christian König <deathsimple@vodafone.de>
This commit is contained in:
Maarten Lankhorst
2011-12-20 12:43:23 +01:00
committed by Christian König
parent ebe7c687ce
commit efa93ae449
2 changed files with 156 additions and 59 deletions
+19 -27
View File
@@ -786,7 +786,7 @@ entry:
}
}
static INLINE bool
static INLINE void
decode_slice(struct vl_mpg12_bs *bs)
{
struct pipe_mpeg12_macroblock mb;
@@ -800,6 +800,7 @@ decode_slice(struct vl_mpg12_bs *bs)
mb.blocks = dct_blocks;
reset_predictor(bs);
vl_vlc_fillbits(&bs->vlc);
dct_scale = quant_scale[bs->desc.q_scale_type][vl_vlc_get_uimsbf(&bs->vlc, 5)];
if (vl_vlc_get_uimsbf(&bs->vlc, 1))
@@ -807,13 +808,15 @@ decode_slice(struct vl_mpg12_bs *bs)
vl_vlc_fillbits(&bs->vlc);
vl_vlc_fillbits(&bs->vlc);
assert(vl_vlc_bits_left(&bs->vlc) > 23 && vl_vlc_peekbits(&bs->vlc, 23));
do {
int inc = 0;
while (vl_vlc_peekbits(&bs->vlc, 11) == 15) {
vl_vlc_eatbits(&bs->vlc, 11);
vl_vlc_fillbits(&bs->vlc);
}
if (bs->decoder->profile == PIPE_VIDEO_PROFILE_MPEG1)
while (vl_vlc_peekbits(&bs->vlc, 11) == 15) {
vl_vlc_eatbits(&bs->vlc, 11);
vl_vlc_fillbits(&bs->vlc);
}
while (vl_vlc_peekbits(&bs->vlc, 11) == 8) {
vl_vlc_eatbits(&bs->vlc, 11);
@@ -928,7 +931,6 @@ decode_slice(struct vl_mpg12_bs *bs)
mb.num_skipped_macroblocks = 0;
bs->decoder->decode_macroblock(bs->decoder, &mb.base, 1);
return true;
}
void
@@ -959,32 +961,22 @@ void
vl_mpg12_bs_decode(struct vl_mpg12_bs *bs, unsigned num_bytes, const uint8_t *buffer)
{
assert(bs);
assert(buffer && num_bytes);
while(num_bytes > 2) {
if (buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0x01 &&
buffer[3] >= 0x01 && buffer[3] < 0xAF) {
unsigned consumed;
vl_vlc_init(&bs->vlc, 1, (const void * const *)&buffer, &num_bytes);
while (vl_vlc_bits_left(&bs->vlc) > 32) {
uint32_t code = vl_vlc_peekbits(&bs->vlc, 32);
buffer += 3;
num_bytes -= 3;
if (code >= 0x101 && code <= 0x1AF) {
vl_vlc_eatbits(&bs->vlc, 24);
decode_slice(bs);
vl_vlc_init(&bs->vlc, buffer, num_bytes);
if (!decode_slice(bs))
return;
consumed = num_bytes - vl_vlc_bits_left(&bs->vlc) / 8;
/* crap, this is a bug we have consumed more bytes than left in the buffer */
assert(consumed <= num_bytes);
num_bytes -= consumed;
buffer += consumed;
/* align to a byte again */
vl_vlc_eatbits(&bs->vlc, vl_vlc_valid_bits(&bs->vlc) & 7);
} else {
++buffer;
--num_bytes;
vl_vlc_eatbits(&bs->vlc, 8);
}
vl_vlc_fillbits(&bs->vlc);
}
}
+137 -32
View File
@@ -25,22 +25,30 @@
*
**************************************************************************/
/*
* Functions for fast bitwise access to multiple probably unaligned input buffers
*/
#ifndef vl_vlc_h
#define vl_vlc_h
#include <assert.h>
#include "pipe/p_compiler.h"
#include "util/u_math.h"
#include "util/u_pointer.h"
#include "util/u_debug.h"
struct vl_vlc
{
uint64_t buffer;
unsigned valid_bits;
uint32_t *data;
uint32_t *end;
signed invalid_bits;
const uint8_t *data;
const uint8_t *end;
unsigned num_inputs;
const void *const *inputs;
const unsigned *sizes;
unsigned bytes_left;
};
struct vl_vlc_entry
@@ -55,11 +63,17 @@ struct vl_vlc_compressed
struct vl_vlc_entry entry;
};
/**
* initalize and decompress a lookup table
*/
static INLINE void
vl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_vlc_compressed *src, unsigned src_size)
{
unsigned i, bits = util_logbase2(dst_size);
assert(dst && dst_size);
assert(src && src_size);
for (i=0;i<dst_size;++i) {
dst[i].length = 0;
dst[i].value = 0;
@@ -71,77 +85,161 @@ vl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_v
}
}
/**
* switch over to next input buffer
*/
static INLINE void
vl_vlc_next_input(struct vl_vlc *vlc)
{
const uint8_t* data = vlc->inputs[0];
unsigned len = vlc->sizes[0];
assert(vlc);
assert(vlc->num_inputs);
vlc->bytes_left -= len;
/* align the data pointer */
while (len && pointer_to_uintptr(data) & 3) {
vlc->buffer |= (uint64_t)*data << (24 + vlc->invalid_bits);
++data;
--len;
vlc->invalid_bits -= 8;
}
vlc->data = data;
vlc->end = data + len;
--vlc->num_inputs;
++vlc->inputs;
++vlc->sizes;
}
/**
* fill the bit buffer, so that at least 32 bits are valid
*/
static INLINE void
vl_vlc_fillbits(struct vl_vlc *vlc)
{
if (vlc->valid_bits < 32) {
uint32_t value = *vlc->data;
assert(vlc);
//assert(vlc->data <= vlc->end);
/* as long as the buffer needs to be filled */
while (vlc->invalid_bits > 0) {
unsigned bytes_left = vlc->end - vlc->data;
/* if this input is depleted */
if (bytes_left == 0) {
if (vlc->num_inputs)
/* go on to next input */
vl_vlc_next_input(vlc);
else
/* or give up since we don't have anymore inputs */
return;
} else if (bytes_left >= 4) {
/* enough bytes in buffer, read in a whole dword */
uint64_t value = *(const uint32_t*)vlc->data;
#ifndef PIPE_ARCH_BIG_ENDIAN
value = util_bswap32(value);
value = util_bswap32(value);
#endif
vlc->buffer |= (uint64_t)value << (32 - vlc->valid_bits);
++vlc->data;
vlc->valid_bits += 32;
vlc->buffer |= value << vlc->invalid_bits;
vlc->data += 4;
vlc->invalid_bits -= 32;
/* buffer is now definitely filled up avoid the loop test */
break;
} else while (vlc->data < vlc->end) {
/* not enough bytes left in buffer, read single bytes */
vlc->buffer |= (uint64_t)*vlc->data << (24 + vlc->invalid_bits);
++vlc->data;
vlc->invalid_bits -= 8;
}
}
}
/**
* initialize vlc structure and start reading from first input buffer
*/
static INLINE void
vl_vlc_init(struct vl_vlc *vlc, const uint8_t *data, unsigned len)
vl_vlc_init(struct vl_vlc *vlc, unsigned num_inputs,
const void *const *inputs, const unsigned *sizes)
{
unsigned i;
assert(vlc);
assert(data && len);
assert(num_inputs);
vlc->buffer = 0;
vlc->valid_bits = 0;
vlc->invalid_bits = 32;
vlc->num_inputs = num_inputs;
vlc->inputs = inputs;
vlc->sizes = sizes;
vlc->bytes_left = 0;
/* align the data pointer */
while (pointer_to_uintptr(data) & 3) {
vlc->buffer |= (uint64_t)*data << (56 - vlc->valid_bits);
++data;
--len;
vlc->valid_bits += 8;
}
vlc->data = (uint32_t*)data;
vlc->end = (uint32_t*)(data + len);
for (i = 0; i < num_inputs; ++i)
vlc->bytes_left += sizes[i];
vl_vlc_next_input(vlc);
vl_vlc_fillbits(vlc);
vl_vlc_fillbits(vlc);
}
/**
* number of bits still valid in bit buffer
*/
static INLINE unsigned
vl_vlc_valid_bits(struct vl_vlc *vlc)
{
return 32 - vlc->invalid_bits;
}
/**
* number of bits left over all inbut buffers
*/
static INLINE unsigned
vl_vlc_bits_left(struct vl_vlc *vlc)
{
signed bytes_left = ((uint8_t*)vlc->end)-((uint8_t*)vlc->data);
return bytes_left * 8 + vlc->valid_bits;
signed bytes_left = vlc->end - vlc->data;
bytes_left += vlc->bytes_left;
return bytes_left * 8 + vl_vlc_valid_bits(vlc);
}
/**
* get num_bits from bit buffer without removing them
*/
static INLINE unsigned
vl_vlc_peekbits(struct vl_vlc *vlc, unsigned num_bits)
{
//assert(vlc->valid_bits >= num_bits);
assert(vl_vlc_valid_bits(vlc) <= num_bits || vlc->data >= vlc->end);
return vlc->buffer >> (64 - num_bits);
}
/**
* remove num_bits from bit buffer
*/
static INLINE void
vl_vlc_eatbits(struct vl_vlc *vlc, unsigned num_bits)
{
//assert(vlc->valid_bits > num_bits);
assert(vl_vlc_valid_bits(vlc) <= num_bits);
vlc->buffer <<= num_bits;
vlc->valid_bits -= num_bits;
vlc->invalid_bits += num_bits;
}
/**
* get num_bits from bit buffer with removing them
*/
static INLINE unsigned
vl_vlc_get_uimsbf(struct vl_vlc *vlc, unsigned num_bits)
{
unsigned value;
//assert(vlc->valid_bits >= num_bits);
assert(vl_vlc_valid_bits(vlc) <= num_bits);
value = vlc->buffer >> (64 - num_bits);
vl_vlc_eatbits(vlc, num_bits);
@@ -149,12 +247,15 @@ vl_vlc_get_uimsbf(struct vl_vlc *vlc, unsigned num_bits)
return value;
}
/**
* treat num_bits as signed value and remove them from bit buffer
*/
static INLINE signed
vl_vlc_get_simsbf(struct vl_vlc *vlc, unsigned num_bits)
{
signed value;
//assert(vlc->valid_bits >= num_bits);
assert(vl_vlc_valid_bits(vlc) <= num_bits);
value = ((int64_t)vlc->buffer) >> (64 - num_bits);
vl_vlc_eatbits(vlc, num_bits);
@@ -162,11 +263,15 @@ vl_vlc_get_simsbf(struct vl_vlc *vlc, unsigned num_bits)
return value;
}
/**
* lookup a value and length in a decompressed table
*/
static INLINE int8_t
vl_vlc_get_vlclbf(struct vl_vlc *vlc, const struct vl_vlc_entry *tbl, unsigned num_bits)
{
tbl += vl_vlc_peekbits(vlc, num_bits);
vl_vlc_eatbits(vlc, tbl->length);
assert(tbl->length);
return tbl->value;
}