WvStreams
wvrateadjust.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvRateAdjust is a WvEncoder that makes sure data comes out of it at a
00006  * given average rate.
00007  * 
00008  * See wvrateadjust.h.
00009  */
00010 #include "wvrateadjust.h"
00011 
00012 WvRateAdjust::WvRateAdjust(int _sampsize, int _irate_base, int _orate)
00013 #if 0
00014     : log("RateAdj", WvLog::Debug5)
00015 #endif
00016 {
00017     orate_n = _orate;
00018     orate_d = 1;
00019     match_rate = NULL;
00020     
00021     init(_sampsize, _irate_base);
00022 }
00023 
00024 
00025 WvRateAdjust::WvRateAdjust(int _sampsize, int _irate_base,
00026                            WvRateAdjust *_match_rate)
00027 #if 0
00028     : log("RateAdj", WvLog::Debug5)
00029 #endif
00030 {
00031     match_rate = _match_rate;
00032     assert(match_rate);
00033     
00034     orate_n = match_rate->irate_n;
00035     orate_d = match_rate->irate_d;
00036     
00037     init(_sampsize, _irate_base);
00038 }
00039 
00040 
00041 void WvRateAdjust::init(int _sampsize, int _irate_base)
00042 {
00043     sampsize = _sampsize;
00044     irate_n = _irate_base * 10;
00045     irate_d = 10;
00046     epoch = wvtime();
00047     epoch.tv_sec--;
00048     bucket = 0;
00049 }
00050 
00051 
00052 // we always use all input samples and produce an appropriate number of
00053 // output samples.
00054 bool WvRateAdjust::_encode(WvBuf &inbuf, WvBuf &outbuf, bool flush)
00055 {
00056     if (!inbuf.used()) return true;
00057     assert((inbuf.used() % sampsize) == 0); // can't deal with partial samples
00058     
00059     WvTime now = wvtime();
00060     unsigned isamps = inbuf.used() / sampsize;
00061     
00062     // match our output rate to another stream's input rate, if requested
00063     if (match_rate)
00064     {
00065         orate_n = match_rate->irate_n;
00066         orate_d = match_rate->irate_d;
00067     }
00068     
00069     // adjust the input rate estimate
00070     if (!epoch.tv_sec)
00071         epoch = now;
00072     irate_n += isamps * 10;
00073     irate_d = msecdiff(wvtime(), epoch) / 100;
00074     if (!irate_d)
00075         irate_d = 1;
00076 
00077 #if 0
00078     log("irate=%s (%s/%s), orate=%s (%s/%s), bucket=%s\n",
00079         getirate(), irate_n, irate_d, getorate(), orate_n, orate_d,
00080         bucket);
00081 #endif
00082 
00083     // reduce the rate estimate if it's getting out of control FIXME:
00084     // this method is (almost) unbearably cheesy because it's very
00085     // "blocky" - it doesn't happen every time, so it'll cause sudden
00086     // jumps from one value to the next.  Hopefully not a big deal,
00087     // since the input rate is supposed to be constant anyway.  The
00088     // hardcoded constants are also rather weird.
00089     if (irate_d > 100) // ten seconds
00090     {
00091         epoch.tv_sec++; // time now starts one second later
00092         irate_n = irate_n * (irate_d - 10)/irate_d;
00093         irate_d -= 10;
00094 
00095 #if 0
00096         log("  JUMP!  new irate=%s (%s/%s)\n", getirate(), irate_n, irate_d);
00097 #endif
00098     }
00099         
00100     int plus = orate_n * irate_d, minus = irate_n * orate_d;
00101     //log("plus=%s, minus=%s, ", plus, minus);
00102 
00103     unsigned omax = isamps + isamps/2;
00104     //log("isamps=%s, omax=%s\n", isamps, omax);
00105     
00106     const unsigned char *iptr = inbuf.get(isamps * sampsize);
00107     unsigned char *ostart, *optr;
00108     
00109     ostart = optr = outbuf.alloc(omax * sampsize);
00110 
00111     // copy the buffers using the "Bresenham line-drawing" algorithm.
00112     for (unsigned s = 0; s < isamps; s++, iptr += sampsize)
00113     {
00114         bucket += plus;
00115         //log("s=%s, bucket=%s (+%s, -%s)\n", s, bucket, plus, minus);
00116         
00117         while (bucket >= minus)
00118         {
00119             // allocate more buffer space if needed
00120             if ((unsigned)(optr - ostart) >= omax * sampsize)
00121                 ostart = optr = outbuf.alloc(omax * sampsize);
00122             
00123             for (int i = 0; i < sampsize; i++)
00124                 optr[i] = iptr[i];
00125             optr += sampsize;
00126             bucket -= minus;
00127         }
00128     }
00129     
00130     unsigned un = omax*sampsize - (optr - ostart);
00131     //log("unalloc %s/%s (%s)\n", un, omax*sampsize, optr-ostart);
00132     outbuf.unalloc(un);
00133     
00134     return true;
00135 }
00136 
00137