Mesa (master): vl: improve vlc functions and handling

Christian König deathsimple at kemper.freedesktop.org
Fri Dec 23 15:33:58 UTC 2011


Module: Mesa
Branch: master
Commit: efa93ae449b6dc8437ee7240a8ea050a0d1699e0
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=efa93ae449b6dc8437ee7240a8ea050a0d1699e0

Author: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date:   Tue Dec 20 12:43:23 2011 +0100

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 at gmail.com>
Signed-off-by: Christian König <deathsimple at vodafone.de>

---

 src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c |   46 +++----
 src/gallium/auxiliary/vl/vl_vlc.h              |  169 +++++++++++++++++++-----
 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 936cf2c..7e20d71 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 dc4faed..ff0c4b5 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;
 }
 




More information about the mesa-commit mailing list