Logo Search packages:      
Sourcecode: vic version File versions

decoder-nv.cpp

/*
 * Copyright (c) 1993-1994 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and the Network Research Group at
 *      Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/*
 * This module was originally derived from:
 *
 * Netvideo version 3.2
 * Written by Ron Frederick <frederick@parc.xerox.com>
 *
 * Video decode routines
 *
 * Copyright (c) Xerox Corporation 1992. All rights reserved.
 *  
 * License is granted to copy, to use, and to make and to use derivative
 * works for research and evaluation purposes, provided that Xerox is
 * acknowledged in all documentation pertaining to any such copy or derivative
 * work. Xerox grants no other licenses expressed or implied. The Xerox trade
 * name should not be used in any advertising without its written permission.
 *  
 * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
 * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
 * FOR ANY PARTICULAR PURPOSE.  The software is provided "as is" without
 * express or implied warranty of any kind.
 *  
 * These notices must be retained in any copies of any part of this software.
 */
static const char rcsid[] =
    "@(#) $Header: /cs/research/mice/starship/src/local/CVS_repository/vic/codec/decoder-nv.cpp,v 1.2 1999/11/05 11:33:04 piers Exp $ (LBL)";

#include <stdio.h>
#include <string.h>
#include "inet.h"
#include "rtp.h"
#include "decoder.h"
#include "pktbuf.h"

class NvDecoder : public PlaneDecoder {
public:
      NvDecoder();
protected:
      void info(char* wrk) const;
      virtual void recv(pktbuf*);
      const u_char* decode_run(const u_char* data, const u_char* end,
                         int color);
      void VidTransform_Rev(u_int* inp, u_char* yp, char* up, char* vp,
                        int width);
      void NVDCT_RevTransform(u_int* inp, u_char *yp,
                        char* up, char* vp, int width);
      int use_dct_;
};

static class NvDecoderMatcher : public Matcher {
public:
      NvDecoderMatcher() : Matcher("decoder") {}
      TclObject* match(const char* id) {
            if (strcasecmp(id, "nv") == 0)
                  return (new NvDecoder());
            return (0);
      }
} dm_nv;

#define STAT_BAD_GEOM   0
#define STAT_BAD_COORD  1
#define STAT_BAD_BLKRUN 2
#define STAT_BAD_RUNLEN 3
#define STAT_BAD_ENC    4

NvDecoder::NvDecoder() : PlaneDecoder(sizeof(nvhdr)), use_dct_(0)
{
      stat_[STAT_BAD_GEOM].name = "Nv-Bad-Geom";
      stat_[STAT_BAD_COORD].name = "Nv-Bad-Coord";
      stat_[STAT_BAD_BLKRUN].name = "Nv-Bad-Blkrun";
      stat_[STAT_BAD_RUNLEN].name = "Nv-Bad-Runlen";
      stat_[STAT_BAD_ENC].name = "Nv-Bad-Enc";
      nstat_ = 5;

      inw_ = 0;
      inh_ = 0;

}
void NvDecoder::info(char* wrk) const
{
      strcpy(wrk, use_dct_ ? "[dct]" : "[haar]");
}

/* Sick little macro which will limit x to [0..255] with logical ops */
#define UCLIMIT(x) ((t = (x)), (t &= ~(t>>31)), (t | ~((t-256) >> 31)))
/* A variant of above which will limit x to [-128..127] */
#define SCLIMIT(x) (UCLIMIT((x)+128)-128)

