[Sumover-dev] [svn commit] r3795 - in vic/trunk: . codec codec/p64
tcl
sumover-dev at cs.ucl.ac.uk
sumover-dev at cs.ucl.ac.uk
Tue Aug 22 02:06:08 BST 2006
Author: rhys
Date: Tue Aug 22 02:04:58 2006
New Revision: 3795
Added:
vic/trunk/codec/decoder-h261as.cpp
vic/trunk/codec/encoder-h261as.cpp
vic/trunk/codec/p64/p64as.cpp
vic/trunk/codec/p64/p64as.h
Modified:
vic/trunk/configure
vic/trunk/configure.in
vic/trunk/rtp/rtp.h
vic/trunk/rtp/session.cpp
vic/trunk/tcl/cf-main.tcl
Log:
Added support for h261as decoding. Enable using ./configure
--enable-h261as
Added: vic/trunk/codec/decoder-h261as.cpp
==============================================================================
--- (empty file)
+++ vic/trunk/codec/decoder-h261as.cpp Tue Aug 22 02:04:58 2006
@@ -0,0 +1,223 @@
+/*-
+ * 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.
+ */
+static const char rcsid[] =
+ "@(#) $Header$ (LBL)";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "inet.h"
+#include "rtp.h"
+#include "decoder.h"
+#include "renderer.h"
+#include "p64/p64as.h"
+
+class H261ASDecoder : public Decoder {
+ public:
+ H261ASDecoder();
+ virtual ~H261ASDecoder();
+ virtual void info(char* wrk) const;
+ virtual void recv(pktbuf*);
+ int colorhist(u_int* hist) const;
+ virtual void stats(char* wrk);
+ protected:
+ void decode(const u_char* vh, const u_char* bp, int cc);
+ virtual void redraw();
+ P64ASDecoder* codec_;
+};
+
+static class H261ASDecoderMatcher : public Matcher {
+ public:
+ H261ASDecoderMatcher() : Matcher("decoder") {}
+ TclObject* match(const char* id) {
+ if (strcasecmp(id, "h.261as") == 0 ||
+ strcasecmp(id, "h261as") == 0)
+ return (new H261ASDecoder());
+ return (0);
+ }
+} dm_h261as;
+
+#define STAT_BAD_PSC 0
+#define STAT_BAD_GOB 1
+#define STAT_BAD_SYNTAX 2
+#define STAT_BAD_FMT 3
+#define STAT_FMT_CHANGE 4 /* # times fmt changed */
+#define STAT_BAD_HEADER 5
+
+
+H261ASDecoder::H261ASDecoder() : Decoder(4), codec_(0)
+{
+ stat_[STAT_BAD_PSC].name = "H261AS-Bad-PSC";
+ stat_[STAT_BAD_GOB].name = "H261AS-Bad-GOB";
+ stat_[STAT_BAD_SYNTAX].name = "H261AS-Bad-Syntax";
+ stat_[STAT_BAD_FMT].name = "H261AS-Bad-fmt";
+ stat_[STAT_FMT_CHANGE].name = "H261AS-Fmt-change";
+ stat_[STAT_BAD_HEADER].name = "H261AS-Bad-Header";
+ nstat_ = 6;
+
+ decimation_ = 411;
+ /*
+ * Assume CIF. Picture header will trigger a resize if
+ * we encounter QCIF instead.
+ */
+ inw_ = 352;
+ inh_ = 288;
+
+ /*XXX*/
+ resize(inw_, inh_);
+}
+
+H261ASDecoder::~H261ASDecoder()
+{
+ delete codec_;
+}
+
+void H261ASDecoder::info(char* wrk) const
+{
+ if (codec_ == 0)
+ *wrk = 0;
+ else
+ sprintf(wrk, "[q=%d]", codec_->gobquant());
+}
+
+void H261ASDecoder::stats(char* wrk)
+{
+ /* pull stats out of vic indepdendent P64Decoder */
+ setstat(STAT_BAD_PSC, codec_->bad_psc());
+ setstat(STAT_BAD_GOB, codec_->bad_GOBno());
+ setstat(STAT_BAD_SYNTAX, codec_->bad_bits());
+ setstat(STAT_BAD_FMT, codec_->bad_fmt());
+ Decoder::stats(wrk);
+}
+
+int H261ASDecoder::colorhist(u_int* hist) const
+{
+ const u_char* frm = codec_->frame();
+ int w = inw_;
+ int h = inh_;
+ int s = w * h;
+ colorhist_411_556(hist, frm, frm + s, frm + s + (s >> 2), w, h);
+ return (1);
+}
+
+
+#ifdef CR_STATS
+u_char shadow[640*480/64];
+
+void dumpShadow(u_int32_t ts, u_char* p, int nblk)
+{
+ ts &= 0x7fffffff;
+ static u_int32_t lastTS = 0;
+ if (ts != lastTS) {
+ printf("ts %u\n", ts);
+ lastTS = ts;
+ }
+ int left = -1;
+ for (int i = 0; i < nblk; ++i) {
+ if (shadow[i] != p[i]) {
+ if (left < 0) {
+ left = i;
+ }
+ } else {
+ if (left > 0)
+ printf("b %d %d\n", left, i - 1);
+ left = -1;
+ }
+ }
+ if (left > 0)
+ printf("b %d %d\n", left, i - 1);
+}
+#endif
+
+void H261ASDecoder::recv(pktbuf* pb)
+{
+ rtphdr* rh = (rtphdr*)pb->dp;
+ u_int8_t* vh = (u_int8_t*)(rh + 1);
+ if (codec_ == 0) {
+ codec_ = new P64ASDecoder();
+ codec_->marks(rvts_);
+ }
+#ifdef CR_STATS
+ memcpy(shadow, rvts_, nblk_);
+#endif
+ /*
+ * h261as header is as follows:
+ * ebit 3
+ * quant 5
+ * width 12
+ * height 12
+ */
+ u_int v = ntohl(*(u_int32_t*)vh);
+ int ebit = v >> 29;
+ int quant = (v >> 24) & 0x1f;
+ int pwidth = (v >> 12) & 0x7ff;
+ int pheight = v & 0x7ff;
+
+ int cc = pb->len - (sizeof(*rh) + 4);
+
+ pwidth = (pwidth + 1) * 16;
+ pheight = (pheight + 1) * 16;
+
+ /*
+ * If the stream changes format, issue a resize.
+ */
+ if (pwidth != codec_->width() ||
+ pheight != codec_->height()) {
+ codec_->set_size(pwidth, pheight);
+ resize(codec_->width(), codec_->height());
+ codec_->marks(rvts_);
+ count(STAT_FMT_CHANGE);
+ }
+
+ codec_->mark(now_);
+ (void)codec_->decode(vh + 4, cc, ebit, quant);
+
+#ifdef CR_STATS
+ dumpShadow(ntohl(rh->rh_ts), rvts_, nblk_);
+#endif
+ /*XXX*/
+ if (ntohs(rh->rh_flags) & RTP_M) {
+ codec_->sync();
+ ndblk_ = codec_->ndblk();
+ render_frame(codec_->frame());
+ codec_->resetndblk();
+ }
+ pb->release();
+}
+
+void H261ASDecoder::redraw()
+{
+ if (codec_ != 0)
+ Decoder::redraw(codec_->frame());
+}
Added: vic/trunk/codec/encoder-h261as.cpp
==============================================================================
--- (empty file)
+++ vic/trunk/codec/encoder-h261as.cpp Tue Aug 22 02:04:58 2006
@@ -0,0 +1,877 @@
+/*
+ * Copyright (c) 1994-1995 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.
+ */
+static const char rcsid[] =
+ "@(#) $Header$ (LBL)";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "inet.h"
+#include "net.h"
+#include "rtp.h"
+#include "dct.h"
+#include "p64/p64-huff.h"
+#include "bsd-endian.h"
+#include "vic_tcl.h"
+#include "crdef.h"
+#include "transmitter.h"
+#include "pktbuf-rtp.h"
+#include "module.h"
+
+#define HDRSIZE (sizeof(rtphdr) + 4)
+#define CIF_WIDTH 352
+#define CIF_HEIGHT 288
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 144
+#define BMB 6 /* # blocks in a MB */
+#define MBPERGOB 33 /* # of Macroblocks per GOB */
+
+#ifdef INT_64
+#define NBIT 64
+#define BB_INT INT_64
+#else
+#define NBIT 32
+#define BB_INT u_int
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#if NBIT == 64
+#define STORE_BITS(bb, bc) \
+ bc[0] = bb >> 56; \
+ bc[1] = bb >> 48; \
+ bc[2] = bb >> 40; \
+ bc[3] = bb >> 32; \
+ bc[4] = bb >> 24; \
+ bc[5] = bb >> 16; \
+ bc[6] = bb >> 8; \
+ bc[7] = bb;
+#define LOAD_BITS(bc) \
+ ((BB_INT)bc[0] << 56 | \
+ (BB_INT)bc[1] << 48 | \
+ (BB_INT)bc[2] << 40 | \
+ (BB_INT)bc[3] << 32 | \
+ (BB_INT)bc[4] << 24 | \
+ (BB_INT)bc[5] << 16 | \
+ (BB_INT)bc[6] << 8 | \
+ (BB_INT)bc[7])
+#else
+#define STORE_BITS(bb, bc) \
+ bc[0] = bb >> 24; \
+ bc[1] = bb >> 16; \
+ bc[2] = bb >> 8; \
+ bc[3] = bb;
+#define LOAD_BITS(bc) (ntohl(*(BB_INT*)(bc)))
+#endif
+#else
+#define STORE_BITS(bb, bc) *(BB_INT*)bc = (bb);
+#define LOAD_BITS(bc) (*(BB_INT*)(bc))
+#endif
+
+#define PUT_BITS(bits, n, nbb, bb, bc) \
+{ \
+ nbb += (n); \
+ if (nbb > NBIT) { \
+ u_int extra = (nbb) - NBIT; \
+ bb |= (BB_INT)(bits) >> extra; \
+ STORE_BITS(bb, bc) \
+ bc += sizeof(BB_INT); \
+ bb = (BB_INT)(bits) << (NBIT - extra); \
+ nbb = extra; \
+ } else \
+ bb |= (BB_INT)(bits) << (NBIT - (nbb)); \
+}
+
+
+class H261ASEncoder : public TransmitterModule {
+ public:
+ void setq(int q);
+ protected:
+ H261ASEncoder(int ft);
+ ~H261ASEncoder();
+ int encode(const VideoFrame*, const u_int8_t *crvec);
+ int command(int argc, const char*const* argv);
+ void encode_blk(const short* blk, const char* lm);
+ int flush(pktbuf* pb, int nbit, pktbuf* npb);
+ char* make_level_map(int q, u_int fthresh);
+ void setquantizers(int lq, int mq, int hq);
+
+ virtual void size(int w, int h) = 0;
+ virtual void encode_mb(u_int mba, const u_char* frm,
+ u_int loff, u_int coff, int how) = 0;
+
+ /* bit buffer */
+ BB_INT bb_;
+ u_int nbb_;
+
+ u_char* bs_;
+ u_char* bc_;
+ int sbit_;
+
+ u_char lq_; /* low quality quantizer */
+ u_char mq_; /* medium quality quantizer */
+ u_char hq_; /* high quality quantizer */
+ u_char mquant_; /* the last quantizer we sent to other side */
+ int quant_required_; /* 1 if not quant'd in dct */
+ u_int ngob_;
+ u_int mba_;
+
+ u_int cif_; /* 1 for CIF, 0 for QCIF */
+ u_int bstride_;
+ u_int lstride_;
+ u_int cstride_;
+
+ u_int loffsize_; /* amount of 1 luma block */
+ u_int coffsize_; /* amount of 1 chroma block */
+ u_int bloffsize_; /* amount of 1 block advance */
+
+ const char* llm_[32]; /* luma dct val -> level maps */
+ const char* clm_[32]; /* chroma dct val -> level maps */
+
+ float lqt_[64]; /* low quality quantizer */
+ float mqt_[64]; /* medium quality quantizer */
+ float hqt_[64]; /* high quality quantizer */
+
+ u_int coff_[12]; /* where to find U given gob# */
+ u_int loff_[12]; /* where to find Y given gob# */
+ u_int blkno_[12]; /* for CR */
+};
+
+class H261ASDCTEncoder : public H261ASEncoder {
+ public:
+ H261ASDCTEncoder();
+ int consume(const VideoFrame*);
+ void size(int w, int h);
+ protected:
+ void encode_mb(u_int mba, const u_char* frm,
+ u_int loff, u_int coff, int how);
+};
+
+class H261ASPixelEncoder : public H261ASEncoder {
+ public:
+ H261ASPixelEncoder();
+ int consume(const VideoFrame*);
+ void size(int w, int h);
+ protected:
+ void encode_mb(u_int mba, const u_char* frm,
+ u_int loff, u_int coff, int how);
+};
+
+static class H261ASEncoderMatcher : public Matcher {
+ public:
+ H261ASEncoderMatcher() : Matcher("module") {}
+ TclObject* match(const char* fmt) {
+ if (strcasecmp(fmt, "h261as/pixel") == 0)
+ return (new H261ASPixelEncoder);
+ if (strcasecmp(fmt, "h261as/dct") == 0)
+ return (new H261ASDCTEncoder);
+ /* XXX for now, this is compatible with ui-ctrlmenu.tcl */
+ if (strcasecmp(fmt, "h261as") == 0)
+ return (new H261ASPixelEncoder);
+ return (0);
+ }
+} encoder_matcher_h261as;
+
+
+H261ASEncoder::H261ASEncoder(int ft) : TransmitterModule(ft),
+ bs_(0), bc_(0), ngob_(12)
+{
+ for (int q = 0; q < 32; ++q) {
+ llm_[q] = 0;
+ clm_[q] = 0;
+ }
+}
+
+H261ASEncoder::~H261ASEncoder()
+{
+ for (int q = 0; q < 32; ++q) {
+ if (llm_[q] != 0)
+ delete llm_[q]; //SV-XXX: Debian
+ if (clm_[q] != 0)
+ delete clm_[q]; //SV-XXX: Debian
+ }
+}
+
+H261ASPixelEncoder::H261ASPixelEncoder() : H261ASEncoder(FT_YUV_CIF)
+{
+ quant_required_ = 0;
+ setq(10);
+}
+
+H261ASDCTEncoder::H261ASDCTEncoder() : H261ASEncoder(FT_DCT)
+{
+ quant_required_ = 1;
+ setq(10);
+}
+
+/*
+ * Set up the forward DCT quantization table for
+ * INTRA mode operation.
+ */
+void
+H261ASEncoder::setquantizers(int lq, int mq, int hq)
+{
+ int qt[64];
+ if (lq > 31)
+ lq = 31;
+ if (lq <= 0)
+ lq = 1;
+ lq_ = lq;
+
+ if (mq > 31)
+ mq = 31;
+ if (mq <= 0)
+ mq = 1;
+ mq_ = mq;
+
+ if (hq > 31)
+ hq = 31;
+ if (hq <= 0)
+ hq = 1;
+ hq_ = hq;
+
+ /*
+ * quant_required_ indicates quantization is not folded
+ * into fdct [because fdct is not performed]
+ */
+ if (quant_required_ == 0) {
+ /*
+ * Set the DC quantizer to 1, since we want to do this
+ * coefficient differently (i.e., the DC is rounded while
+ * the AC terms are truncated).
+ */
+ qt[0] = 1;
+ int i;
+ for (i = 1; i < 64; ++i)
+ qt[i] = lq_ << 1;
+ fdct_fold_q(qt, lqt_);
+
+ qt[0] = 1;
+ for (i = 1; i < 64; ++i)
+ qt[i] = mq_ << 1;
+ fdct_fold_q(qt, mqt_);
+
+ qt[0] = 1;
+ for (i = 1; i < 64; ++i)
+ qt[i] = hq_ << 1;
+ fdct_fold_q(qt, hqt_);
+ }
+}
+
+void
+H261ASEncoder::setq(int q)
+{
+ setquantizers(q, q / 2, 1);
+}
+
+void
+H261ASPixelEncoder::size(int w, int h)
+{
+ Module::size(w, h);
+ if (w == CIF_WIDTH && h == CIF_HEIGHT) {
+ /* CIF */
+ cif_ = 1;
+ ngob_ = 12;
+ bstride_ = 11;
+ lstride_ = 16 * CIF_WIDTH - CIF_WIDTH / 2;
+ cstride_ = 8 * 176 - 176 / 2;
+ loffsize_ = 16;
+ coffsize_ = 8;
+ bloffsize_ = 1;
+ } else if (w == QCIF_WIDTH && h == QCIF_HEIGHT) {
+ /* QCIF */
+ cif_ = 0;
+ ngob_ = 6; /* not really number of GOBs, just loop limit */
+ bstride_ = 0;
+ lstride_ = 16 * QCIF_WIDTH - QCIF_WIDTH;
+ cstride_ = 8 * 88 - 88;
+ loffsize_ = 16;
+ coffsize_ = 8;
+ bloffsize_ = 1;
+ } else {
+ /*XXX*/
+ fprintf(stderr, "H261ASPixelEncoder: H.261 bad geometry: %dx%d\n",
+ w, h);
+ exit(1);
+ }
+ u_int loff = 0;
+ u_int coff = 0;
+ u_int blkno = 0;
+ for (u_int gob = 0; gob < ngob_; gob += 2) {
+ loff_[gob] = loff;
+ coff_[gob] = coff;
+ blkno_[gob] = blkno;
+ /* width of a GOB (these aren't ref'd in QCIF case) */
+ loff_[gob + 1] = loff + 11 * 16;
+ coff_[gob + 1] = coff + 11 * 8;
+ blkno_[gob + 1] = blkno + 11;
+
+ /* advance to next GOB row */
+ loff += (16 * 16 * MBPERGOB) << cif_;
+ coff += (8 * 8 * MBPERGOB) << cif_;
+ blkno += MBPERGOB << cif_;
+ }
+}
+
+void
+H261ASDCTEncoder::size(int w, int h)
+{
+
+ Module::size(w, h);
+ if (w == CIF_WIDTH && h == CIF_HEIGHT) {
+ /* CIF */
+ cif_ = 1;
+ ngob_ = 12;
+ bstride_ = 11;
+ lstride_ = - (11 * (64*BMB)) + 2 * 11 * 64 * BMB;
+ cstride_ = - (11 * (64*BMB)) + 2 * 11 * 64 * BMB;
+ loffsize_ = 64 * BMB;
+ coffsize_ = 64 * BMB;
+ bloffsize_ = 1;
+ } else if (w == QCIF_WIDTH && h == QCIF_HEIGHT) {
+ /* QCIF */
+ cif_ = 0;
+ ngob_ = 6; /* not really number of GOBs, just loop limit */
+ bstride_ = 0;
+ lstride_ = 0;
+ cstride_ = 0;
+ loffsize_ = 64 * BMB;
+ coffsize_ = 64 * BMB;
+ bloffsize_ = 1;
+ } else {
+ /*XXX*/
+ fprintf(stderr, "H261ASDCTEncoder: H.261 bad geometry: %dx%d\n",
+ w, h);
+ exit(1);
+ }
+
+ u_int gob;
+ for (gob = 0; gob < ngob_; gob += 2) {
+
+ if (gob != 0) {
+ loff_[gob] = loff_[gob-2] +
+ (MBPERGOB << cif_) * BMB * 64;
+ coff_[gob] = coff_[gob-2] +
+ (MBPERGOB << cif_) * BMB * 64;
+ blkno_[gob] = blkno_[gob-2] +
+ (MBPERGOB << cif_);
+ } else {
+ loff_[0] = 0;
+ coff_[0] = loff_[0] + 4 * 64; // 4 Y's
+ blkno_[0] = 0;
+ }
+
+ loff_[gob + 1] = loff_[gob] + 11 * BMB * 64;
+ coff_[gob + 1] = coff_[gob] + 11 * BMB * 64;
+ blkno_[gob + 1] = blkno_[gob] + 11;
+ }
+}
+
+
+int
+H261ASEncoder::command(int argc, const char*const* argv)
+{
+ if (argc == 3 && strcmp(argv[1], "q") == 0) {
+ setq(atoi(argv[2]));
+ return (TCL_OK);
+ }
+ return (TransmitterModule::command(argc, argv));
+}
+
+/*
+ * Make a map to go from a 12 bit dct value to an 8 bit quantized
+ * 'level' number. The 'map' includes both the quantizer (for the
+ * dct encoder) and the perceptual filter 'threshhold' (for both
+ * the pixel & dct encoders). The first 4k of the map is for the
+ * unfiltered coeff (the first 20 in zigzag order; roughly the
+ * upper left quadrant) and the next 4k of the map are for the
+ * filtered coef.
+ */
+char*
+H261ASEncoder::make_level_map(int q, u_int fthresh)
+{
+ /* make the luminance map */
+ char* lm = new char[0x2000];
+ char* flm = lm + 0x1000;
+ int i;
+ lm[0] = 0;
+ flm[0] = 0;
+ q = quant_required_? q << 1 : 0;
+ for (i = 1; i < 0x800; ++i) {
+ int l = i;
+ if (q)
+ l /= q;
+ lm[i] = l;
+ lm[-i & 0xfff] = -l;
+
+ if ((u_int)l <= fthresh)
+ l = 0;
+ flm[i] = l;
+ flm[-i & 0xfff] = -l;
+ }
+ return (lm);
+}
+
+/*
+ * encode_blk:
+ * encode a block of DCT coef's
+ */
+void
+H261ASEncoder::encode_blk(const short* blk, const char* lm)
+{
+ BB_INT bb = bb_;
+ u_int nbb = nbb_;
+ u_char* bc = bc_;
+
+ /*
+ * Quantize DC. Round instead of truncate.
+ */
+ int dc = (blk[0] + 4) >> 3;
+
+ if (dc <= 0)
+ /* shouldn't happen with CCIR 601 black (level 16) */
+ dc = 1;
+ else if (dc > 254)
+ dc = 254;
+ else if (dc == 128)
+ /* per Table 6/H.261 */
+ dc = 255;
+ /* Code DC */
+ PUT_BITS(dc, 8, nbb, bb, bc);
+ int run = 0;
+ const u_char* colzag = &COLZAG[0];
+ for (int zag; (zag = *++colzag) != 0; ) {
+ if (colzag == &COLZAG[20])
+ lm += 0x1000;
+ int level = lm[((const u_short*)blk)[zag] & 0xfff];
+ if (level != 0) {
+ int val, nb;
+ huffent* he;
+ if (u_int(level + 15) <= 30 &&
+ (nb = (he = &hte_tc[((level&0x1f) << 6)|run])->nb))
+ /* we can use a VLC. */
+ val = he->val;
+ else {
+ /* Can't use a VLC. Escape it. */
+ val = (1 << 14) | (run << 8) | (level & 0xff);
+ nb = 20;
+ }
+ PUT_BITS(val, nb, nbb, bb, bc);
+ run = 0;
+ } else
+ ++run;
+ }
+ /* EOB */
+ PUT_BITS(2, 2, nbb, bb, bc);
+
+ bb_ = bb;
+ nbb_ = nbb;
+ bc_ = bc;
+}
+
+/*
+ * H261ASPixelEncoder::encode_mb
+ * encode a macroblock given a set of input YUV pixels
+ */
+void
+H261ASPixelEncoder::encode_mb(u_int mba, const u_char* frm,
+ u_int loff, u_int coff, int how)
+{
+ register int q;
+ float* qt;
+ if (how == CR_MOTION) {
+ q = lq_;
+ qt = lqt_;
+ } else if (how == CR_BG) {
+ q = hq_;
+ qt = hqt_;
+ } else {
+ /* must be at age threshold */
+ q = mq_;
+ qt = mqt_;
+ }
+
+ /*
+ * encode all 6 blocks of the macro block to find the largest
+ * coef (so we can pick a new quantizer if gquant doesn't have
+ * enough range).
+ */
+ /*XXX this can be u_char instead of short but need smarts in fdct */
+ short blk[64 * 6];
+ register int stride = width_;
+ /* luminance */
+ const u_char* p = &frm[loff];
+ fdct(p, stride, blk + 0, qt);
+ fdct(p + 8, stride, blk + 64, qt);
+ fdct(p + 8 * stride, stride, blk + 128, qt);
+ fdct(p + (8 * stride + 8), stride, blk + 192, qt);
+ /* chominance */
+ int fs = framesize_;
+ p = &frm[fs + coff];
+ stride >>= 1;
+ fdct(p, stride, blk + 256, qt);
+ fdct(p + (fs >> 2), stride, blk + 320, qt);
+
+ /*
+ * if the default quantizer is too small to handle the coef.
+ * dynamic range, spin through the blocks and see if any
+ * coef. would significantly overflow.
+ */
+ if (q < 8) {
+ register int cmin = 0, cmax = 0;
+ register short* bp = blk;
+ for (register int i = 6; --i >= 0; ) {
+ ++bp; // ignore dc coef
+ for (register int j = 63; --j >= 0; ) {
+ register int v = *bp++;
+ if (v < cmin)
+ cmin = v;
+ else if (v > cmax)
+ cmax = v;
+ }
+ }
+ if (cmax < -cmin)
+ cmax = -cmin;
+ if (cmax >= 128) {
+ /* need to re-quantize */
+ register int s;
+ for (s = 1; cmax >= (128 << s); ++s) {
+ }
+ q <<= s;
+ register short* bp = blk;
+ for (register int i = 6; --i >= 0; ) {
+ ++bp; // ignore dc coef
+ for (register int j = 63; --j >= 0; ) {
+ register int v = *bp;
+ *bp++ = v >> s;
+ }
+ }
+ }
+ }
+
+ u_int m = mba - mba_;
+ mba_ = mba;
+ huffent* he = &hte_mba[m - 1];
+ /* MBA */
+ PUT_BITS(he->val, he->nb, nbb_, bb_, bc_);
+ if (q != mquant_) {
+ /* MTYPE = INTRA + TC + MQUANT */
+ PUT_BITS(1, 7, nbb_, bb_, bc_);
+ PUT_BITS(q, 5, nbb_, bb_, bc_);
+ mquant_ = q;
+ } else {
+ /* MTYPE = INTRA + TC (no quantizer) */
+ PUT_BITS(1, 4, nbb_, bb_, bc_);
+ }
+
+ /* luminance */
+ const char* lm = llm_[q];
+ if (lm == 0) {
+ lm = make_level_map(q, 1);
+ llm_[q] = lm;
+ clm_[q] = make_level_map(q, 2);
+ }
+ encode_blk(blk + 0, lm);
+ encode_blk(blk + 64, lm);
+ encode_blk(blk + 128, lm);
+ encode_blk(blk + 192, lm);
+ /* chominance */
+ lm = clm_[q];
+ encode_blk(blk + 256, lm);
+ encode_blk(blk + 320, lm);
+}
+
+
+/*
+ * H261ASDCTEncoder::encode_mb
+ * encode a macroblock given a set of input DCT coefs
+ * each coef is stored as a short
+ */
+void
+H261ASDCTEncoder::encode_mb(u_int mba, const u_char* frm,
+ u_int loff, u_int coff, int how)
+{
+ short *lblk = (short *)frm + loff;
+ short *ublk = (short *)frm + coff;
+ short *vblk = (short *)frm + coff + 64;
+
+ register u_int q;
+ if (how == CR_MOTION)
+ q = lq_;
+ else if (how == CR_BG)
+ q = hq_;
+ else
+ /* must be at age threshold */
+ q = mq_;
+
+ /*
+ * if the default quantizer is too small to handle the coef.
+ * dynamic range, spin through the blocks and see if any
+ * coef. would significantly overflow.
+ */
+ if (q < 8) {
+ register int cmin = 0, cmax = 0;
+ register short* bp = lblk;
+ register int i, j;
+
+ // Y U and V blocks
+ for (i = 6; --i >= 0; ) {
+ ++bp; // ignore dc coef
+ for (j = 63; --j >= 0; ) {
+ register int v = *bp++;
+ if (v < cmin)
+ cmin = v;
+ else if (v > cmax)
+ cmax = v;
+ }
+ }
+
+ if (cmax < -cmin)
+ cmax = -cmin;
+ cmax /= (q << 1);
+ if (cmax >= 128) {
+ /* need to re-quantize */
+ register int s;
+
+ for (s = 1; cmax >= (128 << s); ++s) {
+ }
+ q <<= s;
+
+ }
+ }
+
+ u_int m = mba - mba_;
+ mba_ = mba;
+ huffent* he = &hte_mba[m - 1];
+ /* MBA */
+ PUT_BITS(he->val, he->nb, nbb_, bb_, bc_);
+ if (q != mquant_) {
+ /* MTYPE = INTRA + TC + MQUANT */
+ PUT_BITS(1, 7, nbb_, bb_, bc_);
+ PUT_BITS(q, 5, nbb_, bb_, bc_);
+ mquant_ = q;
+ } else {
+ /* MTYPE = INTRA + TC (no quantizer) */
+ PUT_BITS(1, 4, nbb_, bb_, bc_);
+ }
+
+ /* luminance */
+ const char* lm = llm_[q];
+ if (lm == 0) {
+ /*
+ * the filter thresh is 0 since we assume the jpeg percept.
+ * quantizer already did the filtering.
+ */
+ lm = make_level_map(q, 0);
+ llm_[q] = lm;
+ clm_[q] = make_level_map(q, 0);
+ }
+ encode_blk(lblk + 0, lm);
+ encode_blk(lblk + 64, lm);
+ encode_blk(lblk + 128, lm);
+ encode_blk(lblk + 192, lm);
+ /* chominance */
+ lm = clm_[q];
+ encode_blk(ublk, lm);
+ encode_blk(vblk, lm);
+}
+
+int
+H261ASEncoder::flush(pktbuf* pb, int nbit, pktbuf* npb)
+{
+ /* flush bit buffer */
+ STORE_BITS(bb_, bc_);
+
+ int cc = (nbit + 7) >> 3;
+ int ebit = (cc << 3) - nbit;
+
+ /*XXX*/
+ if (cc == 0 && npb != 0)
+ abort();
+
+ pb->len = cc + HDRSIZE;
+ rtphdr* rh = (rtphdr*)pb->data;
+ if (npb == 0)
+ rh->rh_flags |= htons(RTP_M);
+
+ int h = *(u_int*)(rh + 1) | ebit << 26 | sbit_ << 29;
+ *(u_int*)(rh + 1) = htonl(h);
+
+ if (npb != 0) {
+ u_char* nbs = &npb->data[HDRSIZE];
+ u_int bc = (bc_ - bs_) << 3;
+ int tbit = bc + nbb_;
+ int extra = ((tbit + 7) >> 3) - (nbit >> 3);
+ if (extra > 0)
+ memcpy(nbs, bs_ + (nbit >> 3), extra);
+ bs_ = nbs;
+ sbit_ = nbit & 7;
+ tbit -= nbit &~ 7;
+ bc = tbit &~ (NBIT - 1);
+ nbb_ = tbit - bc;
+ bc_ = bs_ + (bc >> 3);
+ /*
+ * Prime the bit buffer. Be careful to set bits that
+ * are not yet in use to 0, since output bits are later
+ * or'd into the buffer.
+ */
+ if (nbb_ > 0) {
+ u_int n = NBIT - nbb_;
+ bb_ = (LOAD_BITS(bc_) >> n) << n;
+ } else
+ bb_ = 0;
+ }
+ tx_->send(pb);
+
+ return (cc + HDRSIZE);
+}
+
+int H261ASDCTEncoder::consume(const VideoFrame *vf)
+{
+ if (!samesize(vf))
+ size(vf->width_, vf->height_);
+
+ DCTFrame* df = (DCTFrame *)vf;
+
+ return(encode(df, df->crvec_));
+}
+
+int H261ASPixelEncoder::consume(const VideoFrame *vf)
+{
+ if (!samesize(vf))
+ size(vf->width_, vf->height_);
+
+ YuvFrame* p = (YuvFrame*)vf;
+ return(encode(p, p->crvec_));
+}
+
+
+int
+H261ASEncoder::encode(const VideoFrame* vf, const u_int8_t *crvec)
+{
+ tx_->flush();
+
+ pktbuf* pb = pool_->alloc(vf->ts_, RTP_PT_H261);
+ bs_ = &pb->data[HDRSIZE];
+ bc_ = bs_;
+ u_int ec = (tx_->mtu() - HDRSIZE) << 3;
+ bb_ = 0;
+ nbb_ = 0;
+ sbit_ = 0;
+ /* RTP/H.261 header */
+ rtphdr* rh = (rtphdr*)pb->data;
+ *(u_int*)(rh + 1) = 1 << 25 | lq_ << 10;
+
+ /* PSC */
+ PUT_BITS(0x0001, 16, nbb_, bb_, bc_);
+ /* GOB 0 -> picture header */
+ PUT_BITS(0, 4, nbb_, bb_, bc_);
+ /* TR (XXX should do this right) */
+ PUT_BITS(0, 5, nbb_, bb_, bc_);
+ /* PTYPE = CIF */
+ int pt = cif_ ? 4 : 0;
+ PUT_BITS(pt, 6, nbb_, bb_, bc_);
+ /* PEI */
+ PUT_BITS(0, 1, nbb_, bb_, bc_);
+
+ int step = cif_ ? 1 : 2;
+ int cc = 0;
+
+ u_int8_t* frm = vf->bp_;
+ for (u_int gob = 0; gob < ngob_; gob += step) {
+ u_int loff = loff_[gob];
+ u_int coff = coff_[gob];
+ u_int blkno = blkno_[gob];
+ u_int nbit = ((bc_ - bs_) << 3) + nbb_;
+
+ /* GSC/GN */
+ PUT_BITS(0x10 | (gob + 1), 20, nbb_, bb_, bc_);
+ /* GQUANT/GEI */
+ mquant_ = lq_;
+ PUT_BITS(mquant_ << 1, 6, nbb_, bb_, bc_);
+
+ mba_ = 0;
+ int line = 11;
+ for (u_int mba = 1; mba <= 33; ++mba) {
+ /*
+ * If the conditional replenishment algorithm
+ * has decided to send any of the blocks of
+ * this macroblock, code it.
+ */
+ u_int s = crvec[blkno];
+
+ if ((s & CR_SEND) != 0) {
+ u_int mbpred = mba_;
+ encode_mb(mba, frm, loff, coff, CR_STATE(s));
+ u_int cbits = ((bc_ - bs_) << 3) + nbb_;
+ if (cbits > ec) {
+ pktbuf* npb;
+ npb = pool_->alloc(vf->ts_, RTP_PT_H261);
+ cc += flush(pb, nbit, npb);
+ cbits -= nbit;
+ pb = npb;
+ /* RTP/H.261 header */
+ u_int m = mbpred;
+ u_int g;
+ if (m != 0) {
+ g = gob + 1;
+ m -= 1;
+ } else
+ g = 0;
+
+ rh = (rtphdr*)pb->data;
+ *(u_int*)(rh + 1) =
+ 1 << 25 |
+ m << 15 |
+ g << 20 |
+ mquant_ << 10;
+ }
+ nbit = cbits;
+ }
+
+ loff += loffsize_;
+ coff += coffsize_;
+ blkno += bloffsize_;
+ if (--line <= 0) {
+ line = 11;
+ blkno += bstride_;
+ loff += lstride_;
+ coff += cstride_;
+ }
+
+ }
+ }
+ cc += flush(pb, ((bc_ - bs_) << 3) + nbb_, 0);
+ return (cc);
+}
Added: vic/trunk/codec/p64/p64as.cpp
==============================================================================
--- (empty file)
+++ vic/trunk/codec/p64/p64as.cpp Tue Aug 22 02:04:58 2006
@@ -0,0 +1,663 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WIN32
+//#include <winsock.h>
+#else
+#include <sys/param.h>
+#include <sys/file.h>
+#endif
+#include <sys/stat.h>
+
+#include "p64as.h"
+#include "p64-huff.h"
+#include "dct.h"
+#include "bsd-endian.h"
+
+#define inverseDCT( block, mask, image, rowstride, merge ) \
+ rdct( block, mask, image, rowstride, merge )
+
+void P64ASDecoder::err(const char* msg ...) const
+{
+#ifdef DEVELOPMENT_VERSION
+ va_list ap;
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, " @g%d m%d %d/%d of %d/%d: %04x %04x %04x %04x|%04x\n",
+ gob_, mba_,
+ (int)((u_char*)bs_ - (u_char*)ps_), nbb_,
+ (int)((u_char*)es_ - (u_char*)ps_), pebit_,
+ bs_[-4], bs_[-3], bs_[-2], bs_[-1], bs_[0]);
+#else
+ UNUSED(msg);
+#endif
+}
+
+P64ASDecoder::P64ASDecoder() :
+ fs_(0),
+ front_(0),
+ back_(0),
+ width_(0),
+ height_(0),
+ ngob_(0),
+ maxgob_(0),
+ ndblk_(0),
+ gobquant_(0),
+ mt_(0),
+ gob_(0),
+ mba_(0),
+ mvdh_(0),
+ mvdv_(0),
+ marks_(0),
+ mark_(0),
+ bad_psc_(0),
+ bad_bits_(0),
+ bad_GOBno_(0),
+ bad_fmt_(0),
+ coord_(0),
+ mb_state_(0)
+{
+ inithuff();
+ initquant();
+}
+
+P64ASDecoder::~P64ASDecoder()
+{
+ delete [] fs_;
+}
+
+void
+P64ASDecoder::init()
+{
+ //memset(mb_state_, MBST_OLD, sizeof(mb_state_));
+
+ minx_ = width_;
+ miny_ = height_;
+ maxx_ = 0;
+ maxy_ = 0;
+
+ front_ = 0;
+ back_ = 0;
+
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HUFFRQ(bs, bb) \
+ { \
+ register int t = *bs++; \
+ bb <<= 16; \
+ bb |= (t & 0xff) << 8; \
+ bb |= t >> 8; \
+}
+#else
+#define HUFFRQ(bs, bb) \
+ { \
+ bb <<= 16; \
+ bb |= *bs++; \
+}
+#endif
+
+#define MASK(s) ((1 << (s)) - 1)
+
+#define HUFF_DECODE(bs, ht, nbb, bb, result) { \
+ register int s__, v__; \
+ \
+ if (nbb < 16) { \
+ HUFFRQ(bs, bb); \
+ nbb += 16; \
+ } \
+ s__ = ht.maxlen; \
+ v__ = (bb >> (nbb - s__)) & MASK(s__); \
+ s__ = (ht.prefix)[v__]; \
+ nbb -= (s__ & 0x1f); \
+ result = s__ >> 5; \
+ }
+
+#define GET_BITS(bs, n, nbb, bb, result) \
+{ \
+ nbb -= n; \
+ if (nbb < 0) { \
+ HUFFRQ(bs, bb); \
+ nbb += 16; \
+ } \
+ (result) = ((bb >> nbb) & MASK(n)); \
+}
+
+#define SKIP_BITS(bs, n, nbb, bb) \
+{ \
+ nbb -= n; \
+ if (nbb < 0) { \
+ HUFFRQ(bs, bb); \
+ nbb += 16; \
+ } \
+}
+
+/*
+ * Set up the huffman tables.
+ */
+void
+P64ASDecoder::inithuff()
+{
+ ht_mtype_.prefix = htd_mtype;
+ ht_mtype_.maxlen = htd_mtype_width;
+ ht_mba_.prefix = htd_mba;
+ ht_mba_.maxlen = htd_mba_width;
+ ht_mvd_.prefix = htd_dvm;
+ ht_mvd_.maxlen = htd_dvm_width;
+ ht_cbp_.prefix = htd_cbp;
+ ht_cbp_.maxlen = htd_cbp_width;
+ ht_tcoeff_.prefix = htd_tcoeff;
+ ht_tcoeff_.maxlen = htd_tcoeff_width;
+}
+
+int
+P64ASDecoder::quantize(int v, int q)
+{
+ if (v > 0)
+ return (((v << 1) + 1) * q) - (~q & 1);
+ else
+ return (((v << 1) - 1) * q) + (~q & 1);
+}
+
+/*
+ * Build quantization lookup table.
+ * One for each possible MQUANT paramenter.
+ */
+void
+P64ASDecoder::initquant()
+{
+ for (int mq = 0; mq < 32; ++mq) {
+ short* qt = &quant_[mq << 8];
+ for (int v = 0; v < 256; ++v) {
+ int s = (v << 24) >> 24;
+ qt[v] = quantize(s, mq);
+ }
+ }
+}
+
+/*
+ * Decode the next block of transform coefficients
+ * from the input stream.
+ * Return number of non-zero ac coefficients.
+ */
+#ifdef INT_64
+int P64ASDecoder::parse_block(short* blk, INT_64* mask)
+#else
+int P64ASDecoder::parse_block(short* blk, u_int* mask)
+#endif
+{
+#ifdef INT_64
+ INT_64 m0 = 0;
+#else
+ u_int m1 = 0, m0 = 0;
+#endif
+ /*
+ * Cache bit buffer in registers.
+ */
+ register int nbb = nbb_;
+ register int bb = bb_;
+ register short* qt = qt_;
+
+ for (int i = 0; i < 64; i ++ ) {
+ blk[i] = 0;
+ }
+ int k;
+ if ((mt_ & MT_CBP) == 0) {
+ int v;
+ GET_BITS(bs_, 8, nbb, bb, v);
+ if (v == 255)
+ v = 128;
+ if (mt_ & MT_INTRA)
+ v <<= 3;
+ else
+ v = qt[v];
+ blk[0] = v;
+ k = 1;
+ m0 |= 1;
+ } else if ((bb >> (nbb - 1)) & 1) {
+ /*
+ * In CBP blocks, the first block present must be
+ * non-empty (otherwise it's mask bit wouldn't
+ * be set), so the first code cannot be an EOB.
+ * CCITT optimizes this case by using a huffman
+ * table equivalent to ht_tcoeff_ but without EOB,
+ * in which 1 is coded as "1" instead of "11".
+ * We grab two bits, the first bit is the code
+ * and the second is the sign.
+ */
+ int v;
+ GET_BITS(bs_, 2, nbb, bb, v);
+ /*XXX quantize?*/
+ blk[0] = qt[(v & 1) ? 0xff : 1];
+ k = 1;
+ m0 |= 1;
+ } else {
+ k = 0;
+#ifndef INT_64
+ blk[0] = 0;/*XXX need this because the way we set bits below*/
+#endif
+ }
+ int nc = 0;
+ for (;;) {
+ int r, v;
+ HUFF_DECODE(bs_, ht_tcoeff_, nbb, bb, r);
+ if (r <= 0) {
+ /* SYM_EOB, SYM_ILLEGAL, or SYM_ESCAPE */
+ if (r == SYM_ESCAPE) {
+ GET_BITS(bs_, 14, nbb, bb, r);
+ v = r & 0xff;
+ r >>= 8;
+ } else {
+ if (r == SYM_ILLEGAL) {
+ bb_ = bb;
+ nbb_ = nbb;
+ err("illegal symbol in block");
+ }
+ /* EOB */
+ break;
+ }
+ } else {
+ v = (r << 22) >> 27;
+ r = r & 0x1f;
+ }
+ k += r;
+ if (k >= 64) {
+ bb_ = bb;
+ nbb_ = nbb;
+ err("bad run length %d (r %d, v %d)", k, r, v);
+ break;
+ }
+ r = COLZAG[k++];
+ //r = ROWZAG[k++];
+ blk[r] = qt[v & 0xff];
+ ++nc;
+#ifdef INT_64
+ m0 |= (INT_64)1 << r;
+#else
+ if (r < 32)
+ m0 |= 1 << r;
+ else
+ m1 |= 1 << (r - 32);
+#endif
+ }
+ /*
+ * Done reading input. Update bit buffer.
+ */
+ bb_ = bb;
+ nbb_ = nbb;
+
+ *mask = m0;
+#ifndef INT_64
+ mask[1] = m1;
+#endif
+ return (nc);
+}
+
+/*
+ * Parse a GOB header, which consists of the GOB quantiation
+ * factor (GQUANT) and spare bytes that we ignore.
+ */
+int P64ASDecoder::parse_gob_hdr(int ebit)
+{
+ UNUSED(ebit);
+ int gobu, gobm, gobl;
+
+ mba_ = -1;
+
+ GET_BITS(bs_, 7, nbb_, bb_, gobu);
+ GET_BITS(bs_, 6, nbb_, bb_, gobm);
+ GET_BITS(bs_, 7, nbb_, bb_, gobl);
+ gob_ = (gobu << 13) | (gobm << 7) | (gobl);
+
+ int mq;
+ GET_BITS(bs_, 5, nbb_, bb_, mq);
+ gobquant_ = mq;
+ qt_ = &quant_[mq << 8];
+
+ return gob_;
+}
+
+/*
+ * Parse a macroblock header. If there is no mb header because
+ * we hit the next start code, return -1, otherwise 0.
+ */
+int P64ASDecoder::parse_mb_hdr(u_int& cbp)
+{
+ /*
+ * Read the macroblock address (MBA)
+ */
+ int v;
+ HUFF_DECODE(bs_, ht_mba_, nbb_, bb_, v);
+ if (v <= 0) {
+ /*
+ * (probably) hit a start code; either the
+ * next GOB or the next picture header.
+ * If we got MBA stuffing (0) we need to return
+ * so the outer loop can check if we're at the
+ * end of the buffer (lots of codecs put stuffing
+ * at the end of a picture to byte align the psc).
+ */
+ return (v);
+ }
+
+ /*
+ * MBA is differentially encoded.
+ */
+ mba_ += v;
+ if (mba_ >= MBPERGOB) {
+ return (SYM_ILLEGAL);
+ }
+
+ HUFF_DECODE(bs_, ht_mtype_, nbb_, bb_, mt_);
+ if (mt_ & MT_MQUANT) {
+ int mq;
+ GET_BITS(bs_, 5, nbb_, bb_, mq);
+ qt_ = &quant_[mq << 8];
+ }
+
+ /*
+ * Coded block pattern.
+ */
+ if (mt_ & MT_CBP) {
+ HUFF_DECODE(bs_, ht_cbp_, nbb_, bb_, cbp);
+ if (cbp > 63) {
+ err("cbp invalid %x", cbp);
+ return (SYM_ILLEGAL);
+ }
+ } else
+ cbp = 0x3f;
+
+ return (1);
+}
+
+/*
+ * Handle the next block in the current macroblock.
+ * If tc is non-zero, then coefficients are present
+ * in the input stream and they are parsed. Otherwise,
+ * coefficients are not present, but we take action
+ * according to the type macroblock that we have.
+ */
+void P64ASDecoder::decode_block(u_int tc,
+ u_int x,
+ u_int y,
+ u_int stride,
+ u_char* front,
+ u_char* back,
+ int sf)
+{
+ UNUSED(sf);
+ short blk[64];
+#ifdef INT_64
+ INT_64 mask;
+#define MASK_VAL mask
+#define MASK_REF &mask
+#else
+ u_int mask[2];
+#define MASK_VAL mask[0], mask[1]
+#define MASK_REF mask
+#endif
+ int nc = 0;
+ if (tc != 0)
+ nc = parse_block(blk, MASK_REF);
+
+ int off = y * stride + x;
+ u_char* out = front + off;
+
+ if (mt_ & MT_INTRA) {
+ if (tc != 0) {
+ if (nc == 0) {
+ dcfill((blk[0] + 4) >> 3, out, stride);
+ } else {
+ inverseDCT(blk, MASK_VAL, out, stride, (u_char*)0);
+ }
+ } else {
+ u_char* in = back + off;
+ mvblka(in, out, stride);
+ }
+ return;
+ }
+}
+
+/*
+ * Decompress the next macroblock. Return 0 if the macroblock
+ * was present (with no errors). Return SYM_STARTCODE (-1),
+ * if there was no macroblock but instead the start of the
+ * next GOB or picture (in which case the start code has
+ * been consumed). Return SYM_ILLEGAL (-2) if there was an error.
+ */
+int P64ASDecoder::decode_mb()
+{
+ u_int cbp;
+ register int v;
+
+ if ((v = parse_mb_hdr(cbp)) <= 0)
+ return (v);
+
+ /*
+ * Lookup the base coordinate for this MBA.
+ * Convert from a block to a pixel coord.
+ */
+ register u_int x, y;
+ x = coord_[33 * gob_ + mba_];
+ y = (x & 0xffff);
+ x >>= 16;
+
+ /* Update bounding box */
+ if (x < minx_)
+ minx_ = x;
+ if (x > maxx_)
+ maxx_ = x;
+ if (y < miny_)
+ miny_ = y;
+ if (y > maxy_)
+ maxy_ = y;
+
+ /*
+ * Decode the six blocks in the MB (4Y:1U:1V).
+ * (This code assumes MT_TCOEFF is 1.)
+ */
+ register u_int tc = mt_ & MT_TCOEFF;
+ register u_int s = width_;
+ decode_block(tc & (cbp >> 5), x, y, s, front_, back_, 1);
+ decode_block(tc & (cbp >> 4), x + 8, y, s, front_, back_, 1);
+ decode_block(tc & (cbp >> 3), x, y + 8, s, front_, back_, 1);
+ decode_block(tc & (cbp >> 2), x + 8, y + 8, s, front_, back_, 1);
+ s >>= 1;
+ int off = size_;
+ decode_block(tc & (cbp >> 1), x >> 1, y >> 1, s,
+ front_ + off, back_ + off, 2);
+ off += size_ >> 2;
+ decode_block(tc & (cbp >> 0), x >> 1, y >> 1, s,
+ front_ + off, back_ + off, 2);
+
+ mbst_[mba_] = MBST_NEW;
+
+ /*
+ * If a marking table was attached, take note.
+ * This allows us to dither only the blocks that have changed,
+ * rather than the entire image on each frame.
+ */
+ if (marks_) {
+ /* convert to 8x8 block offset */
+ off = (x >> 3) + (y >> 3) * (width_ >> 3);
+ int m = mark_;
+ marks_[off] = m;
+ marks_[off + 1] = m;
+ off += width_ >> 3;
+ marks_[off] = m;
+ marks_[off + 1] = m;
+ }
+ return (0);
+}
+
+/*
+ * Decode H.261 stream. Decoding can begin on either
+ * a GOB or macroblock header. All the macroblocks of
+ * a given frame can be decoded in any order, but chunks
+ * cannot be reordered across frame boundaries. Since data
+ * can be decoded in any order, this entry point can't tell
+ * when a frame is fully decoded (actually, we could count
+ * macroblocks but if there is loss, we would not know when
+ * to sync). Instead, the callee should sync the decoder
+ * by calling the sync() method after the entire frame
+ * has been decoded (modulo loss).
+ *
+ * This routine should not be called with more than
+ * one frame present since there is no callback mechanism
+ * for renderering frames (i.e., don't call this routine
+ * with a buffer that has a picture header that's not
+ * at the front).
+ */
+int P64ASDecoder::decode(const u_char* bp,
+ int cc,
+ int ebit,
+ int quant)
+{
+ ps_ = (u_short*)bp;
+ /*
+ * If cc is odd, ignore 8 extra bits in last short.
+ */
+ int odd = cc & 1;
+ ebit += odd << 3;
+ pebit_ = ebit;
+ es_ = (u_short*)(bp + ((cc - 1) &~ 1));
+
+ /*
+ * If input buffer not aligned, prime bit-buffer
+ * with 8 bits; otherwise, prime it with a 16.
+ */
+ if ((long)bp & 1) {
+ bs_ = (u_short*)(bp + 1);
+ bb_ = *bp;
+ nbb_ = 8;
+ } else {
+ bs_ = (u_short*)bp;
+ HUFFRQ(bs_, bb_);
+ nbb_ = 16;
+ }
+
+ int gob = 0;
+ qt_ = &quant_[quant << 8];
+
+ while (bs_ < es_ || (bs_ == es_ && nbb_ > ebit)) {
+ mbst_ = &mb_state_[gob * 33];
+
+ ndblk_++;
+ int v = decode_mb();
+ if (v == 0)
+ continue;
+
+ if (v != SYM_STARTCODE) {
+ err("expected GOB startcode");
+ ++bad_bits_;
+ return (0);
+ }
+ gob = parse_gob_hdr(ebit);
+ if (gob < 0) {
+ /*XXX*/
+ ++bad_bits_;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+void P64ASDecoder::sync()
+{
+ bbx_ = minx_;
+ bby_ = miny_;
+ bbw_ = maxx_ - minx_ + 16;
+ bbh_ = maxy_ - miny_ + 16;
+
+ minx_ = width_;
+ miny_ = height_;
+ maxx_ = 0;
+ maxy_ = 0;
+
+ maxgob_ = 0;
+}
+
+void P64ASDecoder::getPreviewLevelSize( u_short level, u_int &width, u_int &height )
+{
+ width = width_ >> level;
+ height = height_ >> level;
+}
+
+void P64ASDecoder::mvblka(u_char* in, u_char* out, u_int stride)
+{
+#ifdef INT_64
+ *(INT_64*)out = *(INT_64*)in;
+ out += stride; in += stride;
+ *(INT_64*)out = *(INT_64*)in;
+ out += stride; in += stride;
+ *(INT_64*)out = *(INT_64*)in;
+ out += stride; in += stride;
+ *(INT_64*)out = *(INT_64*)in;
+ out += stride; in += stride;
+ *(INT_64*)out = *(INT_64*)in;
+ out += stride; in += stride;
+ *(INT_64*)out = *(INT_64*)in;
+ out += stride; in += stride;
+ *(INT_64*)out = *(INT_64*)in;
+ out += stride; in += stride;
+ *(INT_64*)out = *(INT_64*)in;
+#else
+ for (int k = 8; --k >= 0; ) {
+ *(u_int*)out = *(u_int*)in;
+ *(u_int*)(out + 4) = *(u_int*)(in + 4);
+ in += stride;
+ out += stride;
+ }
+#endif
+}
+
+void
+P64ASDecoder::set_size(int w, int h)
+{
+ width_ = w;
+ height_ = h;
+ size_ = w * h;
+
+ int hblks = w/16;
+ int vblks = h/16;
+
+ int blks = hblks * vblks;
+
+ if (mb_state_) {
+ delete [] mb_state_;
+ }
+ mb_state_ = new u_char[blks];
+ memset(mb_state_, MBST_OLD, blks);
+
+ if (coord_) {
+ delete [] coord_;
+ }
+
+ coord_ = new u_int[blks];
+
+ int i = 0;
+ for (int y = 0; y < vblks; y ++) {
+ for (int x = 0; x < hblks; x ++, i ++) {
+ coord_[i] = (0xffff & (x * 16)) << 16 | (0xffff & (y * 16));
+ }
+ }
+
+ if (front_) {
+ delete [] front_;
+ }
+ if (back_) {
+ delete [] back_;
+ }
+
+ int buffer_size = size_ + size_/2;
+
+ front_ = new u_char[buffer_size];
+ back_ = new u_char[buffer_size];
+
+ memset(front_, 127, buffer_size);
+ memset(back_, 127, buffer_size);
+
+ sync();
+}
+
Added: vic/trunk/codec/p64/p64as.h
==============================================================================
--- (empty file)
+++ vic/trunk/codec/p64/p64as.h Tue Aug 22 02:04:58 2006
@@ -0,0 +1,149 @@
+
+#ifndef lib_p64as_h
+#define lib_p64as_h
+
+#include <sys/types.h>
+#include <stdio.h>
+
+struct huffcode;
+
+#define MBPERGOB 33
+
+class P64ASDecoder {
+public:
+ P64ASDecoder();
+ virtual ~P64ASDecoder();
+
+ virtual const u_char* frame() const { return (front_); }
+
+ inline int ndblk() const { return (ndblk_); }
+ inline void resetndblk() { ndblk_ = 0; }
+ inline int width() const { return (width_); }
+ inline int height() const { return (height_); }
+
+ virtual void set_size(int w, int h);
+
+ virtual int decode(const u_char* bp,
+ int cc,
+ int ebit,
+ int quant);
+
+ virtual void sync();
+ inline void bb(int& x, int& y, int& w, int& h) {
+ x = bbx_; y = bby_; w = bbw_; h = bbh_;
+ };
+ inline u_int bad_psc() const { return (bad_psc_); }
+ inline u_int bad_bits() const { return (bad_bits_); }
+ inline u_int bad_GOBno() const { return (bad_GOBno_); }
+ inline u_int bad_fmt() const { return (bad_fmt_); }
+ inline int seenMaxGob() const { return (maxgob_ >= ngob_ - 1); }
+ inline u_int gobquant() const { return (gobquant_); }
+
+ inline void marks(u_char* p) { marks_ = p; }
+ inline void mark(int v) { mark_ = v; }
+
+ inline void setPreviewLevel( u_short level ) { set_preview_level = level; }
+ inline u_short getPreviewLevel() const { return preview_level; }
+
+ inline u_short getPreviewLevelMax() const { return 3; }
+ void getPreviewLevelSize( u_short level, u_int &width, u_int &height );
+
+ void mvblk(u_char* in, u_char* out, u_int stride);
+ void mvblka(u_char*, u_char*, u_int stride);
+
+protected:
+ void init();
+ void inithuff();
+ void initquant();
+ virtual void err(const char* msg ...) const;
+ int quantize(int v, int q);
+#ifdef INT_64
+ int parse_block(short* blk, INT_64* mask);
+#else
+ int parse_block(short* blk, u_int* mask);
+#endif
+ void decode_block(u_int tc, u_int x, u_int y, u_int stride,
+ u_char* front, u_char* back, int sf);
+
+ int parse_gob_hdr(int);
+ int parse_mb_hdr(u_int& cbp);
+ int decode_gob(u_int gob);
+ int decode_mb();
+
+ u_int size_;
+ u_char* fs_;
+ u_char* front_;
+ u_char* back_;
+
+ struct hufftab {
+ int maxlen;
+ const short* prefix;
+ };
+ hufftab ht_mba_;
+ hufftab ht_mvd_;
+ hufftab ht_cbp_;
+ hufftab ht_tcoeff_;
+ hufftab ht_mtype_;
+
+ u_int bb_; /* 32-bit bit buffer */
+ int nbb_; /* number bits in bit buffer */
+ const u_short* bs_; /* input bit stream (less bits in bb_) */
+ const u_short* es_; /* pointer to end if input stream */
+ const u_short* ps_; /* packet start (for error reporting) */
+ int pebit_; /* packet end bit (for error reporting) */
+
+#define MBST_FRESH 0
+#define MBST_OLD 1
+#define MBST_NEW 2
+ u_char* mbst_;
+ short* qt_;
+
+ u_int width_; /* width of Y component */
+ u_int height_; /* height of Y component */
+
+ u_int ngob_; /* number of gobs (12 for CIF, 3 for QCIF) */
+ u_int maxgob_; /* max gob seen this frame */
+ int ndblk_; /* # of decoded macroblocks */
+ u_int gobquant_; /* last gob quantizer (for info funtion) */
+
+ u_int mt_; /* macroblock type (flags in p64-huff.h) */
+ u_int gob_; /* current gob index */
+ int mba_; /* macroblock address (predictor) */
+ int mvdh_; /* motion vector (predictor) */
+ int mvdv_; /* motion vector (predictor) */
+
+ /* bounding box */
+ u_int minx_;
+ u_int miny_;
+ u_int maxx_;
+ u_int maxy_;
+ u_int bbx_;
+ u_int bby_;
+ u_int bbw_;
+ u_int bbh_;
+
+ /*
+ * Table to indicate which blocks have changed.
+ */
+ u_char* marks_;
+ int mark_;
+
+ /* error counters */
+ int bad_psc_;
+ int bad_bits_;
+ int bad_GOBno_;
+ int bad_fmt_; /* # times RTP fmt != H.261 fmt */
+
+ /* inverse quantization via table lookup */
+ short quant_[32 * 256];
+
+ /* gob/mba to coordinate mappings */
+ u_int* coord_;
+ u_char* mb_state_;
+
+
+ u_short preview_level;
+ u_short set_preview_level;
+};
+
+#endif
Modified: vic/trunk/configure
==============================================================================
--- vic/trunk/configure (original)
+++ vic/trunk/configure Tue Aug 22 02:04:58 2006
@@ -309,7 +309,7 @@
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX CPP EGREP V_INCLUDE_X11 V_LIB_X11 V_INCLUDE_TCL V_LIB_TCL V_LIBRARY_TCL V_TKDOSNAMES V_INCLUDE_TK V_LIB_TK V_LIBRARY_TK V_INCLUDE_GRABBER V_LIB_GRABBER V_OBJ_GRABBER V_LIB_XIL V_OBJ_XIL V_STATIC V_TAR_TARGET V_ALL V_CCOPT V_CCOPT_H261 V_TAR_EXTRA V_LIB V_DEFINE V_SIGRET V_SHELL V_TARCMD V_INCLUDE V_OBJ V_BROKEN_OBJ V_OBJ_CRYPT LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX CPP EGREP V_INCLUDE_X11 V_LIB_X11 V_INCLUDE_TCL V_LIB_TCL V_LIBRARY_TCL V_TKDOSNAMES V_INCLUDE_TK V_LIB_TK V_LIBRARY_TK V_INCLUDE_GRABBER V_LIB_GRABBER V_OBJ_GRABBER V_LIB_XIL V_OBJ_XIL V_OBJ V_STATIC V_TAR_TARGET V_ALL V_CCOPT V_CCOPT_H261 V_TAR_EXTRA V_LIB V_DEFINE V_SIGRET V_SHELL V_TARCMD V_INCLUDE V_BROKEN_OBJ V_OBJ_CRYPT LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -719,13 +719,13 @@
/^X\(\/\).*/{ s//\1/; q; }
s/.*/./; q'`
srcdir=$ac_confdir
- if test ! -r $srcdir/$ac_unique_file; then
+ if test ! -r "$srcdir/$ac_unique_file"; then
srcdir=..
fi
else
ac_srcdir_defaulted=no
fi
-if test ! -r $srcdir/$ac_unique_file; then
+if test ! -r "$srcdir/$ac_unique_file"; then
if test "$ac_srcdir_defaulted" = yes; then
{ echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
{ (exit 1); exit 1; }; }
@@ -734,7 +734,7 @@
{ (exit 1); exit 1; }; }
fi
fi
-(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+(cd $srcdir && test -r "./$ac_unique_file") 2>/dev/null ||
{ echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
{ (exit 1); exit 1; }; }
srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
@@ -855,6 +855,7 @@
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-debug build with debugging enabled
--enable-ipv6 build with ipv6 enabled
+--enable-h261as Enable or disable the h261as codec
--enable-v4l2old Enable or disable old Video4Linux2 grabber
--enable-XvGrabber Enable or disable old XvGrabber
@@ -4487,6 +4488,21 @@
exit 1
fi
+V_OBJ=""
+V_H261AS=""
+
+# Check whether --enable-h261as or --disable-h261as was given.
+if test "${enable_h261as+set}" = set; then
+ enableval="$enable_h261as"
+ h261as=yes
+else
+ h261as=no
+fi;
+if test "$h261as" = "yes"; then
+ V_OBJ="$V_OBJ codec/p64/p64as.o codec/decoder-h261as.o codec/encoder-h261as.o"
+ V_H261AS="-DUSE_H261AS"
+fi
+
# lots of hairy special cases for detecting which frame capture
# support to compile in
@@ -4821,7 +4837,8 @@
-V_DEFINE="$V_DEFINE $V_SHM"
+
+V_DEFINE="$V_DEFINE $V_SHM $V_H261AS"
# tcl7.5 needs a dynamic loading library (unless built with the
@@ -5708,6 +5725,7 @@
s, at V_OBJ_GRABBER@,$V_OBJ_GRABBER,;t t
s, at V_LIB_XIL@,$V_LIB_XIL,;t t
s, at V_OBJ_XIL@,$V_OBJ_XIL,;t t
+s, at V_OBJ@,$V_OBJ,;t t
s, at V_STATIC@,$V_STATIC,;t t
s, at V_TAR_TARGET@,$V_TAR_TARGET,;t t
s, at V_ALL@,$V_ALL,;t t
@@ -5720,7 +5738,6 @@
s, at V_SHELL@,$V_SHELL,;t t
s, at V_TARCMD@,$V_TARCMD,;t t
s, at V_INCLUDE@,$V_INCLUDE,;t t
-s, at V_OBJ@,$V_OBJ,;t t
s, at V_BROKEN_OBJ@,$V_BROKEN_OBJ,;t t
s, at V_OBJ_CRYPT@,$V_OBJ_CRYPT,;t t
s, at LIBOBJS@,$LIBOBJS,;t t
Modified: vic/trunk/configure.in
==============================================================================
--- vic/trunk/configure.in (original)
+++ vic/trunk/configure.in Tue Aug 22 02:04:58 2006
@@ -29,6 +29,16 @@
exit 1
fi
+V_OBJ=""
+V_H261AS=""
+
+dnl h261 as (arbitrary size)
+AC_ARG_ENABLE(h261as, --enable-h261as Enable or disable the h261as codec, h261as=yes, h261as=no)
+if test "$h261as" = "yes"; then
+ V_OBJ="$V_OBJ codec/p64/p64as.o codec/decoder-h261as.o codec/encoder-h261as.o"
+ V_H261AS="-DUSE_H261AS"
+fi
+
# lots of hairy special cases for detecting which frame capture
# support to compile in
@@ -351,7 +361,8 @@
AC_SUBST(V_OBJ_GRABBER)
AC_SUBST(V_LIB_XIL)
AC_SUBST(V_OBJ_XIL)
+AC_SUBST(V_OBJ)
-V_DEFINE="$V_DEFINE $V_SHM"
+V_DEFINE="$V_DEFINE $V_SHM $V_H261AS"
builtin(include, configure.in.tail)
Modified: vic/trunk/rtp/rtp.h
==============================================================================
--- vic/trunk/rtp/rtp.h (original)
+++ vic/trunk/rtp/rtp.h Tue Aug 22 02:04:58 2006
@@ -63,6 +63,9 @@
/* backward compat hack for decoding RTPv1 ivs streams */
#define RTP_PT_H261_COMPAT 127
+/* non-standard arbitrary sized h261 */
+#define RTP_PT_H261AS 77
+
/* RTP standard content encodings for audio */
#define RTP_PT_PCMU 0
#define RTP_PT_CELP 1
Modified: vic/trunk/rtp/session.cpp
==============================================================================
--- vic/trunk/rtp/session.cpp (original)
+++ vic/trunk/rtp/session.cpp Tue Aug 22 02:04:58 2006
@@ -81,6 +81,9 @@
case RTP_PT_H263P:
case RTP_PT_LDCT:
case RTP_PT_PVH:
+#ifdef USE_H261AS
+ case RTP_PT_H261AS:
+#endif
return (1);
}
return (0);
Modified: vic/trunk/tcl/cf-main.tcl
==============================================================================
--- vic/trunk/tcl/cf-main.tcl (original)
+++ vic/trunk/tcl/cf-main.tcl Tue Aug 22 02:04:58 2006
@@ -46,6 +46,7 @@
set rtp_type(42) h263+
set rtp_type(34) h263
set rtp_type(127) h261v1
+set rtp_type(77) h261as
proc vic_main {} {
global V tcl_platform
More information about the Sumover-dev
mailing list