Logo Search packages:      
Sourcecode: vic version File versions

decoder-bvc.cpp

/* $Header: /cs/research/mice/starship/src/local/CVS_repository/vic/codec/decoder-bvc.cpp,v 1.2 1999/11/05 12:30:25 piers Exp $ */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "decoder.h"
#include "inet.h"
#include "rtp.h"
#include "renderer.h"

class BvcDecoder : public Decoder {
 public:
      BvcDecoder();
      ~BvcDecoder();
      virtual void recv(pktbuf* pb);
      void resize(int width, int height);
      int colorhist(u_int* hist) const;
 protected:
      virtual void redraw();
      void sync();
      void decode(const u_char* bp, int cc, int blkno);
      void decode_block(int x, int y);
      void decode_sbc(int8_t* ll, int8_t* hl, int8_t* lh, int stride);
      int prune_layers(int active);
      void decode_coef(int8_t* p, int active, int qs);
      void reconstruct_block(int x, int y);
      void quantizer(u_int32_t nquant, u_int32_t oquant);
      void compute_dchild();

      const u_char *inb_;           /* input buffer XXX make u_long */
      const u_char *end_;
      u_int bb_;        /* bit buffer */
      int nbb_;         /* # bits in bit buffer */

      u_int32_t quant_;
      u_char qs_[64];
      /*XXX*/
      int8_t* level0_;
      int8_t* ll_;
      int8_t* lh_;
      int8_t* hl_;
      /*XXX*/
      u_char* blk_;

      u_char* frm_;

      /*XXX*/
      u_short dchild_[64];
};

static class BvcDecoderMatcher : public Matcher {
public:
      BvcDecoderMatcher() : Matcher("decoder") {}
      TclObject* match(const char* id) {
            if (strcasecmp(id, "bvc") == 0)
                  return (new BvcDecoder());
            else
                  return (0);
      }
} dm_bvc;

#define STAT_BAD_SYNTAX 0
#define STAT_BAD_GEOM   1

BvcDecoder::BvcDecoder() : Decoder(sizeof(bvchdr)),
      frm_(0), blk_(0), level0_(0)
{
      /*XXX*/
      for (int i = 0; i < 64; ++i)
            qs_[i] = 0;
      quant_ = 0;

      stat_[STAT_BAD_SYNTAX].name = "Bvc-Bad-Syntax";
      stat_[STAT_BAD_GEOM].name = "Bvc-Bad-Geom";
      nstat_ = 2;
      decimation_ = 411;

      /*XXX*/
      inw_ = 320;
      inh_ = 240;

      compute_dchild();
      resize(inw_, inh_);
}

BvcDecoder::~BvcDecoder()
{
      delete[] level0_;
      delete[] frm_;
      delete[] blk_;
}

#define LINEPAD 8

/*XXX*/
extern u_char child[];

/*XXX*/
void BvcDecoder::compute_dchild()
{
      int stride = (inw_ + LINEPAD) >> 1;
      /*XXX need to update dchild when qs_ changes */
      for (int i = 0; i < 64; ++i) {
            int v = child[i];
            if (v < 64)
                  dchild_[i] = (v << 5) | qs_[i];
            else if (v >= 192) {
                  v -= 156;
                  v >>= 1;
                  dchild_[i] = (v << 5) | (3 << 3) | qs_[i];
            } else {
                  int m;
                  if (v >= 128) {
                        m = 1;
                        v -= 128;
                  } else {
                        m = 2;
                        v -= 64;
                  }
                  int x = v & 7;
                  int y = v >> 3;
                  v = y * stride + x;
                  if ((v & 1) || (v >> 1) >= 0x7ff)
                        abort();/*XXX*/
                  v >>= 1;
                  dchild_[i] = (v << 5) | (m << 3) | qs_[i];
            }
      }
}