void NvDecoder::VidTransform_Rev(u_int* inp, u_char *yp,
                         char* up, char* vp, int width)
{
    register int i, t, t0, t1, t2, t3, t4, t5, *dataptr;
    register int width2=2*width, width6=6*width;
    register signed char *inpcptr=(signed char *)inp;
    static int block[64];
#define SIGN_EXTEND(c) c

    dataptr = block;
    for (i=0; i<8; i++) {
      if ((inp[0] << 8) == 0) {
          t2 = t3 = t4 = t5 = SIGN_EXTEND(inpcptr[0]);
      } else {
          t4 = SIGN_EXTEND(inpcptr[0]);
          t5 = SIGN_EXTEND(inpcptr[1]);
          t0 = t4 - t5;
          t1 = t4 + t5;

          t4 = SIGN_EXTEND(inpcptr[2]);
          t5 = SIGN_EXTEND(inpcptr[3]);
          t2 = t0 - t4;
          t3 = t0 + t4;
          t4 = t1 - t5;
          t5 = t1 + t5;
      }

      if (inp[1] == 0) {
          dataptr[0] = dataptr[1] = t2;
          dataptr[2] = dataptr[3] = t3;
          dataptr[4] = dataptr[5] = t4;
          dataptr[6] = dataptr[7] = t5;
      } else {
          t0 = SIGN_EXTEND(inpcptr[4]);
          t1 = SIGN_EXTEND(inpcptr[5]);
          dataptr[0] = t2 - t0;
          dataptr[1] = t2 + t0;
          dataptr[2] = t3 - t1;
          dataptr[3] = t3 + t1;

          t0 = SIGN_EXTEND(inpcptr[6]);
          t1 = SIGN_EXTEND(inpcptr[7]);
          dataptr[4] = t4 - t0;
          dataptr[5] = t4 + t0;
          dataptr[6] = t5 - t1;
          dataptr[7] = t5 + t1;
      }

      inp += 2;
      inpcptr += 8;
      dataptr += 8;
    }

    dataptr = block;
    for (i=0; i<8; i++) {
      t4 = dataptr[0] + 128; /* Add back DC offset */
      t5 = dataptr[8];
      t0 = t4 - t5;
      t1 = t4 + t5;

      t4 = dataptr[16];
      t5 = dataptr[24];
      t2 = t0 - t4;
      t3 = t0 + t4;
      t4 = t1 - t5;
      t5 = t1 + t5;

      t0 = dataptr[32];
      t1 = dataptr[40];
      yp[0] = UCLIMIT(t2 - t0);
      yp[width] = UCLIMIT(t2 + t0);
      yp += width2;
      yp[0] = UCLIMIT(t3 - t1);
      yp[width] = UCLIMIT(t3 + t1);
      yp += width2;

      t0 = dataptr[48];
      t1 = dataptr[56];
      yp[0] = UCLIMIT(t4 - t0);
      yp[width] = UCLIMIT(t4 + t0);
      yp += width2;
      yp[0] = UCLIMIT(t5 - t1);
      yp[width] = UCLIMIT(t5 + t1);
      yp -= width6;

      yp++;
      dataptr++;
    }

    if (up) {
      int uswitch = 1;
      signed char* p = (signed char*)up++;
      dataptr = block;
      for (i=0; i<8; i++) {
          if ((inp[0] << 16) == 0) {
            t2 = t3 = SIGN_EXTEND(inpcptr[0]);
            t4 = t5 = SIGN_EXTEND(inpcptr[1]);
          } else {
            t0 = SIGN_EXTEND(inpcptr[0]);
            t1 = SIGN_EXTEND(inpcptr[1]);

            t4 = SIGN_EXTEND(inpcptr[2]);
            t5 = SIGN_EXTEND(inpcptr[3]);
            t2 = t0 - t4;
            t3 = t0 + t4;
            t4 = t1 - t5;
            t5 = t1 + t5;
          }

          if (inp[1] == 0) {
            dataptr[0] = dataptr[2] = t2;
            dataptr[4] = dataptr[6] = t3;
            dataptr[1] = dataptr[3] = t4;
            dataptr[5] = dataptr[7] = t5;
          } else {
            t0 = SIGN_EXTEND(inpcptr[4]);
            t1 = SIGN_EXTEND(inpcptr[5]);
            dataptr[0] = t2 - t0;
            dataptr[2] = t2 + t0;
            dataptr[4] = t3 - t1;
            dataptr[6] = t3 + t1;

            t0 = SIGN_EXTEND(inpcptr[6]);
            t1 = SIGN_EXTEND(inpcptr[7]);
            dataptr[1] = t4 - t0;
            dataptr[3] = t4 + t0;
            dataptr[5] = t5 - t1;
            dataptr[7] = t5 + t1;
          }

          inp += 2;
          inpcptr += 8;
          dataptr += 8;
      }

      dataptr = block;
      for (i=0; i<8; i++) {
          t4 = dataptr[0];
          t5 = dataptr[8];
          t0 = t4 - t5;
          t1 = t4 + t5;

          t4 = dataptr[16];
          t5 = dataptr[24];
          t2 = t0 - t4;
          t3 = t0 + t4;
          t4 = t1 - t5;
          t5 = t1 + t5;

          t0 = dataptr[32];
          t1 = dataptr[40];

          *p = SCLIMIT(t2 - t0) + 0x80;
          p += width / 2;
          *p = SCLIMIT(t2 + t0) + 0x80;
          p += width / 2;
          *p = SCLIMIT(t3 - t1) + 0x80;
          p += width / 2;
          *p = SCLIMIT(t3 + t1) + 0x80;
          p += width / 2;
          
          t0 = dataptr[48];
          t1 = dataptr[56];
          *p = SCLIMIT(t4 - t0) + 0x80;
          p += width / 2;
          *p = SCLIMIT(t4 + t0) + 0x80;
          p += width / 2;
          *p = SCLIMIT(t5 - t1) + 0x80;
          p += width / 2;
          *p = SCLIMIT(t5 + t1) + 0x80;
          p += width / 2;

          if (uswitch) {
                uswitch = 0;
                p = (signed char*)vp++;
          } else {
                uswitch = 1;
                p = (signed char*)up++;
          }
          dataptr++;
      }
    }
}

