WvStreams
|
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