void BvcDecoder::resize(int width, int height)
{
      if ((width | height) & 0xf) {
            printf("vic: bad geometry in bvc coder (%dx%d)\n",
                   width, height);
            abort();
      }

      delete[] frm_;
      int size = width * height;
      /*XXX 4:1:1*/
      frm_ = new u_char[2 * size];
      /* 
       * Initialize image to gray.
       */
      memset(frm_, 0x80, 2 * size);

      /*XXX*/
      int w = width >> 1;
      int h = height >> 1;
      int s = (w + LINEPAD) * (h + 2);
      delete[] level0_;
      level0_ = new int8_t[3 * s];
      /*XXX*/
      memset(level0_, 0, 3 * s);
      int off = w + LINEPAD / 2;
      ll_ = level0_ + 0 * s + off;
      lh_ = level0_ + 1 * s + off;
      hl_ = level0_ + 2 * s + off;
      delete[] blk_;
      blk_ = new u_char[(width >> 4) * (height >> 4)];

      Decoder::resize(width, height);
}

u_char quantno[] = {
      9, 0, 2, 2, 4, 4, 4, 4,
      0, 1, 3, 3, 5, 5, 5, 5,
      2, 3, 6, 6, 7, 7, 7, 7,
      2, 3, 6, 6, 7, 7, 7, 7,
      4, 5, 7, 7, 8, 8, 8, 8,
      4, 5, 7, 7, 8, 8, 8, 8,
      4, 5, 7, 7, 8, 8, 8, 8,
      4, 5, 7, 7, 8, 8, 8, 8,
};
      
void
setquant(u_char* p, int n, int q)
{
      for (int i = 0; i < 64; ++i)
            if (n == quantno[i])
                  p[i] = q;
}

void BvcDecoder::quantizer(u_int32_t nquant, u_int32_t oquant)
{
      for (int i = 0; i < 10; ++i) {
            int nq = nquant & 7;
            int oq = oquant & 7;
            if (nq != oq)
                  setquant(qs_, i, nq);
            nquant >>= 3;
            oquant >>= 3;
      }
      compute_dchild();
}

#define MASK(s) ((1 << (s)) - 1)

/*
 * Read the next 16 bits off the bit string into the bit buffer.
 * Skip over zero-stuffed ff's but make no attempt to verify
 * that they aren't some other marker (which shouldn't be in the
 * middle of a block anyway).
 */
#define HUFFRQ(bb) \
 { \
      register int v; \
      register const u_char *cp = inb_; \
 \
      bb <<= 16; \
      v = *cp++; \
      bb |= v << 8; \
      v = *cp++; \
      bb |= v; \
      inb_ = cp; \
 \
}

#define HUFF_DECODE(ht, nbb, bb, result) { \
      register int s_, v_; \
 \
      if (nbb < 16) { \
            HUFFRQ(bb); \
            nbb += 16; \
      } \
      v_ = (bb >> (nbb - 16)) & 0xffff; \
      s_ = (ht)[v_]; \
      nbb -= (s_ >> 8); \
      result = s_ & 0xff; \
 }

#define GET_BITS(n, nbb, bb, result) \
{ \
      nbb -= n; \
      if (nbb < 0)  { \
            HUFFRQ(bb); \
            nbb += 16; \
      } \
      (result) = ((bb >> nbb) & MASK(n)); \
}

#define SKIP_BITS(n, nbb, bb) \
{ \
      nbb -= n; \
      if (nbb < 0)  { \
            HUFFRQ(bb); \
            nbb += 16; \
      } \
}