void NvDecoder::NVDCT_RevTransform(u_int* inp, u_char *yp,
                           char* up, char* vp, int width)
{
    int i, t, *dataptr;
    int a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3;
    int8_t *inpcptr=(int8_t *)inp;
    static int block[64];

    dataptr = block;
    for (i=0; i<8; i++) {
      if ((inp[0]|inp[1]) == 0) {
          dataptr[0] = dataptr[1] = dataptr[2] = dataptr[3] =
            dataptr[4] = dataptr[5] = dataptr[6] = dataptr[7] = 0;
      } else {
          b0 = inpcptr[0] << 4;
          b1 = inpcptr[4] << 4;
          b2 = inpcptr[2] << 4;
          b3 = inpcptr[6] << 4;

          a0 = (362 * (b0+b1)) >> 9;
          a1 = (362 * (b0-b1)) >> 9;
          a2 = (196*b2 - 473*b3) >> 9;
          a3 = (473*b2 + 196*b3) >> 9;

          b0 = a0+a3;
          b1 = a1+a2;
          b2 = a1-a2;
          b3 = a0-a3;

          a0 = inpcptr[1] << 4;
          a1 = inpcptr[3] << 4;
          a2 = inpcptr[5] << 4;
          a3 = inpcptr[7] << 4;

          c0 = (100*a0 - 502*a3) >> 9;
          c1 = (426*a2 - 284*a1) >> 9;
          c2 = (426*a1 + 284*a2) >> 9;
          c3 = (502*a0 + 100*a3) >> 9;

          a0 = c0+c1;
          a1 = c0-c1;
          a2 = c3-c2;
          a3 = c3+c2;

          c0 = a0;
          c1 = (362 * (a2-a1)) >> 9;
          c2 = (362 * (a1+a2)) >> 9;
          c3 = a3;

          dataptr[0] = b0+c3;
          dataptr[1] = b1+c2;
          dataptr[2] = b2+c1;
          dataptr[3] = b3+c0;
          dataptr[4] = b3-c0;
          dataptr[5] = b2-c1;
          dataptr[6] = b1-c2;
          dataptr[7] = b0-c3;
      }

      inp += 2;
      inpcptr += 8;
      dataptr += 8;
    }

    dataptr = block;
    for (i=0; i<8; i++) {
      b0 = dataptr[0]+1448; /* Add back DC offset */
      b1 = dataptr[32];
      b2 = dataptr[16];
      b3 = dataptr[48];

      a0 = (362 * (b0+b1)) >> 9;
      a1 = (362 * (b0-b1)) >> 9;
      a2 = (196*b2 - 473*b3) >> 9;
      a3 = (473*b2 + 196*b3) >> 9;

      b0 = a0+a3;
      b1 = a1+a2;
      b2 = a1-a2;
      b3 = a0-a3;

      a0 = dataptr[8];
      a1 = dataptr[24];
      a2 = dataptr[40];
      a3 = dataptr[56];

      c0 = (100*a0 - 502*a3) >> 9;
      c1 = (426*a2 - 284*a1) >> 9;
      c2 = (426*a1 + 284*a2) >> 9;
      c3 = (502*a0 + 100*a3) >> 9;

      a0 = c0+c1;
      a1 = c0-c1;
      a2 = c3-c2;
      a3 = c3+c2;

      c0 = a0;
      c1 = (362 * (a2-a1)) >> 9;
      c2 = (362 * (a2+a1)) >> 9;
      c3 = a3;

      yp[0]     = UCLIMIT((b0+c3+4) >> 3);
      yp[width] = UCLIMIT((b1+c2+4) >> 3);
      yp += 2*width;

      yp[0]     = UCLIMIT((b2+c1+4) >> 3);
      yp[width] = UCLIMIT((b3+c0+4) >> 3);
      yp += 2*width;

      yp[0]     = UCLIMIT((b3-c0+4) >> 3);
      yp[width] = UCLIMIT((b2-c1+4) >> 3);
      yp += 2*width;

      yp[0]     = UCLIMIT((b1-c2+4) >> 3);
      yp[width] = UCLIMIT((b0-c3+4) >> 3);
      yp -= 6*width;

      yp++;
      dataptr++;
    }

    if (up) {
      u_int8_t uvblk[64];
      u_int8_t* uvp = uvblk;
#define width 8
      dataptr = block;
      for (i=0; i<8; i++) {
          if ((inp[0]|inp[1]) == 0) {
            dataptr[0] = dataptr[1] = dataptr[2] = dataptr[3] =
                dataptr[4] = dataptr[5] = dataptr[6] = dataptr[7] = 0;
          } else {
            b0 = inpcptr[0] << 4;
            b2 = inpcptr[2] << 4;
            b1 = inpcptr[4] << 4;
            b3 = inpcptr[6] << 4;

            a0 = (362 * (b0+b1)) >> 9;
            a1 = (362 * (b0-b1)) >> 9;
            a2 = (196*b2 - 473*b3) >> 9;
            a3 = (473*b2 + 196*b3) >> 9;

            dataptr[0] = a0+a3;
            dataptr[2] = a1+a2;
            dataptr[4] = a1-a2;
            dataptr[6] = a0-a3;

            b0 = inpcptr[1] << 4;
            b2 = inpcptr[3] << 4;
            b1 = inpcptr[5] << 4;
            b3 = inpcptr[7] << 4;

            a0 = (362 * (b0+b1)) >> 9;
            a1 = (362 * (b0-b1)) >> 9;
            a2 = (196*b2 - 473*b3) >> 9;
            a3 = (473*b2 + 196*b3) >> 9;

            dataptr[1] = a0+a3;
            dataptr[3] = a1+a2;
            dataptr[5] = a1-a2;
            dataptr[7] = a0-a3;
          }

          inp += 2;
          inpcptr += 8;
          dataptr += 8;
      }

      dataptr = block;
      for (i=0; i<8; i++) {
          b0 = dataptr[0];
          b1 = dataptr[32];
          b2 = dataptr[16];
          b3 = dataptr[48];

          a0 = (362 * (b0+b1)) >> 9;
          a1 = (362 * (b0-b1)) >> 9;
          a2 = (196*b2 - 473*b3) >> 9;
          a3 = (473*b2 + 196*b3) >> 9;

          b0 = a0+a3;
          b1 = a1+a2;
          b2 = a1-a2;
          b3 = a0-a3;

          a0 = dataptr[8];
          a1 = dataptr[24];
          a2 = dataptr[40];
          a3 = dataptr[56];

          c0 = (100*a0 - 502*a3) >> 9;
          c1 = (426*a2 - 284*a1) >> 9;
          c2 = (426*a1 + 284*a2) >> 9;
          c3 = (502*a0 + 100*a3) >> 9;

          a0 = c0+c1;
          a1 = c0-c1;
          a2 = c3-c2;
          a3 = c3+c2;

          c0 = a0;
          c1 = (362 * (a2-a1)) >> 9;
          c2 = (362 * (a2+a1)) >> 9;
          c3 = a3;

          uvp[0]     = SCLIMIT((b0+c3+4) >> 3);
          uvp[width] = SCLIMIT((b1+c2+4) >> 3);
          uvp += 2*width;

          uvp[0]     = SCLIMIT((b2+c1+4) >> 3);
          uvp[width] = SCLIMIT((b3+c0+4) >> 3);
          uvp += 2*width;

          uvp[0]     = SCLIMIT((b3-c0+4) >> 3);
          uvp[width] = SCLIMIT((b2-c1+4) >> 3);
          uvp += 2*width;

          uvp[0]     = SCLIMIT((b1-c2+4) >> 3);
          uvp[width] = SCLIMIT((b0-c3+4) >> 3);
          uvp -= 6*width;

          uvp++;
          dataptr++;
      }
#undef width
      uvp = uvblk;
      for (i = 0; i < 8; ++i) {
            up[0] = uvp[0] + 0x80;
            vp[0] = uvp[1] + 0x80;
            up[1] = uvp[2] + 0x80;
            vp[1] = uvp[3] + 0x80;
            up[2] = uvp[4] + 0x80;
            vp[2] = uvp[5] + 0x80;
            up[3] = uvp[6] + 0x80;
            vp[3] = uvp[7] + 0x80;
            up += width >> 1;
            vp += width >> 1;
            uvp += 8;
      }
    }
}

