Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members
BufferedHttpMPGStreamReader.cpp
00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: BufferedHTTPMPGStreamReader.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 "BufferedHttpMPGStreamReader.hpp" 00045 00046 #include "VideoESInfo.hpp" 00047 #include "CompressedVideoFrame.hpp" 00048 #include "CompressedAudioFrame.hpp" 00049 #include "IO.hpp" 00050 #include "../net/SDP.hpp" 00051 #include "BitField.hpp" 00052 00053 00054 #include "../container/ISOMP4ContainerFile.hpp" 00055 00056 00057 BufferedHttpMPGStreamReader::BufferedHttpMPGStreamReader(ESInfo * esi, const char *file, 00058 bool write, bool omit, int bufferSize, int maxFrameSize): MPGStreamIO(esi, file, write, omit) 00059 { 00060 00061 dprintf_full("BufferedHttpMPGStreamReader::BufferedHttpMPGStreamReader file=%s writeonly=%s\n",(file?file:"NULL"),(write?"WRITE":"READ")); 00062 assert(esi); 00063 00064 assert(bufferSize > 0); 00065 buffer = new u8[SAFETYDIST + bufferSize]; 00066 initBuffer(); 00067 this->bufferSize = bufferSize; 00068 bufferAtEnd = false; 00069 00070 contentLength = 0; 00071 contentStart = NULL; 00072 00073 this->maxFrameSize = maxFrameSize; 00074 DTS = 0; 00075 00076 http = NULL; 00077 00078 //FIXME: this call is necessary to get the correct filesize (contentlength) 00079 //however, with the videostream it produces an error when starting the datachannel-thread later (on wince) 00080 //thus, this call should be made in the calling object (e.g. simpleplayer) only for the audio-input 00081 00082 //this->open(); 00083 } 00084 00085 00086 BufferedHttpMPGStreamReader::~BufferedHttpMPGStreamReader() 00087 { 00088 if (buffer != NULL) delete [] buffer; 00089 if (http != NULL) delete http; 00090 } 00091 00092 bool BufferedHttpMPGStreamReader::open() 00093 { 00094 00095 setState(OPENING); 00096 00097 http = new HttpRequest(url); 00098 00099 if (http->makeHttpRequest()) { 00100 initBuffer(); 00101 contentLength = http->getContentLength(); 00102 00103 setState(OPEN); 00104 return true; 00105 } 00106 00107 setState(CLOSED); 00108 return false; 00109 } 00110 00111 00112 bool BufferedHttpMPGStreamReader::close(bool immediate) 00113 { 00114 if (http != NULL) { 00115 http->closeSock(); 00116 } 00117 dprintf_small("BufferedHttpMPGStreamReader::close() set state to CLOSED!\n"); 00118 setState(CLOSED); 00119 return true; 00120 } 00121 00122 bool BufferedHttpMPGStreamReader::testFileopen() 00123 { 00124 return true; 00125 } 00126 00127 00128 void BufferedHttpMPGStreamReader::initBuffer() 00129 { 00130 lastBytesBuffered = bytesBuffered = 0; 00131 bytesRead = 0; 00132 bytesReadTotal = 0; 00133 } 00134 00135 00136 00137 bool BufferedHttpMPGStreamReader::readBuffer() 00138 { 00139 if (bufferAtEnd) { 00140 dprintf_small("BufferedHttpMPGStreamReader::readBuffer() buffer at the end --> set state to CLOSED!\n"); 00141 setState(CLOSED); 00142 return false; 00143 } 00144 00145 if (lastBytesBuffered != 0) { 00146 //copy bytes of last read access 00147 for (int i=0; i < SAFETYDIST; i++) buffer[i] = buffer[lastBytesBuffered+i]; 00148 } 00149 00150 bool waitForMoreData; 00151 do { 00152 waitForMoreData = false; 00153 lastBytesBuffered = bytesBuffered = http->continueReceive((char*)buffer + SAFETYDIST, bufferSize); 00154 dprintf_full("BufferedHttpMPGStreamReader::readBuffer() read %d bytes\n", bytesBuffered); 00155 00156 if (bytesBuffered <= 0) { 00157 if (bytesReadTotal < (signed)contentLength) { 00158 msleep(10); 00159 waitForMoreData = true; 00160 dprintf_small("bufferedHttpMPGStreamReader:readBuffer() waiting for more data...\n"); 00161 } else { 00162 bufferAtEnd = true; 00163 bytesRead = 0; 00164 return false; 00165 //io will be closed by ::close() later! 00166 } 00167 } 00168 } while (waitForMoreData == true); 00169 00170 bytesRead = 0; 00171 return true; 00172 } 00173 00174 00175 int BufferedHttpMPGStreamReader::buffered_getc() 00176 { 00177 if (bytesBuffered == 0) { 00178 if (!readBuffer()) { 00179 return 0; 00180 } 00181 } 00182 bytesBuffered--; 00183 00184 bytesReadTotal++; 00185 return (int)buffer[bytesRead++ + SAFETYDIST]; 00186 } 00187 00188 00189 int BufferedHttpMPGStreamReader::buffered_read(u8 *buf, int nrBytes) 00190 { 00191 for (int i = 0; i < nrBytes; i++) { 00192 buf[i] = buffered_getc(); 00193 } 00194 return nrBytes; 00195 } 00196 00197 int BufferedHttpMPGStreamReader::buffered_copy(u8 *buf, int nrBytes) 00198 { 00199 int retVal = 0; 00200 00201 if (bytesBuffered == 0) { 00202 if (!readBuffer()) { 00203 return 0; 00204 } 00205 } 00206 00207 if (nrBytes <= bytesBuffered) { 00208 memcpy(buf, buffer + bytesRead + SAFETYDIST, nrBytes); 00209 bytesRead += nrBytes; 00210 bytesReadTotal += nrBytes; 00211 bytesBuffered -= nrBytes; 00212 retVal = nrBytes; 00213 } else { 00214 retVal = buffered_copy(buf, bytesBuffered); 00215 retVal += buffered_copy(buf+retVal, nrBytes-retVal); 00216 } 00217 00218 return retVal; 00219 } 00220 00221 00222 void BufferedHttpMPGStreamReader::goBack(int nrBytes) 00223 { 00224 bytesRead -= nrBytes; 00225 bytesReadTotal -= nrBytes; 00226 bytesBuffered += nrBytes; 00227 } 00228 00229 00230 Frame *BufferedHttpMPGStreamReader::getFrame() { 00231 if (writeOnly || state != OPEN) 00232 return NULL; 00233 00234 if (( (this->currentFrameNumber > this->endFrameNumber) && (endFrameNumber!=0) )) { // || feof(io)) { 00235 close(true); 00236 state=STREAMEOF; 00237 return NULL; 00238 } 00239 00240 // now read the frame 00241 AU *au = new AU(); 00242 Frame *frm = NULL; 00243 Frame::FrameType type = Frame::NN_VOP; 00244 00245 // parse MPGFile for VOB_Code if it is a visual stream 00246 00247 if(es->isVisualStream()) { 00248 // 00 00 01 182 dec -> 0x1B6 (=438 dec) 00249 u32 code = 2000; // don't init to 0, we want the code from the 2nd frame, not the first 00250 int i = 0; 00251 00252 u8 *data = new u8[MAX_FRAME_SIZE]; 00253 00254 do { 00255 data[i] = buffered_getc(); 00256 code = (code << 8) | data[i]; //(u8)buffered_getc(); 00257 i++; 00258 if ((i==4) && code == VOP_START_CODE) code = 0; 00259 } while ((code != VOP_START_CODE) && (i < maxFrameSize) && state != CLOSED); 00260 00261 if (code == VOP_START_CODE) { 00262 goBack(4); 00263 i -= 4; 00264 au->size = i; 00265 au->payload = new u8[i]; 00266 memcpy(au->payload, data, i); 00267 delete [] data; 00268 dprintf_full("BufferedHttpMPGStreamReader::getFrame() read %d bytes of video frame\n", i); 00269 } 00270 00271 if (au->size == 0) { 00272 state = STREAMEOF; 00273 delete au; 00274 return NULL; 00275 } 00276 00277 au->prio = IO_NETWORK_HIGHEST_PRIORITY; 00278 au->duration = es->getVOPTimeIncrement(); 00279 au->cts = currentFrameNumber * es->getVOPTimeIncrement(); 00280 au->dts = currentFrameNumber * es->getVOPTimeIncrement(); 00281 au->sampleFlags = 0; 00282 if (code != VOP_START_CODE) 00283 au->err = SA_EOF; 00284 else 00285 au->err = SA_OK; 00286 00287 } 00288 00289 if(es->isAudioStream()) { //XXX not sure if it works properly 00290 // start code for MP3 frame is 11111111 111 (first 11 bits set) 00291 u32 code = 2000; // don't init to 0, we want the code from the 2nd frame, not the first 00292 int i = 0; 00293 00294 //special handling for first frame 00295 if (framesSeen == 0) { 00296 int ch = 0; 00297 au->payload = new u8[1024]; 00298 do { 00299 ch = buffered_getc(); 00300 au->payload[i] = ch; 00301 i++; 00302 code = (code << 8) | ch; 00303 } 00304 while ((code>>21) != 0x000007FF /*VOP_START_CODE for audio(actually MP3)*/); 00305 au->size = i; 00306 } else { 00307 au->payload = new u8[MAX_FRAME_SIZE]; 00308 au->size = buffered_copy(au->payload, maxFrameSize); 00309 } 00310 00311 dprintf_full("BufferedHttpMPGStreamReader::getFrame() read %d bytes of audio frame\n", au->size); 00312 00313 au->cts = DTS; 00314 au->dts = DTS; 00315 au->duration = 0; 00316 au->sampleFlags = 0; 00317 au->err = SA_OK; 00318 00319 DTS += es->getVOPTimeIncrement(); 00320 } 00321 00322 // frame types will be detected in frm->setAU()! 00323 if(es->isVisualStream()) 00324 frm = new CompressedVideoFrame(type, ((VideoESInfo*)es)->getWidth(), ((VideoESInfo*)es)->getHeight()); 00325 else if(es->isAudioStream()) 00326 frm=new CompressedAudioFrame(type); 00327 else 00328 frm = new CompressedVideoFrame(type, 0, 0); 00329 frm->setAU(au); 00330 frm->setMediaTimeScale(es->getMediaTimeScale()); 00331 framesSeen++; 00332 currentFrameNumber++; 00333 00334 00335 #ifdef _POSIX_PRIORITY_SCHEDULING 00336 sched_yield(); 00337 #else 00338 // for windows pthread lib! 00339 #ifdef WIN32 00340 #ifndef WINCE 00341 sched_yield(); 00342 #else 00343 Sleep(1); 00344 #endif 00345 #endif 00346 #endif 00347 00348 return frm; 00349 } 00350 00351