/*16x16*/
void BvcDecoder::reconstruct_block(int x, int y)
{
      int stride = (inw_ + LINEPAD) >> 1;
      int off = (y >> 1) * stride + (x >> 1);
      int16_t blk[2*10*16];

      int16_t* o = blk;
      u_int8_t* lu = (u_int8_t*)ll_ + off - stride;
      int8_t* h = lh_ + off - stride;
      o = blk;
      int th;
      for (th = 10; --th >= 0; ) {
            int l0 = lu[-1];
            int h0 = h[-1];
            int l1 = *lu++;
            int h1 = *h++;
            for (int w = 8; --w >= 0; ) {
                  int l3 = l1 + (l1 << 1);
                  int h3 = h1 + (h1 << 1);
                  int v = l0 + l3 + h0 - h3;
                  *o++ = v >> 2;

                  l0 = l1;
                  h0 = h1;
                  l1 = *lu++;
                  h1 = *h++;

                  v = l3 + l1 + h3 - h1;
                  *o++ = v >> 2;
            }
            lu += stride - 9;
            h += stride - 9;
      }
      int8_t* l = hl_ + off - stride;
#ifdef HAVE_HH
      h = hh_ + off - stride;
#endif
      for (th = 10; --th >= 0; ) {
            int l0 = l[-1];
            int h0 = h[-1];
            int l1 = *l++;
#ifdef HAVE_HH
            int h1 = *h++;
#else
            int h1 = 0;
#endif
            for (int w = 8; --w >= 0; ) {
                  int l3 = l1 + (l1 << 1);
                  int h3 = h1 + (h1 << 1);
                  int v = l0 + l3 + h0 - h3;
                  *o++ = v >> 2;

                  l0 = l1;
                  h0 = h1;
                  l1 = *l++;
#ifdef HAVE_HH
                  h1 = *h++;
#endif
                  v = l3 + l1 + h3 - h1;
                  *o++ = v >> 2;
            }
            l += stride - 9;
#ifdef HAVE_HH
            h += stride - 9;
#endif
      }

      o = blk;
      off = y * inw_ + x;
      u_int8_t* out = frm_ + off;
      for (int w = 16; --w >= 0; ) {
            const int16_t* cl = o++;
            const int16_t* ch = cl + 10*16;
            u_int8_t* p = out++;

            int l0 = *cl;
            cl += 16;
            int h0 = *ch;
            ch += 16;
            int l1 = *cl;
            cl += 16;
            int h1 = *ch;
            ch += 16;
            
            for (int th = 8; --th >= 0; ) {
                  int l3 = l1 + (l1 << 1);
                  int h3 = h1 + (h1 << 1);
                  int v = l3 + l0 + h0 - h3;
                  v >>= 2;
                  /*XXX*/
                  if (v & ~0xff)
                        v = (v < 0) ? 0 : 255;
                  *p = v;
                  p += inw_;

                  l0 = l1;
                  h0 = h1;
                  l1 = *cl;
                  cl += 16;
                  h1 = *ch;
                  ch += 16;

                  v = l1 + l3 + h3 - h1;
                  v >>= 2;
                  /*XXX*/
                  if (v & ~0xff)
                        v = (v < 0) ? 0 : 255;
                  *p = v;
                  p += inw_;
            }
      }
}

void haar_rev(const int8_t* in, int8_t* out, int stride)
{
      int blk[64];
      int* o = blk;

#ifdef notdef
      if (nohaar)
            return;
#endif

      int m = 0xff;/*XXX make sure DC is unsigned*/

      /* inverse Haar transform 8x8 base image */
      int k;
      for (k = 8; --k >= 0; ) {
            int t4 = in[0];
            t4 &= m;
            m = ~0;
            int t5 = in[1];
            int t0 = t4 - t5;
            int t1 = t4 + t5;
                  
            t4 = in[2];
            t5 = in[3];
            int t2 = t0 - t4;
            int t3 = t0 + t4;
            t4 = t1 - t5;
            t5 = t1 + t5;

            t0 = in[4];
            t1 = in[5];
            o[0] = t2 - t0;
            o[1] = t2 + t0;
            o[2] = t3 - t1;
            o[3] = t3 + t1;

            t0 = in[6];
            t1 = in[7];
            o[4] = t4 - t0;
            o[5] = t4 + t0;
            o[6] = t5 - t1;
            o[7] = t5 + t1;

            o += 8;
            in += 8;
      }
      /* columns */
      o = blk;
      for (k = 8; --k >= 0; ) {
            int t4 = o[0*8];
            int t5 = o[1*8];
            int t0 = t4 - t5;
            int t1 = t4 + t5;

            t4 = o[2*8];
            t5 = o[3*8];
            int t2 = t0 - t4;
            int t3 = t0 + t4;
            t4 = t1 - t5;
            t5 = t1 + t5;

            t0 = o[4*8];
            t1 = o[5*8];

            /*
             * Saturate the reconstructed values, since quantization
             * of the transform coefficients can result in values
             * outside [0,255].
             */
#define UCLIMIT(x) ((t = (x)), (t &= ~(t>>31)), (t | ~((t-256) >> 31)))
            int t;
            *out = UCLIMIT(t2 - t0);
            out += stride;
            *out = UCLIMIT(t2 + t0);
            out += stride;
            *out = UCLIMIT(t3 - t1);
            out += stride;
            *out = UCLIMIT(t3 + t1);
            out += stride;

            t0 = o[6*8];
            t1 = o[7*8];
            *out = UCLIMIT(t4 - t0);
            out += stride;
            *out = UCLIMIT(t4 + t0);
            out += stride;
            *out = UCLIMIT(t5 - t1);
            out += stride;
            *out = UCLIMIT(t5 + t1);
            out += stride;

            out -= stride << 3;
            ++out;
            ++o;
      }
}

