IncompleteIO.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: IncompleteIO.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 #include "IncompleteIO.hpp" 00045 #include "MPGStreamIO.hpp" 00046 #include "SimpleRtp.hpp" 00047 #include "ESInfo.hpp" 00048 #include "../net/PacketizationLayer.hpp" 00049 #include "../net/Session.hpp" 00050 #include "../metadata/TerminalCapabilities.hpp" 00051 #include "../adaptors/GlobalTimer.hpp" 00052 00053 IncompleteIO::IncompleteIO(const char* localFile, const char *url, 00054 int remotePrt, const char *address, int localPrt, 00055 ESInfo * es, PacketizationLayer * packetization, bool writeOnly, 00056 GlobalTimer * globalTimer, Statistics *stats):IO(),frameCache(INCOMPLETEIO__MAX_FRAMES) 00057 { 00058 assert(es); 00059 this->es=es; 00060 vopTimeIncrement=es->getVOPTimeIncrement(); 00061 dprintf_full("IncompleteIO::IncompleteIO with es=%p\n",es); 00062 //omitheader??? default is false, should be ok 00063 localInput=new MPGStreamIO(es,localFile,writeOnly); 00064 #ifndef WINCE 00065 remoteInput=new SimpleRtp(url, remotePrt, localPrt, address, es, 00066 packetization, writeOnly, NULL,true,SimpleRtp::NO_DELAY,false,false); 00067 #endif //wince 00068 lastCTS=0; 00069 framesSeen=0; 00070 cacheUsage=0; 00071 }; 00072 00073 IncompleteIO::~IncompleteIO() 00074 { 00075 if(localInput) { 00076 localInput->close(true); 00077 delete localInput; 00078 } 00079 #ifndef WINCE 00080 if(remoteInput) { 00081 remoteInput->close(true); 00082 delete remoteInput; 00083 } 00084 #endif 00085 flushLocalCache(); 00086 00087 00088 }; 00089 00090 void IncompleteIO::flushLocalCache() 00091 { 00092 frameCache.flushBuffer(); 00093 }; 00094 00095 00096 long IncompleteIO::setToClosestIFrame(u32 frameNumber, bool backwards) 00097 { 00098 return localInput->setToClosestIFrame(frameNumber, backwards); 00099 }; 00100 00101 Frame * IncompleteIO::getFrame() 00102 { 00103 // first check the locally cached frames 00104 // then check MpgStreamIO 00105 // then try Rtp (blocking!) 00106 // then return from local cache 00107 dprintf_full("IncompleteIO::getFrame(): expecting CTS %u\n",(lastCTS==0)?0:lastCTS+vopTimeIncrement); 00108 00109 // get packets from remote to avoid buffer overflow in Rtp 00110 #ifndef WINCE 00111 remoteInput->preBufferPackets(0); 00112 #endif 00113 if(lastCTS>=es->getDuration()) { 00114 dprintf_full("IncompleteIO::getFrame() eos detected\n"); 00115 close(true); 00116 return NULL; 00117 } 00118 00119 Frame* frm=NULL; 00120 // check the cache 00121 if(lastCTS==0) 00122 frm=findAndUnlinkFrame(0); 00123 else 00124 frm=findAndUnlinkFrame(vopTimeIncrement+lastCTS); 00125 00126 if(frm) { 00127 lastCTS=frm->getAU()->cts; 00128 dprintf_full("IncompleteIO::getFrame(): found buffered frame with CTS %u\n",lastCTS); 00129 framesSeen++; 00130 return frm; 00131 } 00132 // it's not in the cache 00133 // so get the next frm from MpgStreamIO 00134 dprintf_full("IncompleteIO::getFrame(): before reading next local frame\n"); 00135 frm=localInput->getFrame(); 00136 dprintf_full("IncompleteIO::getFrame(): after reading local frame\n"); 00137 if(!frm && framesSeen==0) { 00138 // header treatment 00139 frm=localInput->getFrame(); 00140 } 00141 00142 dprintf_full("IncompleteIO::getFrame(): read cached frame %p with CTS %u\n",frm, ( (frm && frm->getAU())?frm->getAU()->cts:0)); 00143 if(frm) { 00144 if(frm->getAU()->cts==(lastCTS+vopTimeIncrement) 00145 || frm->getAU()->cts==0) { 00146 // found 00147 framesSeen++; 00148 if(frm->getAU()->cts!=0) 00149 lastCTS=frm->getAU()->cts; 00150 dprintf_full("IncompleteIO::getFrame(): local frame is returned\n"); 00151 return frm; 00152 } 00153 else if(frm->getAU()->cts>lastCTS) { 00154 // store in cache 00155 setFrame(frm); 00156 dprintf_full("IncompleteIO::getFrame(): local frame is cached\n"); 00157 } 00158 else { 00159 delete frm; // frame is too old 00160 dprintf_full("IncompleteIO::getFrame(): local frame is too old. Deleted!\n"); 00161 frm=NULL; 00162 } 00163 } 00164 // if we have not found a local or cached frame, check network 00165 #ifndef WINCE 00166 frm=remoteInput->getFrame(); 00167 #else 00168 frm = NULL; 00169 #endif 00170 dprintf_full("IncompleteIO::getFrame(): read remote frame %p with CTS %u\n",frm, ( (frm && frm->getAU())?frm->getAU()->cts:0)); 00171 if(frm) { 00172 if(frm->getAU()->cts==(lastCTS+vopTimeIncrement) 00173 || frm->getAU()->cts==0) { 00174 // found 00175 framesSeen++; 00176 if(frm->getAU()->cts!=0) 00177 lastCTS=frm->getAU()->cts; 00178 dprintf_full("IncompleteIO::getFrame(): remote frame is returned\n"); 00179 return frm; 00180 } 00181 else if(frm->getAU()->cts>lastCTS) { 00182 // store in cache 00183 setFrame(frm); 00184 dprintf_full("IncompleteIO::getFrame(): remote frame is cached\n"); 00185 } 00186 else { 00187 delete frm; // frame is too old 00188 dprintf_full("IncompleteIO::getFrame(): remote frame is too old. Deleted!\n"); 00189 } 00190 } 00191 frm=NULL; 00192 // we have to return sth 00193 // so look in the frameCache and return the first 00194 if(cacheUsage>0) { 00195 // search the cache for the next n frames 00196 // vopTimeIncrement+lastCTS was not found, thus check the next first 00197 u32 nextCTS=2*vopTimeIncrement+lastCTS; 00198 for(u32 iCts=nextCTS;iCts<nextCTS+INCOMPLETEIO__MAX_FRAME_LOOK_AHEAD*vopTimeIncrement;iCts+=vopTimeIncrement) { 00199 frm=findAndUnlinkFrame(iCts); 00200 if(frm) { 00201 framesSeen++; 00202 if(frm->getAU()->cts!=0) 00203 lastCTS=frm->getAU()->cts; 00204 dprintf_full("IncompleteIO::getFrame(): gap detected, just returning the first cached frame %p with CTS %u\n",frm,frm->getAU()->cts); 00205 return frm; 00206 }; 00207 } 00208 } 00209 assert(frm==NULL); 00210 //we still have to increase lastCTS, otherwise infinite loop for one and the same CTS 00211 lastCTS+=vopTimeIncrement; 00212 dprintf_full("IncompleteIO::getFrame(): gap detected, returning NULL\n"); 00213 return frm; 00214 }; 00215 00216 int IncompleteIO::writeFrame(Frame * frm, ESInfo *out_es) 00217 { 00218 assert(false && "Not Implemented"); 00219 return -1; 00220 }; 00221 00225 bool IncompleteIO::open() 00226 { 00227 framesSeen=0;lastCTS=0; 00228 #ifndef WINCE 00229 bool ret=localInput->open() && remoteInput->open(); 00230 #else 00231 bool ret = false; 00232 #endif 00233 return ret; 00234 }; 00235 00240 bool IncompleteIO::close(bool immediate) 00241 { 00242 #ifndef WINCE 00243 bool ret=localInput->close(immediate) && remoteInput->close(immediate); 00244 #else 00245 bool ret = false; 00246 #endif 00247 return ret; 00248 }; 00249 00253 bool IncompleteIO::destroy() 00254 { 00255 return localInput->destroy(); 00256 }; 00257 00259 int IncompleteIO::getBufferFillLevel() const 00260 { 00261 #ifndef WINCE 00262 return remoteInput->getBufferFillLevel(); 00263 #else 00264 return 0; 00265 #endif 00266 }; 00267 00273 int IncompleteIO::flushBuffer(long from_ts, long to_ts) 00274 { 00275 int b=localInput->flushBuffer(from_ts,to_ts); 00276 #ifndef WINCE 00277 b+=remoteInput->flushBuffer(from_ts,to_ts); 00278 #endif 00279 this->flushLocalCache(); 00280 return b; 00281 }; 00282 00284 const char *IncompleteIO::getURL() const 00285 { 00286 #ifndef WINCE 00287 return remoteInput->getURL(); 00288 #else 00289 return NULL; 00290 #endif 00291 }; 00292 00293 bool IncompleteIO::setToFrameNumber(u32 frameNumber) 00294 { 00295 #ifndef WINCE 00296 bool ret=remoteInput->setToFrameNumber(frameNumber); 00297 #else 00298 bool ret = false; 00299 #endif 00300 // we don't care about remote 00301 ret=localInput->setToFrameNumber(frameNumber); 00302 00303 return ret; 00304 }; 00305 00308 void IncompleteIO::setResendFrameHeader(bool set) 00309 { 00310 // one header is enough, so set this only at the local 00311 localInput->setResendFrameHeader(set); 00312 }; 00313 00314 void IncompleteIO::run() 00315 { 00316 #ifndef WINCE 00317 if(!remoteInput->running()) 00318 remoteInput->start(); 00319 remoteInput->wait(); 00320 #endif 00321 }; 00322 00324 void IncompleteIO::setRtxInfo(const rtx_info* rtx) 00325 { 00326 #ifndef WINCE 00327 remoteInput->setRtxInfo(rtx); 00328 #endif 00329 }; 00330 00331 IO::State IncompleteIO::play(double prefetchTime) 00332 { 00333 00334 #ifndef WINCE 00335 localInput->play(prefetchTime); 00336 return remoteInput->play(prefetchTime); 00337 #else 00338 return IO::CLOSED; 00339 #endif 00340 }; 00341 00342 IO::State IncompleteIO::pause() 00343 { 00344 localInput->pause(); 00345 #ifndef WINCE 00346 return remoteInput->pause(); 00347 #else 00348 return IO::CLOSED; 00349 #endif 00350 }; 00351 00352 IO::State IncompleteIO::setState(IO::State s) 00353 { 00354 localInput->setState(s); 00355 #ifndef WINCE 00356 return remoteInput->setState(s); 00357 #else 00358 return IO::CLOSED; 00359 #endif 00360 }; 00361 00362 IO::State IncompleteIO::getState() const 00363 { 00364 #ifndef WINCE 00365 return remoteInput->getState(); 00366 #else 00367 return IO::CLOSED; 00368 #endif 00369 }; 00370 00371 IO::State IncompleteIO::mute() 00372 { 00373 localInput->mute(); 00374 #ifndef WINCE 00375 return remoteInput->mute(); 00376 #else 00377 return IO::CLOSED; 00378 #endif 00379 }; 00380 00381 00383 Frame* IncompleteIO::findAndUnlinkFrame(u32 cts) 00384 { 00385 Frame* frm=frameCache.get(cts); 00386 if(frm) 00387 cacheUsage--; 00388 00389 return frm; 00390 }; 00391 00392 void IncompleteIO::setFrame(Frame* frm) 00393 { 00394 assert(frm && frm->getAU()); 00395 if(!frm) 00396 return; 00397 if(!frm->getAU()) 00398 return; 00399 // auto deletes if cache is full 00400 frameCache.put(frm,frm->getAU()->cts); 00401 cacheUsage++; 00402 // correct for auto-delete 00403 if(cacheUsage>INCOMPLETEIO__MAX_FRAMES) 00404 cacheUsage=INCOMPLETEIO__MAX_FRAMES; 00405 00406 }; 00407 00408 const ESInfo* const IncompleteIO::getESInfo() const 00409 { 00410 return localInput->getESInfo(); 00411 }; 00412 00413 void IncompleteIO::setESInfo(ESInfo * es) 00414 { 00415 localInput->setESInfo(es); 00416 #ifndef WINCE 00417 remoteInput->setESInfo(es); 00418 #endif 00419 };