Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members
MuxDemuxIO.cpp
00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: MuxDemuxIO.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 "MuxDemuxIO.hpp" 00045 #include "CompressedVideoFrame.hpp" 00046 #include "CompressedAudioFrame.hpp" 00047 #include "VideoESInfo.hpp" 00048 #include "AudioESInfo.hpp" 00049 #include "IO.hpp" 00050 00051 00052 00053 MuxDemuxIO::MuxDemuxIO(ByteStream *stream) : IO() { 00054 assert(stream); 00055 this->stream = stream; 00056 readOnly = stream->isReadOnly(); 00057 state = CLOSED; 00058 currentFrameNumber=0; 00059 firstFrame=true; 00060 mutex = new VMutex(); 00061 mutex->release(); 00062 ioList.clear(); 00063 dprintf_full("MuxDemuxIO for %s constructed!\n",stream->getUrl()); 00064 00065 } 00066 00067 00068 MuxDemuxIO::~MuxDemuxIO() { 00069 if (state != CLOSED) 00070 close(); 00071 if (stream) 00072 delete stream; 00073 delete mutex; 00074 } 00075 00079 bool MuxDemuxIO::open() { 00080 dprintf_full("MuxDemuxIO::open(), working with %i BufferedIOs \n",ioList.size()); 00081 assert(stream); 00082 if(state==OPEN) 00083 return true; 00084 00085 bool ret = false; 00086 state = OPENING; 00087 00088 ret = stream->open(); 00089 00090 if (ret) 00091 state = OPEN; 00092 else 00093 state = CLOSED; 00094 00095 currentFrameNumber=0; 00096 framesSeen=0; 00097 00098 return ret; 00099 } 00100 00101 00102 bool MuxDemuxIO::close(bool immediate) { 00103 state = CLOSING; 00104 stream->close(); 00105 state = CLOSED; 00106 return true; 00107 } 00108 00109 00110 bool MuxDemuxIO::destroy() { 00111 this->close(); 00112 return true; 00113 } 00114 00115 00117 int MuxDemuxIO::writeFrame(Frame * frm, ESInfo *out_es) { 00118 dprintf_full("MuxDemuxIO::writeFrame %p\n",frm); 00119 00120 if (state != OPEN) 00121 this->open(); 00122 00123 if (state != OPEN) { 00124 dprintf_err("MuxDemuxIO::writeFrame: Stream not open!\n"); 00125 return 0; 00126 } 00127 00128 if (firstFrame) { 00129 firstFrame=false; 00130 //write Container Header to file 00131 } 00132 00133 dprintf_full("MuxDemuxIO::writeFrame: writing frame CTS %i size %i from streamID %lli to container\n", 00134 frm->getAU()->cts, frm->getAU()->size, out_es->getStreamId()); 00135 00136 // forwarding the frame to container file 00137 00138 00139 framesSeen++; 00140 00141 #ifdef _POSIX_PRIORITY_SCHEDULING 00142 sched_yield(); //this is necessary to give parallel getFrames a chance 00143 #endif 00144 00145 return true; 00146 } 00147 00148 00149 00154 Frame *MuxDemuxIO::getFrame() { 00155 if (!readOnly || state != OPEN) 00156 return NULL; 00157 00158 #ifdef _POSIX_PRIORITY_SCHEDULING 00159 sched_yield(); //this is necessary to give parallel getFrames a chance 00160 #endif 00161 00162 return NULL; 00163 } 00164 00165 00166 bool MuxDemuxIO::addBufferedIO(int streamID, BufferedIO *bufIO) { 00167 mutex->lock(); 00168 00169 dprintf_full("MuxDemuxIO::addBufferedIO with streamID %i, already %i elems in list\n",streamID,ioList.size()); 00170 00171 if (!readOnly && !firstFrame) { 00172 dprintf_err("MuxDemuxIO::addBufferedIO but container HEADER already written!!!!\n"); 00173 ::exit(1); 00174 } 00175 00176 //FIXME: check for double streamIDs! 00177 ioList[streamID] = bufIO; 00178 00179 mutex->release(); 00180 00181 return true; 00182 } 00183 00184 00185 bool MuxDemuxIO::removeBufferedIO(int streamID, BufferedIO *bufIO) { 00186 mutex->lock(); 00187 00188 dprintf_full("MuxDemuxIO::removeBufferedIO with streamID %i\n",streamID); 00189 ioList.erase(streamID); 00190 00191 mutex->release(); 00192 00193 return true; 00194 } 00195 00196 00197 int MuxDemuxIO::getNumberOfConnectedBufferedIO() { 00198 int size; 00199 00200 //FIXME: no locks, since it's already locked in processFrame 00201 // mutex->lock(); 00202 size=ioList.size(); 00203 // mutex->release(); 00204 00205 return size; 00206 00207 } 00208 00209 00210 void MuxDemuxIO::processFrame() { 00211 mutex->lock(); 00212 00213 if (readOnly) 00214 processReadFrame(); 00215 else 00216 processWriteFrame(); 00217 00218 mutex->release(); 00219 } 00220 00221 00222 void MuxDemuxIO::processReadFrame() { 00223 map < int, BufferedIO* >::iterator currIO; 00224 int bufFillMin = 999999; 00225 00226 Frame *frm = getFrame(); 00227 00228 if (!frm) { 00229 dprintf_full("MuxDemuxIO::processReadFrame: no more frames left, EOF or major problems ;)\n"); 00230 return; 00231 } 00232 00233 BufferedIO *bufio = ioList[frm->getStreamID()]; 00234 00235 if (!bufio) { //no handler installed for this streamID 00236 //THIS IS DEFINITELY STUPID IN STL (by trying to read it, its created to the map!) 00237 ioList.erase(frm->getStreamID()); 00238 00239 dprintf_full("MuxDemuxIO::processReadFrame: got next frame for UNINITIALIZED streamID %i CTS %i, ignoring...\n", 00240 frm->getStreamID(), frm->getAU()->cts); 00241 00242 delete frm; 00243 } else { 00244 00245 ESInfo *esi = bufio->getESInfo(); 00246 00247 //put frm into real type 00248 Frame *realfrm = NULL; 00249 if (esi->isVisualStream()) 00250 realfrm = new CompressedVideoFrame(Frame::NN_VOP, ((VideoESInfo*)esi)->getWidth(), 00251 ((VideoESInfo*)esi)->getHeight()); 00252 else if(esi->isAudioStream()) 00253 realfrm=new CompressedAudioFrame(Frame::NN_VOP); 00254 else //hack for any other stream type 00255 realfrm = new CompressedVideoFrame(Frame::NN_VOP,0,0); 00256 00257 00258 //take over old values 00259 realfrm->setStreamID(frm->getStreamID()); 00260 realfrm->setAU(frm->getAU()); 00261 frm->unsetAU(); //to save from deletion 00262 delete frm; 00263 00264 //fill new ES information 00265 realfrm->getAU()->duration = esi->getDuration(); 00266 realfrm->setMediaTimeScale(esi->getMediaTimeScale()); 00267 realfrm->setCodecID(esi->getCodecID()); 00268 00269 bufio->addToBuffer(realfrm); 00270 00271 dprintf_full("MuxDemuxIO::processReadFrame: got next frame for streamID %i CTS %i type %s size %i\n", 00272 realfrm->getStreamID(), realfrm->getAU()->cts, Frame::VOPTypeToChar(realfrm->getType()), realfrm->getAU()->size); 00273 00274 } 00275 00276 00277 //check buffer fill level 00278 for(currIO=ioList.begin(); currIO != ioList.end(); currIO++) { 00279 //check, if none of the streams is closing 00280 if (currIO->second->getState() != OPEN) 00281 return; 00282 00283 //find out the minimum bufferFillLevel 00284 if (currIO->second->getBufferFillLevel() < bufFillMin) 00285 bufFillMin = currIO->second->getBufferFillLevel(); 00286 } 00287 00288 //needed for good balanced muxing 00289 if (bufFillMin < 500) { 00290 dprintf_full("MuxDemuxIO::processReadFrame: STARTUP: not enough data (%i frames) in BufferedIOs....harvesting...\n",bufFillMin); 00291 #ifdef _POSIX_PRIORITY_SCHEDULING 00292 sched_yield(); 00293 #else 00294 // for windows pthread lib! 00295 #ifndef WINCE 00296 sched_yield(); 00297 #else 00298 Sleep(0); 00299 #endif 00300 #endif 00301 processReadFrame(); 00302 } 00303 } 00304 00305 00306 00307 void MuxDemuxIO::processWriteFrame() { 00308 map < int, BufferedIO* >::iterator currIO; 00309 u32 lowestCTS = ~(u32)0; //make it the highest number possible 00310 s64 actCTS = -1; 00311 s64 streamID = -1; 00312 int bufFillMin = 999999; 00313 00314 dprintf_full("MuxDemuxIO::processWriteFrame: finding next frame with lowest CTS, firstFrame is %s \n",firstFrame?"TRUE":"FALSE"); 00315 00316 00317 for(currIO=ioList.begin(); currIO != ioList.end(); currIO++) { 00318 if ( (currIO->second->getState() == IO::OPEN) || (currIO->second->getState() == IO::CLOSING)) { 00319 actCTS = currIO->second->nextCTSinBuf(); 00320 dprintf_full("MuxDemuxIO::processWriteFrame: checking streamID %i with CTS %lli!\n",currIO->first, actCTS); 00321 if ((actCTS >= 0) && (actCTS < lowestCTS)) { 00322 lowestCTS = actCTS; 00323 streamID = currIO->first; 00324 } 00325 if (firstFrame && (currIO->second->getBufferFillLevel() < bufFillMin)) 00326 bufFillMin = currIO->second->getBufferFillLevel(); 00327 00328 } else { 00329 dprintf_full("MuxDemuxIO::processWriteFrame: BufferIO for streamID %lli is CLOSED!\n",streamID); 00330 } 00331 } 00332 00333 if (streamID < 0) { 00334 dprintf_full("MuxDemuxIO::processWriteFrame: no data in any BufferedIOs....\n"); 00335 return; 00336 } 00337 00338 //needed for good balanced muxing (try 30 or the actual video frame rate (one second of video...) 00339 if ((ioList[streamID]->getState() == IO::OPEN) && firstFrame && (bufFillMin < 30)) { 00340 dprintf_full("MuxDemuxIO::processWriteFrame: STARTUP: not enough data in ALL BufferedIOs....harvesting...\n"); 00341 return; 00342 } 00343 00344 Frame *frm = ioList[streamID]->getFrame(); 00345 00346 if (frm) { 00347 dprintf_full("MuxDemuxIO::processWriteFrame: writing frame %p ES-ID %lli CTS %i type %s size %i to container\n", 00348 frm, streamID, frm->getAU()->cts, Frame::VOPTypeToChar(frm->getType()), frm->getAU()->size); 00349 00350 //add header and write it to file 00351 writeFrame(frm, ioList[streamID]->getESInfo()); 00352 00353 //FIXME: this is an ugly memory leak fix... the whole crappy frame-concept should use reference counter... 00354 if (ioList[streamID]->getBufferFillLevel() > 0) 00355 delete frm; //there are more left, so take care of memory 00356 else 00357 frm->markForDelete(); //it's the direct DataChannel frame, so let the DC do the delete... 00358 00359 00360 } else { 00361 dprintf_full("MuxDemuxIO::processWriteFrame: BufferedIO for streamID %lli has no data! WHY???\n",streamID); 00362 assert(1==0); 00363 } 00364 00365 }