summaryrefslogtreecommitdiffstats
path: root/src/gallium/auxiliary/vl
diff options
context:
space:
mode:
authorMaarten Lankhorst <[email protected]>2011-12-20 12:43:23 +0100
committerChristian König <[email protected]>2011-12-23 16:31:26 +0100
commitefa93ae449b6dc8437ee7240a8ea050a0d1699e0 (patch)
treec7cd9c55ad39463df1e1c2032d1e59ef9775f473 /src/gallium/auxiliary/vl
parentebe7c687ceed4e5ca704b325aac6b91791d394b0 (diff)
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 <[email protected]> Signed-off-by: Christian König <[email protected]>
Diffstat (limited to 'src/gallium/auxiliary/vl')
-rw-r--r--src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c46
-rw-r--r--src/gallium/auxiliary/vl/vl_vlc.h169
2 files changed, 156 insertions, 59 deletions
diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c
index 936cf2cfc93..7e20d7177e4 100644
--- a/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c
+++ b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c
@@ -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);
}
}
diff --git a/src/gallium/auxiliary/vl/vl_vlc.h b/src/gallium/auxiliary/vl/vl_vlc.h
index dc4faedfcbb..ff0c4b52490 100644
--- a/src/gallium/auxiliary/vl/vl_vlc.h
+++ b/src/gallium/auxiliary/vl/vl_vlc.h
@@ -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;
}