#define DECODE(v, qs) \
{ \
      int t; \
      GET_BITS(2, nbb, bb, t); \
      if (t == 0) \
            (v) = 0; \
      else if (t == 2) \
            (v) = 1 << (qs); \
      else if (t == 3) \
            (v) = -1 << (qs); \
      else { \
            GET_BITS(8 - (qs), nbb, bb, t); \
            t <<= (qs); \
            if (t & 0x80) \
                  t = -t | ~0x7f; \
            (v) = t; \
      } \
}

void BvcDecoder::decode_coef(int8_t* p, int active, int qs)
{
      int n;
      for (n = 0; ((1 << n) & active) != 0; ++n)
            ;
      int v;
      GET_BITS(n, nbb_, bb_, v);
      if (v != 0) {
            int sign;
            GET_BITS(1, nbb_, bb_, sign);
            v <<= (7 - qs);
            if (qs < 7)
                  v |= 1 << (6 - qs);
            if (sign)
                  v = -v;
      }
      *p = v;
}

int BvcDecoder::prune_layers(int active)
{
      /*XXX do this with lookup table? */
      while (active != 0) {
            int v;
            GET_BITS(1, nbb_, bb_, v);
            if (v != 0)
                  break;
            active >>= 1;
      }
      return (active);
}

void BvcDecoder::decode_sbc(int8_t* ll, int8_t* hl, int8_t* lh, int stride)
{
#ifdef notyet
      u_int bb = bb_;
      int nbb = nbb_;
#endif
      u_char stack[3*64];
      u_char* sp = stack;

      /*XXX dpcm & entropy */
      int v;
      GET_BITS(8, /*XXX*/nbb_, bb_, v);
      ll[0] = v;

      int hs = qs_[0];

      int active = prune_layers(0x7f);
      if (active == 0)
            return;
      int ga = prune_layers(active);

      *sp++ = ga;
      *sp++ = active|0x80;
      *sp++ = 9;
      *sp++ = ga;
      *sp++ = active|0x80;
      *sp++ = 8;
      *sp++ = ga;
      *sp++ = active|0x80;
      *sp++ = 1;

      do {
            int k = *--sp;
            int active = *--sp;
            int v = dchild_[k];
            int s = v & 7;

            decode_coef(&ll[k], active & 0x7f, s);
            if (active & 0x80) {
                  active = *--sp;
                  if (active & 0x80)
                        abort();
                  if (active == 0)
                        continue;
                  active = prune_layers(active);
                  if (active == 0)
                        continue;
                  k = (v >> 3) & 3;
                  if (k != 0) {
                        int off;
                        int8_t* p;
                        if (k == 1) {
                              p = lh;
                              off = stride;
                              s = hs;
                        } else if (k == 2) {
                              p = hl;
                              off = stride;
                              s = hs;
                        } else {
                              p = ll;
                              off = 8;
                              s = qs_[36];
                        }
                        k = (v >> 5) << 1;
                        decode_coef(&p[k], active, s);
                        decode_coef(&p[k + 1], active, s);
                        decode_coef(&p[k + 8], active, s);
                        decode_coef(&p[k + 9], active, s);
                  } else {
                        /*XXX*/
                        k = v >> 5;
                        if (k == 0)
                              abort();

                        *sp++ = active;
                        *sp++ = k + 9;
                        *sp++ = active;
                        *sp++ = k + 8;
                        *sp++ = active;
                        *sp++ = k + 1;
                        *sp++ = active;
                        *sp++ = k;
                  }
            } else {
                  active = prune_layers(active);
                  if (active == 0)
                        continue;

                  k = (v >> 3) & 3;
                  if (k != 0) {
                        int off;
                        int8_t* p;
                        if (k == 1) {
                              p = lh;
                              off = stride;
                              s = hs;
                        } else if (k == 2) {
                              p = hl;
                              off = stride;
                              s = hs;
                        } else {
                              p = ll;
                              off = 8;
                              s = qs_[36];
                        }
                        k = (v >> 5) << 1;
                        decode_coef(&p[k], active, s);
                        decode_coef(&p[k + 1], active, s);
                        decode_coef(&p[k + 8], active, s);
                        decode_coef(&p[k + 9], active, s);
                  } else {
                        /*XXX*/
                        k = v >> 5;
                        if (k == 0)
                              abort();

                        int ga = prune_layers(active);
                        *sp++ = ga;
                        *sp++ = active|0x80;
                        *sp++ = k + 9;
                        *sp++ = ga;
                        *sp++ = active|0x80;
                        *sp++ = k + 8;
                        *sp++ = ga;
                        *sp++ = active|0x80;
                        *sp++ = k + 1;
                        *sp++ = ga;
                        *sp++ = active|0x80;
                        *sp++ = k;
                  }
            }
      } while (sp > stack);

#ifdef notyet
      bb_ = bb;
      nbb_ = nbb;
#endif
}