#define VIDCODE_COLORFLAG 0x8000
#define VIDCODE_WIDTHMASK 0x0fff

const u_char* NvDecoder::decode_run(const u_char* data, const u_char* end,
                            int color)
{
      if (end - data < 3)
            return (end);

      int w0, w;
      w0 = w = *data++;
      int x0 = *data++;
      int y0 = *data++;

      int inw = inw_;
      int inh = inh_;
      if ((x0+w > inw/8) || (y0 >= inh/8)) {
            count(STAT_BAD_COORD);
#ifdef notdef
            fprintf(stderr, "vic: bogus offset in nv stream (%d,%d)\n",
                  x0 + w, y0);
#endif
            return (end);
      }

      int offset = y0 * inw;
      u_char* ts = &rvts_[(offset >> 3) + x0];
      offset = (offset << 3) + (x0 << 3);
      u_char* yp = &frm_[offset];
      int s = inw * inh;/*XXX*/
      u_char* up = frm_ + s + (offset >> 1);
      u_char* vp = up + (s >> 1);
      while (w-- > 0) {
            if (data >= end) {
                  count(STAT_BAD_BLKRUN);
                  return (end);
            }
            static u_int block[32];
            int lim=color? 128 : 64;
            for (int i=0; i<lim; ) {
                  int run = *data++;
                  int j = run >> 6;
                  int k = run & 0x3f;
                  if (i+j+k > lim) {
#ifdef notdef
                        fprintf(stderr,
                  "vic: bogus run length in nv stream (%d %d %d %d %d)\n",
                              i, j, k, lim, end - data);
#endif
                        count(STAT_BAD_RUNLEN);
                        return (end);
                  }
                  char* blkp = (char*)block;
                  while (j--) blkp[i++] = (char) *data++;
                  while (k--) blkp[i++] = 0;
                  ndblk_++;
            }
            if (use_dct_)
                  NVDCT_RevTransform(block, yp, (char*)up, (char*)vp,
                                 inw);
            else
                  VidTransform_Rev(block, yp, (char*)up, (char*)vp, inw);
            
            yp += 8;
            if (up) {
                  up += 4;
                  vp += 4;
            }
            *ts++ = now_;
      }
      return (data);
}

