Logo Search packages:      
Sourcecode: vic version File versions

encoder-h263.cpp

/*
* Copyright (c) 1994-1999 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.
*/

/* History:
*
* This encoder was written for a DFN project (http://www.dfn.de/) at the
* University of Erlangen-Nuremberg, Lehrstuhl fuer Nachrichtentechnik by
* Marcus Meissner in 1998.
*
* Merged into UCL vic development tree in 1998 by Kris Hasler/Piers O'Hanlon
*
* Cleanups, endianess, translation of comments into english, bugfixes,
* done by Marcus Meissner in June 1999.
*/
#ifndef lint
static char rcsid[] =
"@(#) $Header: /cs/research/mice/starship/src/local/CVS_repository/vic/codec/encoder-h263.cpp,v 1.3 1999/11/05 11:36:08 piers Exp $ (LBL)";
#endif

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <time.h>

#include "defs.h"
#include "bsd-endian.h"
#include "transmitter.h"
#include "pktbuf-rtp.h"
#include "module.h"
#include "crdef.h"

#include "h263/bitOut.h"
#include "h263/h263.h"
#include "encoder-h263.h"

extern "C" {
#include "h263/h263encoder.h"
#include "h263/h263encoder.p"

      int split_h263stream(
            u_char *bs,             /* bitstream [in] */
            u_int bitcount,               /* bitstream length in bits [in] */
            u_int gobs_per_frame,         /* gobs per frame [in] */
            u_int mbs_per_gob,            /* mbs per gob [in] */
            int *mbind,             /* macroblock indices [in] */
            int *mbquant,                 /* quantifiers [in] */
            MVField mvfield,        /* motion vectors [in] */
            u_int ts_,              /* timestamp [in] */
            int headersize,               /* headerlength [in] */
            h263_rtp_packet   **packets   /* rtp packets [out] */
            );
}

H263Encoder::H263Encoder() : TransmitterModule(FT_YUV_CIF)
{
      /* first frame must be coded INTRA */
      nexttype_ = PICTURE_CODING_TYPE_INTRA;
      
      lastw_ = 0;lasth_ = 0;
      oldpic_.w = 0;
      oldpic_.h = 0;
      oldpic_.y = new Byte[3];
      oldpic_.u = oldpic_.y+1;
      oldpic_.v = oldpic_.u+1;
      oldorigpic_.w = 0;
      oldorigpic_.h = 0;
      oldorigpic_.y = new Byte[3];
      oldorigpic_.u = oldorigpic_.y+1;
      oldorigpic_.v = oldorigpic_.u+1;
      
      mbind_=(int*)malloc(1);
      mbquant_=(int*)malloc(1);
      
      mvfield_.mx = (short*)malloc(1);
      mvfield_.my = (short*)malloc(1);
      mvfield_.mode = (short*)malloc(1);
      mvfield_.w = 1;
      mvfield_.h = 1;
      
      decpict_.w = 0; decpict_.h = 0;
      decpict_.y = new Byte[3];
      decpict_.u = decpict_.y+1;
      decpict_.v = decpict_.u+1;
      
      /* global maximum rate for the encoder.
      * The encoder itself does not have a fixed bitrate delimiter, so
      * we just allocate a very big buffer and hope that the encoder does
      * not overflow it.
      */
      maxrate_ = 100000;
      bitstr_.b = new Byte[maxrate_*10/8];
      bitstr_.size = maxrate_*10;
      bitstr_.ind = 0;
      bitstr_.actualSize = 0;
      bitstr_.fp = NULL;
      
      /* We use only codingtime 3, since it is the best time/quality/space
      * tradeoff currently. 
      */
      codingtime_ = 3;
      
      maycheck_ = 0;
      
      /* default Quantisierer is 10 */
      q_ = 10;
}

H263Encoder::~H263Encoder()
{
/* Bus Errors... Caused by destructors called out of sequence.
if (tx_ != 0)
tx_->flush();
      */
}

int
H263Encoder::command(int argc,const char* const *argv)
{
      if (argc==3) {
            if (!strcasecmp(argv[1],"q")) {
                  q_ = atoi(argv[2]);
                  return 0;
            }
      }
      return TransmitterModule::command(argc,argv);
}