inline void zeroblk(int8_t* p, int stride)
{
      for (int h = 8; --h >= 0; ) {
            *(u_int32_t*)p = 0;
            *(u_int32_t*)(p + 4) = 0;
            p += stride;
      }
}

void BvcDecoder::decode_block(int x, int y)
{
      int stride = (inw_ + LINEPAD) >> 1;
      int off = (y >> 1) * stride + (x >> 1);

      int8_t* ll = ll_ + off;
      int8_t* hl = hl_ + off;
      int8_t* lh = lh_ + off;

      zeroblk(hl, stride);
      zeroblk(lh, stride);
      int8_t LL[64];
      memset(LL, 0, sizeof(LL));
      decode_sbc(LL, hl, lh, stride);
      haar_rev(LL, ll, stride);

      int8_t junk[64];
      memset(LL, 0, sizeof(LL));
      decode_sbc(LL, junk, junk, 8);
      int s = inw_ * inh_;
      int8_t* chm = (int8_t*)frm_ + s;
      chm += (y >> 1) * (inw_ >> 1) + (x >> 1);
      haar_rev(LL, chm, inw_ >> 1);
      memset(LL, 0, sizeof(LL));
      decode_sbc(LL, junk, junk, 8);
      haar_rev(LL, chm + (s >> 2), inw_ >> 1);

      /*
       * XXX this needs a comment; esp. subtlety about sign change
       * on lh extension.
       */

      if (y == 0) {
            memcpy(ll - stride, ll, 8 * sizeof(*ll));
            memcpy(hl - stride, hl, 8 * sizeof(*hl));
            for (int k = 0; k < 8; ++k)
                  lh[-stride + k] = -lh[k];
      } else if (y == inh_ - 16 /*XXX*/) {
            ll += stride << 3;
            lh += stride << 3;
            hl += stride << 3;
            memcpy(ll, ll - stride, 8 * sizeof(*ll));
            memcpy(hl, hl - stride, 8 * sizeof(*hl));
            for (int k = 0; k < 8; ++k)
                  lh[k] = -lh[-stride + k];
            ll -= stride << 3;
            lh -= stride << 3;
            hl -= stride << 3;
      }
      if (x == 0) {
            for (int k = 0; k < 8; ++k) {
                  ll[-1] = ll[0];
                  ll += stride;
                  hl[-1] = hl[0];
                  hl += stride;
                  lh[-1] = -lh[0];
                  lh += stride;
            }
      } else if (x == inw_ - 16 /*XXX*/) {
            ll += 8;
            lh += 8;
            hl += 8;
            for (int k = 0; k < 8; ++k) {
                  ll[0] = ll[-1];
                  ll += stride;
                  hl[0] = hl[-1];
                  hl += stride;
                  lh[0] = -lh[-1];
                  lh += stride;
            }
      }
}

