vl: improve vlc functions and handling
authorMaarten Lankhorst <m.b.lankhorst@gmail.com>
Tue, 20 Dec 2011 11:43:23 +0000 (12:43 +0100)
committerChristian König <deathsimple@vodafone.de>
Fri, 23 Dec 2011 15:31:26 +0000 (16:31 +0100)
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>
src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c
src/gallium/auxiliary/vl/vl_vlc.h

index 936cf2cfc93a55093425265d2727b63dfb8bc4a0..7e20d7177e425705cbf9ebab41734f2a387fa9cc 100644 (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);
    }
 }
index dc4faedfcbbebee6446f3f8e381e25497daf68f8..ff0c4b52490679f5a5ab75003dec092e114592bf 100644 (file)
  *
  **************************************************************************/
 
+/*
+ * 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;
 }