/***********************************************************************
* H263Encoder::consume()
*
* Maininterface function to VIC is called for every grabbed frame.
* Encodes the frames into h.263, paketises them according to RFC 2190 and
* sends the RTP packets using the RTP networklayer of VIC.
*
* Returns number of sent bytes.
*/
int H263Encoder::consume(const VideoFrame* vf)
{
      YuvFrame*   yuv = (YuvFrame*)vf;    /* real YUV Frame */
      Picture           thispic;          /* current image */
      u_int       xfps,kbps;        /* parameter from Tcl */
      u_int       i;
      u_int       sentbytes=0;            /* sent bytes in this consume */
      u_int       bps;              /* target bitrate */
      int               k, mbs_per_gob, gobs_per_frame;
      int               w, h;
      Tcl&        tcl = Tcl::instance();
      pktbuf*           pb;
      rtphdr*           rh;
#ifdef TIME_ADAPTION
      struct timeval tv1,tv2;
      int   timespent;
#endif /* TIME_ADAPTION */

      //moved up here by Piers
      tx_->flush();
      
      w = yuv->width_;
      h = yuv->height_;
      
      
      k = 1;
      if (w == CIF4_WIDTH)         k = 2;
      if (w == 2*CIF4_WIDTH)       k = 4;
      
      /* FIXME: incorrect for CIF*2 and up! */
      mbs_per_gob = w/16/k;
      gobs_per_frame = h/16/k;
      
      /* did we the size of the grabbed frame change? */
      if (w!=lastw_ || h!=lasth_) {
            /* readjust structzures, temp. arrays, et.al. */
            delete[] oldpic_.y;
            delete[] oldorigpic_.y;
            delete[] decpict_.y;
            
            free(mvfield_.mx);
            free(mvfield_.my);
            free(mvfield_.mode);
            
            oldpic_.w = w;oldpic_.h = h;
            oldpic_.y = new Byte[w*h*3/2];
            oldpic_.u = oldpic_.y+w*h;
            oldpic_.v = oldpic_.u+w*h/4;
            
            oldorigpic_.w = w;oldpic_.h = h;
            oldorigpic_.y = new Byte[w*h*3/2];
            oldorigpic_.u = oldorigpic_.y+w*h;
            oldorigpic_.v = oldorigpic_.u+w*h/4;
            
            decpict_.w = w;decpict_.h = h;
            decpict_.y = new Byte[w*h*3/2];
            decpict_.u = decpict_.y+w*h;
            decpict_.v = decpict_.u+w*h/4;
            
            mvfield_.mx = (short*)malloc(mbs_per_gob*gobs_per_frame*sizeof(short));
            mvfield_.my = (short*)malloc(mbs_per_gob*gobs_per_frame*sizeof(short));
            mvfield_.mode = (short*)malloc(mbs_per_gob*gobs_per_frame*sizeof(short));
            mvfield_.w = mbs_per_gob;
            mvfield_.h = gobs_per_frame;
            nexttype_ = PICTURE_CODING_TYPE_INTRA;
            lastw_ = w;
            lasth_ = h;
            free(mbind_);free(mbquant_);
            mbind_=(int*)malloc((mbs_per_gob*gobs_per_frame+1)*sizeof(int));
            mbquant_=(int*)malloc(mbs_per_gob*gobs_per_frame*sizeof(int));
            
            
      }
      
      /* HACK: We query the Tcl layers for the specified bps and fps values.
      * Hack due to the fact, that no other encoder uses this values in this
      * way and we could get feedback loops from the network code (who uses
      * them). Bummer.
      */
      tcl.evalc("$fps_slider get");sscanf(tcl.result(),"%d",&xfps);
      tcl.evalc("$bps_slider get");sscanf(tcl.result(),"%d",&kbps);
      
      /* calculate bits/frame */
      bps = kbps*1024/xfps;
      
      /* temporary picture from passed YUV Frame */
      thispic.w = w;
      thispic.h = h;
      thispic.y = (Byte*)yuv->bp_;
      thispic.u = (Byte*)yuv->bp_+w*h;
      thispic.v = (Byte*)yuv->bp_+w*h+(w*h)/4;
      
      /* Bitstream starts at 0 */
      bitstr_.ind = 0;
      
      /* and GO */
      bitstr_.b[bitstr_.size/8-1] = 0x42;
#ifdef TIME_ADAPTION
      gettimeofday(&tv1,NULL);
#endif /* TIME_ADAPTION */
      EncodeH263Q(
            q_,                           /* [in] Quantisierer */
            codingtime_,            /* [in] Codingtime */
            nexttype_,              /* [in] codingtype */
            vf->ts_,                /* [in] Timestamp */
            5,                          /* [in] percent intra blocks */
            &thispic,               /* [in] current image4 */
            &oldorigpic_,
            &oldpic_,               /* [in] prev. coded image */
            (unsigned char*)yuv->crvec_,  /* [in] condit. replenishment */
            &decpict_,              /* [out] new coded image */
            &bitstr_,               /* [out] bitstream */
            mbind_,                       /* [out] MB indices */
            mbquant_,               /* [out] MacroBlock Quant. */
            &mvfield_               /* [out] MotionVector field */
            );
      
      {
            Picture tmppict;
            tmppict = oldpic_; oldpic_ = decpict_; decpict_ = tmppict;
      }
      memcpy(oldorigpic_.y,thispic.y,w*h*3/2);
      
      assert(bitstr_.ind < bitstr_.size);
      assert(bitstr_.b[bitstr_.size/8-1]== 0x42);
      
      /* mark the end of the bitstream */
      mbind_[mbs_per_gob*gobs_per_frame]=bitstr_.ind;
      
      /* The actual splitfunction */
      h263_rtp_packet   *packets = NULL;
      int nrofpackets = split_h263stream(
            bitstr_.b,              /* [in] bitstream */
            bitstr_.ind,            /* [in] length in bits*/
            gobs_per_frame,
            mbs_per_gob,
            mbind_,
            mbquant_,
            mvfield_,
            yuv->ts_,               /* [in] timestamp */
            tx_->mtu(),             /* [in] current MTU */
            &packets                /* [out] packets... */
            );
            /* And now we send the packets.
            * We use the 2 standard iov buffers, buffer 1 just for the RTP header,
            * buffer 2 for the H263 payloadheader and the h.263 bits.
            * Reason for this is that the VIC decoder structure does not like 
            * like differently sized headers and acts differently between loopback
            * and network-in decoding.
      */
      for (i=0;i<nrofpackets;i++) {
            //pb = tx_->alloc(yuv->ts_,RTP_PT_H263);
            pb = pool_->alloc(yuv->ts_,RTP_PT_H263);
            //rh = (rtphdr*)pb->iov[0].iov_base;
            rh = (rtphdr*)pb->data;
            
            //pb->iov[0].iov_len = sizeof(rtphdr);
            
            //memcpy(pb->iov[1].iov_base,packets[i].header,packets[i].headersize);
            memcpy(&pb->data[sizeof(rtphdr)],packets[i].header,packets[i].headersize);
            //memcpy((char*)pb->iov[1].iov_base+packets[i].headersize,packets[i].data,packets[i].datasize);
            memcpy(&pb->data[sizeof(rtphdr)]+packets[i].headersize,packets[i].data,packets[i].datasize);
            //pb->iov[1].iov_len = packets[i].datasize+packets[i].headersize;
            pb->len = sizeof(rtphdr) + packets[i].datasize+packets[i].headersize;
            
            /* mark the last packet */
            if (i==nrofpackets-1)
                  rh->rh_flags |= htons(RTP_M);
            /* sending ...  */
            tx_->send(pb);
            sentbytes+=packets[i].headersize+packets[i].datasize+sizeof(rtphdr);
      }
      /* all other frames are coded with percentual INTRA part */
      nexttype_ = PICTURE_CODING_TYPE_INTER;
      /* flush the buffered RTP packets, so we can free the packets.
      * Bad style probably */
      //I think yes. Piers
      //tx_->flush();
      free(packets);

#ifdef TIME_ADAPTION
      
      /* and TIME! */
      gettimeofday(&tv2,NULL);
      
      timespent = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
      if ((++maycheck_)>20) {
            maycheck_ = 0;
            /* Did we use too much time? */
            if ((1000000/xfps*3)<timespent) {
                  /* Yes, first decrease imagesize */
                  if (w==CIF_WIDTH) {
                        tcl.evalc("grabber decimate 4");
                        tcl.evalc("set inputSize 4");
                        fprintf(stderr,"TOO SLOW: shrunk to QCIF\n");
                        return 0;
                  } else {
                        /* no more ways to do speed it up YET */
                  }
            }
            /* Did we use much less time as expected? */
            if ((1000000/xfps)>timespent*3) {
                  if (w==QCIF_WIDTH) {
                        tx_->flush();
                        tcl.evalc("grabber decimate 2");
                        tcl.evalc("set inputSize 2");
                        fprintf(stderr,"TOO FAST: grown to CIF\n");
                        return 0;
                  }
            }
      }
#endif
      return sentbytes;
}

Generated by  Doxygen 1.6.0   Back to index