void NvDecoder::recv(pktbuf* pb)
{
      rtphdr* rh = (rtphdr*)pb->dp;
      const nvhdr* ph = (nvhdr*)(rh + 1);
      int h = ntohs(ph->height);
      int w = ntohs(ph->width);
      int color = w >> 15;
      w &= 0xfff;
      int fmt = h >> 12;
      h &= 0xfff;
      if (fmt == 0)
            use_dct_ = 0;
      else if (fmt == 1)
            use_dct_ = 1;
      else
            count(STAT_BAD_ENC);
#ifdef notyet
      if (color != color_)
            /*XXX should do this by invoking tcl command */
            setcolor(color);
#endif
      if (w != inw_ || h != inh_) {
            if ((unsigned)w > 1000 || (unsigned)h > 1000) {
                  /*XXX*/
                  w = 320;
                  h = 240;
                  count(STAT_BAD_GEOM);
            }
            resize(w, h);
      }
      const u_int8_t* end = &pb->dp[pb->len];
      const u_int8_t* bp = (u_int8_t*)(ph + 1);
      while (bp < end)
            bp = decode_run(bp, end, color);

      if (ntohs(rh->rh_flags) & RTP_M) {
            render_frame(frm_);
            resetndblk();
      }
      pb->release();
}

Generated by  Doxygen 1.6.0   Back to index