void BvcDecoder::decode(const u_char* bp, int cc, int blkno)
{
      inb_ = bp;
      end_ = bp + cc;
      nbb_ = 0;

      /*XXX*/
      int blkw = inw_ >> 4;

      while (inb_ + 5 < end_) {
            int v;
            GET_BITS(1, nbb_, bb_, v);
            if (v == 1)
                  blkno += 1;
            else {
                  GET_BITS(1, nbb_, bb_, v);
                  if (v == 1) {
                        GET_BITS(4, nbb_, bb_, v);
                        v += 2;
                  } else {
                        GET_BITS(11, nbb_, bb_, v);
                  }
                  blkno += v;
            }
            int y = blkno / blkw;
            int x = blkno - y * blkw;

            x <<= 4;
            y <<= 4;
            if ((unsigned)x > inw_ || (unsigned)y > inh_) {
                  count(STAT_BAD_SYNTAX);
                  return;
            }
            ndblk_++;
            decode_block(x, y);

            /*XXX*/
            /* remember that we need to reconstruct this block */
            blk_[(x >> 4) + blkw * (y >> 4)] = 1;

            /*XXX*/
            int k = (x >> 3) + (inw_ >> 3) * (y >> 3);
            rvts_[k] = now_;
            rvts_[k + 1] = now_;
            k += inw_ >> 3;
            rvts_[k] = now_;
            rvts_[k + 1] = now_;
      }

#ifdef notdef
      if (Lflag) {
            u_char* p = frm_;
            int16_t* ll = ll_;
            int16_t* lh = lh_;
            int16_t* hl = hl_;
            for (int y = 0; y < 120; ++y) {
                  for (int x = 0; x < 160; ++x) {
#define LPIX(v) (((v) < 0) ? 0 : ((v) > 255) ? 255 : (v))
#define HPIX(v) LPIX(4 * (v) + 128)
                        int v = ll[x];
                        p[0] = HPIX(v);
                        v = lh[x];
                        p[160] = HPIX(v);
                        v = hl[x];
                        p[320*120] = HPIX(v);
                        p[320*120 + 160] = HPIX(128);

                        ++p;
                  }
                  ll += (inw_ + LINEPAD) >> 1;
                  lh += (inw_ + LINEPAD) >> 1;
                  hl += (inw_ + LINEPAD) >> 1;
                  p += 160;
            }
      }
#endif
}

void BvcDecoder::recv(pktbuf* pb)
{
      rtphdr* rh = (rtphdr*)pb->dp;
      int hdrsize = sizeof(rtphdr) + hdrlen();
      u_char* bp = pb->dp + hdrsize;
      int cc = pb->len - hdrsize;

      const bvchdr* ph = (bvchdr*)(rh + 1);
      int w = ph->width << 3;
      int h = ph->height << 3;
      if (w != inw_ || h != inh_) {
            if ((unsigned)w > 1000 || (unsigned)h > 1000) {
                  /*XXX*/
                  w = 320;
                  h = 240;
                  count(STAT_BAD_GEOM);
            }
            resize(w, h);
      }

      if (ph->quant != quant_) {
            quantizer(ntohl(ph->quant), ntohl(quant_));
            quant_ = ph->quant;
      }
      int blkno = htons(ph->blkno);
      //NOT-USED timeval t = unixtime();
      decode(bp, cc, blkno << 16 >> 16);
      if (ntohs(rh->rh_flags) & RTP_M) {
            sync();
            render_frame(frm_);
            resetndblk();
      }
      pb->release();
}

void BvcDecoder::sync()
{
      u_char* p = blk_;
      int blkw = inw_ >> 4;
      int blkh = inh_ >> 4;
      for (int y = 0; y < blkh; ++y) {
            for (int x = 0; x < blkw; ++x) {
                  if (*p != 0) {
                        *p = 0;
                        reconstruct_block(x << 4, y << 4);
                  }
                  ++p;
            }
      }
}

/*
 * XXX should use PlaneDecoder class for 411 also
 */

int BvcDecoder::colorhist(u_int* hist) const
{
      int s = inw_ * inh_;
      colorhist_411_556(hist, frm_, frm_ + s, frm_ + s + (s >> 2),
                    inw_, inh_);
      return (1);
}

void BvcDecoder::redraw()
{
      Decoder::redraw(frm_);
}

Generated by  Doxygen 1.6.0   Back to index