Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members
MPGStreamIO.cpp
00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: MPGStreamIO.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 "MPGStreamIO.hpp" 00045 #include "VideoESInfo.hpp" 00046 #include "CompressedVideoFrame.hpp" 00047 #include "CompressedAudioFrame.hpp" 00048 #include "IO.hpp" 00049 #include "../net/SDP.hpp" 00050 #include "BitField.hpp" 00051 00052 #include "../container/ISOMP4ContainerFile.hpp" 00053 00054 MPGStreamIO::MPGStreamIO(ESInfo * esi, const char *file, bool write, bool omit):IO() { 00055 dprintf_full("MPGStreamIO::MPGStreamIO file=%s writeonly=%s\n",(file?file:"NULL"),(write?"WRITE":"READ")); 00056 assert(esi); 00057 writeOnly=write; 00058 omitHeader = omit; 00059 if (!file) 00060 url = NULL; 00061 else { 00062 url = new char[strlen(file) + 1]; 00063 strcpy(url, file); 00064 } 00065 lastCTSSeen=0; 00066 io = NULL; 00067 es = esi; 00068 helpFile = NULL; 00069 writeHelpFile = true; 00070 atFileStart = true; 00071 state = CLOSED; 00072 currentFrameNumber=0; 00073 endFrameNumber=0; 00074 } 00075 00076 00077 MPGStreamIO::~MPGStreamIO() { 00078 dprintf_full("MPGStreamIO::~MPGStreamIO()\n"); 00079 if (state != CLOSED) 00080 close(); 00081 if (io) { 00082 dprintf_full("MPGStreamIO::~MPGStreamIO() closed file in destr.\n"); 00083 fclose(io); 00084 io=NULL; 00085 } 00086 if (helpFile) 00087 fclose(helpFile); 00088 00089 if (url) 00090 delete[] url; 00091 } 00092 00093 00096 bool MPGStreamIO::open() { 00097 00098 if(!url) { 00099 // try to get localfile from esinfo 00100 const char* tmpUrl=es->getInput(); 00101 if(tmpUrl) { 00102 url=new char[strlen(tmpUrl)+1]; 00103 strcpy(url,tmpUrl); 00104 } 00105 else 00106 return false; 00107 } 00108 00109 dprintf_full("MPGStreamIO::open() Trying to open %s\r\n", url); 00110 if(state==OPEN) 00111 return true; 00112 00113 bool ret = false; 00114 atFileStart = true; 00115 state = OPENING; 00116 lastCTSSeen=0; 00117 char *name = new char[512]; 00118 strcpy(name,url); 00119 strcat(name,".hint"); 00120 00121 if (writeOnly) { 00122 // we want to write to a local file 00123 // reset statistic 00124 dprintf_full("MPGStreamIO::open(): resetting Statistic to %u dur %u ticks %u\n", 00125 es->getNumberOfMediaSamples(),(unsigned)es->getDuration(), 00126 es->getVOPTimeIncrement()); 00127 es->disableFrameStatistic(); 00128 es->enableFrameStatistic(); 00129 if (writeHelpFile) { 00130 if(helpFile) 00131 fclose(helpFile); 00132 helpFile = fopen(name,"wb"); 00133 if (!helpFile) { 00134 helpFile = NULL; 00135 writeHelpFile = false; 00136 } 00137 } 00138 if(io) { 00139 // safety check, shouldn't happen 00140 fclose(io); 00141 } 00142 io=fopen(url,"wb"); 00143 ret = (io!=NULL); 00144 } else { 00145 // we want to read from a local file 00146 if (writeHelpFile) { 00147 helpFile = fopen(name,"rb"); 00148 if (helpFile) { 00149 fseek(helpFile,0,SEEK_END); 00150 if (ftell(helpFile) == 0){ //zero length 00151 fclose(helpFile); 00152 helpFile = NULL; 00153 } else 00154 fseek(helpFile,0,SEEK_SET); 00155 } 00156 00157 if (!helpFile) { 00158 dprintf_full("MPGStreamIO::open no valid .hint file found, ignoring...\n"); 00159 helpFile = NULL; 00160 writeHelpFile = false; 00161 } else { 00162 dprintf_full("MPGStreamIO::open using and relying on .hint file %s\n",name); 00163 } 00164 } 00165 io=fopen(url,"rb"); 00166 ret = (io!=NULL); 00167 } 00168 00169 if (ret) 00170 state = OPEN; 00171 else 00172 state = CLOSED; 00173 currentFrameNumber=0; 00174 framesSeen=0; 00175 delete [] name; 00176 return ret; 00177 } 00178 00179 00180 bool MPGStreamIO::close(bool immediate) { 00181 state = CLOSING; 00182 if (io) { 00183 fclose(io); 00184 io=NULL; 00185 } 00186 if (helpFile) { 00187 fclose(helpFile); 00188 helpFile=NULL; 00189 } 00190 state = CLOSED; 00191 // this->es->setDuration(lastCTSSeen+es->getVOPTimeIncrement()); 00192 return true; 00193 } 00194 00195 00197 int MPGStreamIO::writeFrame(Frame * frm, ESInfo *out_es) { 00198 if(!frm) 00199 return 0; 00200 00201 if (!writeOnly || state != OPEN) { 00202 dprintf_small("MPGStreamIO esID %llu Warning: Output is readonly or not open\n", es->getStreamId()); 00203 return -1; 00204 } 00205 00206 00207 00208 // drop frames we have already written!! 00209 if(lastCTSSeen>=frm->getAU()->cts && lastCTSSeen!=0) { 00210 dprintf_small("MPGStreamIO::writeFrame Dropping Frame %u\n",frm->getAU()->cts); 00211 return 0; 00212 } 00213 else 00214 lastCTSSeen=frm->getAU()->cts; 00215 00216 if (frm->getAU()->size == 0) { 00217 dprintf_small("MPGStreamIO::writeFrame esID %llu: Cannot write zero sized frames\n", es->getStreamId()); 00218 return 0; 00219 } 00220 00221 u32 frmBitIndex=frm->getAU()->cts/es->getVOPTimeIncrement(); 00222 dprintf_full("MPGStreamIO::writeFrame CTS %u(%u), size %u(%u %u %u %u...), VOPINC %u\n", 00223 frm->getAU()->cts,frmBitIndex,frm->getAU()->size,frm->getAU()->payload[0], 00224 frm->getAU()->payload[1],frm->getAU()->payload[2],frm->getAU()->payload[3], 00225 es->getVOPTimeIncrement()); 00226 00227 // write header right in front of first frame!!! 00228 if (atFileStart && !omitHeader) { 00229 atFileStart = false; 00230 if (!saveHeader()) { 00231 dprintf_small("MPGStreamIO::writeFrame esID %llu: failed to save header\n", es->getStreamId()); 00232 return -1; 00233 } 00234 } 00235 00236 // save the frame 00237 int i = (frm->getAU()->size == 00238 fwrite(frm->getAU()->payload,sizeof(char), frm->getAU()->size,io)); 00239 framesSeen++; 00240 es->getFrameStatistic()->setBit(frmBitIndex); 00241 if (writeHelpFile) 00242 writeHelpInfo(frm); 00243 #ifdef _POSIX_PRIORITY_SCHEDULING 00244 sched_yield(); 00245 #else 00246 // for windows pthread lib! 00247 #ifndef WINCE 00248 sched_yield(); 00249 #else 00250 Sleep(0); 00251 #endif 00252 #endif 00253 00254 return i; 00255 } 00256 00257 00262 Frame *MPGStreamIO::getFrame() { 00263 if (writeOnly || state != OPEN) 00264 return NULL; 00265 00266 if (atFileStart) { 00267 atFileStart = false; 00268 //FIXME: why we need to call this for audiostream also? 00269 //if (es->isVisualStream()) { 00270 if (!readHeader()) 00271 state=STREAMERR; 00272 return NULL; 00273 //} 00274 } 00275 if (( (this->currentFrameNumber > this->endFrameNumber) && (endFrameNumber!=0) ) || feof(io)) { 00276 close(true); 00277 state=STREAMEOF; 00278 return NULL; 00279 } 00280 00281 // now read the frame 00282 // first check hintfile 00283 AU *au = new AU(); 00284 Frame *frm = NULL; 00285 Frame::FrameType type = Frame::NN_VOP; 00286 00287 if (writeHelpFile) { 00288 // read one AU entry from the file 00289 int auSize = sizeof(AU) - sizeof(u8 *); 00290 int tmp = 0; 00291 if (auSize != (tmp = fread((char *) &(au->size),sizeof(char),auSize,helpFile))) { 00292 if (tmp <= 0) { 00293 // last frame 00294 state = STREAMEOF; 00295 delete au; 00296 return NULL; 00297 } 00298 dprintf_err("MPGStreamIO::getFrame() esID %llu: Mismatch in hintfile. Expected %i bytes, but just got %i?\r\n", 00299 es->getStreamId(), auSize, tmp); 00300 00301 state = STREAMEOF; 00302 delete au; 00303 return NULL; 00304 } 00305 else { // au is correct 00306 // read the AU 00307 au->payload = new u8[au->size]; 00308 assert(au->payload); 00309 if ((unsigned long) au->size != fread(au->payload,sizeof(char),au->size,io)) { 00310 dprintf_err("MPGStreamIO::getFrame(): Mismatch in data & hintfile. Not enough data?\r\n"); 00311 delete au; 00312 state= STREAMERR; 00313 return NULL; 00314 } 00315 dprintf_full("MPGStreamIO::getFrame(): got hinted info CTS %i prio: %i\n",au->cts,au->prio); 00316 } 00317 } 00318 else { // no help stream available, how to calc cts and dts? 00319 00320 // parse MPGFile for VOB_Code if it is a visual stream 00321 // FIXME: do Audio streams have a different VOP Code?? 00322 00323 if(es->isVisualStream()) { 00324 // 00 00 01 182 dec -> 0x1B6 (=438 dec) 00325 u32 code = 2000; // don't init to 0, we want the code from the 2nd frame, not the first 00326 int ch; 00327 int i = 0; 00328 char *data = new char[MAX_FRAME_SIZE]; 00329 do { 00330 ch = getc(io); 00331 data[i] = (u8)ch; 00332 i++; 00333 code = (code << 8) | (u8)ch; 00334 if ((i==4) && code == VOP_START_CODE) 00335 code =0; //correct beginning, parse until next START_CODE 00336 } 00337 while ((i < MAX_FRAME_SIZE) && (ch != EOF) && (code != VOP_START_CODE)); 00338 00339 if (code == VOP_START_CODE) { 00340 // put back the VOP_HEADER 00341 // seek back 4 bytes 00342 fseek(io, -4, SEEK_CUR); 00343 au->size = i; 00344 } 00345 00346 if (au->size == 0) { 00347 state = STREAMEOF; 00348 delete au; 00349 return NULL; 00350 } 00351 00352 au->payload = new u8[i]; 00353 memcpy(au->payload, data, i); 00354 au->prio = IO_NETWORK_HIGHEST_PRIORITY; 00355 au->duration = es->getVOPTimeIncrement(); 00356 au->cts = currentFrameNumber * es->getVOPTimeIncrement(); 00357 au->dts = currentFrameNumber * es->getVOPTimeIncrement(); 00358 au->sampleFlags = 0; 00359 if (code != VOP_START_CODE) 00360 au->err = SA_EOF; 00361 else 00362 au->err = SA_OK; 00363 00364 00365 delete data; 00366 } 00367 00368 if(es->isAudioStream()) { //XXX not sure if it works properly 00369 dprintf_err("MPGStreamIO audioStream parsing\n\n"); 00370 // start code for MP3 frame is 11111111 111 (first 11 bits set) 00371 u32 code = 2000; // don't init to 0, we want the code from the 2nd frame, not the first 00372 int ch; 00373 int i = 0; 00374 char *data = new char[165536]; 00375 do { 00376 ch = getc(io); 00377 data[i] = ch; 00378 i++; 00379 code = (code << 8) | ch; 00380 } 00381 while ((ch != -1) && 00382 (code>>21 != 0x000007FF /*VOP_START_CODE for audio(actually MP3)*/)) 00383 ; 00384 if (code>>21 == 0x000007FF /*VOP_START_CODE*/) { 00385 // put back the VOP_HEADER 00386 // seek back 4 bytes 00387 fseek(io, -4, SEEK_CUR); 00388 /* 00389 ungetc(182,io); 00390 ungetc(1,io); 00391 ungetc(0,io); 00392 ungetc(0,io); */ 00393 au->size = i; 00394 } 00395 au->payload = new u8[i]; 00396 memcpy(au->payload, data, i); 00397 au->cts = 0; 00398 au->dts = 0; 00399 au->duration = 0; 00400 au->sampleFlags = 0; 00401 if (code>>21 != 0x000007FF /*VOP_START_CODE*/) 00402 au->err = SA_EOF; 00403 else 00404 au->err = SA_OK; 00405 00406 delete [] data; 00407 } 00408 } 00409 00410 00411 //FIXME: quickhack to assign priorities, if no Hint file is avail (eg. direct access to .cmp files!) 00412 if (es->isVisualStream() && !writeHelpFile) { 00413 if (au->payload[0] == 0 && au->payload[1] == 0 && 00414 au->payload[2] == 1 && au->payload[3] == 182) { 00415 type = (Frame::FrameType) ((au->payload[4]) >> 6); 00416 if (type == Frame::I_VOP || type == Frame::P_VOP) 00417 au->prio = IO_NETWORK_HIGHEST_PRIORITY; 00418 else 00419 au->prio = ~IO_NETWORK_HIGHEST_PRIORITY; 00420 } 00421 } 00422 00423 // frame types will be detected in frm->setAU()! 00424 00425 if(es->isVisualStream()) 00426 frm = new CompressedVideoFrame(type, ((VideoESInfo*)es)->getWidth(), ((VideoESInfo*)es)->getHeight()); 00427 else if(es->isAudioStream()) 00428 frm=new CompressedAudioFrame(type); 00429 else 00430 frm = new CompressedVideoFrame(type, 0, 0); 00431 frm->setAU(au); 00432 frm->setMediaTimeScale(es->getMediaTimeScale()); 00433 framesSeen++; 00434 currentFrameNumber++; 00435 dprintf_full("MPGStreamIO::getFrame: file offset %li cts %i dts %i type %s (%x %x %x %x) size %i, frameNo %u\r\n", 00436 ftell(io),au->cts,au->dts, 00437 Frame::VOPTypeToChar((Frame::VOP_TYPE)frm->getAU()->frameType), 00438 frm->getAU()->payload[0],frm->getAU()->payload[1],frm->getAU()->payload[2],frm->getAU()->payload[3], 00439 frm->getAU()->size, 00440 getCurrentFrameNumber()); 00441 00442 #ifdef _POSIX_PRIORITY_SCHEDULING 00443 sched_yield(); 00444 #else 00445 // for windows pthread lib! 00446 #ifdef WIN32 00447 #ifndef WINCE 00448 sched_yield(); 00449 #else 00450 Sleep(0); 00451 #endif 00452 #endif 00453 #endif 00454 00455 return frm; 00456 } 00457 00458 00459 bool MPGStreamIO::saveHeader() { 00460 int size; 00461 00462 // if we have a network connection we never write the header into 00463 // the data stream, the header is typically found in the SDP desc. 00464 dprintf_full("MPGStreamIO::saveHeader\n"); 00465 if (!io) 00466 return true; 00467 00468 const u8 *encConf = es->getEncodedDecoderConfig(); 00469 if (!encConf || (size = strlen((const char *) encConf)) == 0) { 00470 dprintf_err("MPGStreamIO::saveHeader esID %llu: Failed to get EncodedDecoderConfig, got %s\n", 00471 es->getStreamId(), encConf); 00472 return false; 00473 } 00474 00475 u8 *decConf = new u8[size / 2+1]; 00476 SDP::decodeDecoderConfig(decConf, encConf, size); 00477 // problem: decoderConfig is some extended Header 00478 // we have some leading bytes, and then we have 00 00 01h, the start of the header 00479 // so search for this hex value 00480 int i = 0; 00481 u32 data = 0xFFFFFFFF; 00482 u32 offset = 0; 00483 // generic streams have different headers 00484 if (!es->isVisualStream() && !es->isAudioStream()) { 00485 i = size / 2; 00486 } 00487 00488 bool headerFound=false; 00489 while (i < size / 2 - 1) { 00490 printf("%x\t",data); 00491 data <<= 8; 00492 data += decConf[i]; 00493 i++; 00494 if (data != 0x00000100) { 00495 headerFound = true; 00496 break; 00497 } 00498 } 00499 if (headerFound) { // we have read 2 zeros followed by a 1 00500 // set offset to point to the first 0 00501 // i points after the 1 -> header is 00 00 01 xx-> reduce by 3 00502 // 00 01 02 03 00 00 01 xx -> i=7 -> i=4 00503 if (i > (signed)sizeof(data)) 00504 offset = i - sizeof(data) + 1; 00505 else 00506 offset = 0; 00507 00508 dprintf_full("MPGStreamIO: Found header in decconf %x at offset %i\n", data, offset); 00509 // save the header to the hintstream if possible 00510 if (helpFile) { 00511 // first save the size of the decoder config 00512 char intTemp[20]; 00513 intTemp[0] = 0; 00514 sprintf(intTemp, "%i\n", size / 2); 00515 fwrite(intTemp, 1, strlen(intTemp), helpFile); 00516 // then save the decoder config 00517 fwrite(decConf,1, size/2,helpFile); 00518 } 00519 } else { 00520 dprintf_err("MPGStreamIO::saveHeader: Missing Header for esID %llu\n", es->getStreamId()); 00521 fwrite("0\n", 1, 2, helpFile); 00522 } 00523 bool ret = ((size / 2 - offset) == ((u32)fwrite((char *) (decConf + offset), 1, size / 2 - offset, io))); 00524 dprintf_full("MPGStreamIO::saveHeader: Offset is %i, first 4 bytes are %x %x %x %x, status: %s\n", 00525 offset, decConf[offset], decConf[offset + 1], decConf[offset + 2], 00526 decConf[offset + 3], ret?"written":"WRITE FAILED"); 00527 if (writeHelpFile) { 00528 char tmp[20]; 00529 tmp[0]=0; 00530 sprintf(tmp, "%i\n",(size / 2 - offset)); 00531 fwrite(tmp,1,strlen(tmp),helpFile); 00532 } 00533 00534 delete[] decConf; 00535 return ret; 00536 } 00537 00538 00539 bool MPGStreamIO::readHeader() { 00540 char *header = new char[MAX_HEADERS_SIZE]; 00541 00542 if (!io) { 00543 dprintf_full("MPGStreamIO::readHeader: cannot read header from network device\n"); 00544 delete [] header; 00545 return true; 00546 } 00547 int headerSize = 0; 00548 int extHeaderSize = 0; 00549 long currentHelpPos=0; 00550 00551 if (writeHelpFile) { 00552 // Format: <size of the extended header> \n <extendedheader> <headerSize>\n 00553 // read the headerSize from the helpFile 00554 00555 if(helpFile) 00556 currentHelpPos=ftell(helpFile); 00557 00558 fseek(helpFile,0, SEEK_SET); 00559 00560 char line[20]; 00561 if (fgets(line,20, helpFile) != NULL) { 00562 dprintf_full("DecConf Size is %s\n", line); 00563 if (sscanf(line, "%i", &extHeaderSize) != 1) 00564 extHeaderSize = 0; 00565 else { 00566 // we know the ext header size 00567 // extract header 00568 if (extHeaderSize > 0 00569 && extHeaderSize == (signed)fread(header,1,extHeaderSize,helpFile)) 00570 { 00571 header[extHeaderSize] = 0; 00572 es->setDecoderConfig((u8 *) header, extHeaderSize); 00573 } 00574 } 00575 // now read the header size 00576 if (fgets(line,20, helpFile) != NULL) { 00577 if (sscanf(line, "%i", &headerSize) != 1) 00578 headerSize = 0; 00579 } 00580 } 00581 } 00582 if (headerSize == 0) { // FIXME: header!=decoderConfig -> we loose part of the decConf in this case 00583 // parse MPGFile for first VOB_Code 00584 // 0d 0d 1d 182d -> 0x1B6 00585 u32 code = 0; 00586 int ch; 00587 int i = 0; 00588 fseek(io, 0, SEEK_SET); 00589 do { 00590 ch = fgetc(io); 00591 header[i] = ch; 00592 i++; 00593 code = (code << 8) | (u8)ch; 00594 // dprintf_err("MPGStreamIO::readHeader %i %x %x\n",i,ch, code); 00595 } 00596 while ((i<MAX_HEADERS_SIZE) && (ch != EOF) && (code != VOP_START_CODE)); 00597 00598 if (code != VOP_START_CODE) { 00599 dprintf_err("MPGStreamIO::readHeader Error: not even one VOP_START_CODE found!\r\n"); 00600 if(currentHelpPos>0) 00601 fseek(helpFile,currentHelpPos,SEEK_SET); 00602 delete [] header; 00603 return false; 00604 } 00605 // put back the first VOP_HEADER 00606 fseek(io, -4, SEEK_CUR); 00607 00608 headerSize = ftell(io); 00609 header[headerSize] = 0; 00610 // set header 00611 if (extHeaderSize == 0) 00612 es->setDecoderConfig((u8 *) header, headerSize); 00613 if(currentHelpPos>0) 00614 fseek(helpFile,currentHelpPos,SEEK_SET); 00615 delete [] header; 00616 return true; 00617 } else { 00618 // we know the header size 00619 // skip header 00620 if (headerSize == (signed)fread(header, 1, headerSize, io)) { 00621 if(currentHelpPos>0) 00622 fseek(helpFile,currentHelpPos,SEEK_SET); 00623 delete [] header; 00624 return true; 00625 } 00626 } 00627 dprintf_err("MPGStreamIO:readHeader: Should never happen :-D"); 00628 if(currentHelpPos>0) 00629 fseek(helpFile,currentHelpPos,SEEK_SET); 00630 delete [] header; 00631 return false; 00632 } 00633 00634 00635 void MPGStreamIO::writeHelpInfo(const Frame * frm) { 00636 // write one AU 00637 char *temp = frm->getAU()->toString(); 00638 int size = sizeof(AU) - sizeof(u8 *); 00639 fwrite(temp,1,size,helpFile); 00640 delete[] temp; 00641 } 00642 00643 00644 bool MPGStreamIO::destroy() { 00645 // if we have a network connection we have got nothing to delete 00646 // so return true 00647 00648 if (!io) 00649 return true; 00650 00651 close(); 00652 #ifndef WINCE 00653 bool err = (remove(url) == 0); 00654 #else 00655 bool err = (DeleteFile((LPCTSTR)url) != 0); 00656 #endif 00657 if (helpFile) { 00658 char *name = new char[512]; 00659 strcpy(name,url); 00660 strcat(name,".hint"); 00661 #ifndef WINCE 00662 err &= (remove(name) == 0); 00663 #else 00664 err &= (DeleteFile((LPCTSTR)name) != 0); 00665 #endif 00666 delete [] name; 00667 } 00668 00669 return err; 00670 } 00671 00672 00673 bool MPGStreamIO::setToFrameNumber(u32 frameNumber) { 00674 // check if valid 00675 // e.g.: writeOnly streams can not be seeked 00676 if(writeOnly) { 00677 dprintf_err("MPGStreamIO::setToFrameNumber(u32 %i) failed: MPGStreamIO opened for writing\n",frameNumber); 00678 return false; 00679 } 00680 dprintf_full("MPGStreamIO::setToFrameNumber: current is %i, new is %i\n",currentFrameNumber,frameNumber); 00681 if(!io) { 00682 // shouldn't happen??? reset class 00683 dprintf_small("MPGStreamIO::setToFrameNumber(u32 %i): called on closed MPGStreamIO\n",frameNumber); 00684 close(true); 00685 open(); 00686 } 00687 if(!io) { 00688 dprintf_err("MPGStreamIO::setToFrameNumber(u32 %i) failed: couldn't open input %s?\n",frameNumber,url); 00689 return false; 00690 } 00691 dprintf_full("MPGStreamIO::setToFrameNumber(u32 %i)\r\n",frameNumber); 00692 long currentFilePos=ftell(io); 00693 long currentHelpPos=0; 00694 00695 if(helpFile) 00696 currentHelpPos=ftell(helpFile); 00697 long newFilePos=currentFilePos; 00698 00699 // readonly stream 00700 if(currentFrameNumber!=frameNumber) { 00701 // reposition 00702 if(frameNumber==0) { 00703 // set to beginning 00704 fseek(io,0,SEEK_SET); 00705 if(helpFile) 00706 fseek(helpFile,0, SEEK_SET); 00707 atFileStart = true; 00708 currentFrameNumber=0; // I-frame always true 00709 return true; 00710 } 00711 else { 00712 int auSize = sizeof(AU) - sizeof(u8 *); 00713 int tmp=0; 00714 00715 AU *au=NULL; 00716 atFileStart = false; 00717 if(currentHelpPos==0) { 00718 readHeader(); 00719 u8* temp=NULL; 00720 newFilePos+=this->es->getHeaders(&temp); 00721 if(temp) 00722 delete[] temp; 00723 } 00724 00725 while(currentFrameNumber!=frameNumber) { 00726 if(writeHelpFile) { 00727 // seeking easy: load data from helpFile 00728 00729 au = new AU(); 00730 00731 //seek forward or backward 00732 00733 if(frameNumber>currentFrameNumber) { 00734 // seek forward 00735 tmp = fread((char *) &(au->size), 1, auSize, helpFile); 00736 if(auSize!=tmp) { 00737 // if a seek fails undo all changes to filepointers 00738 fseek(helpFile,currentHelpPos,SEEK_SET); 00739 fseek(io,currentFilePos,SEEK_SET); 00740 dprintf_err("MPGStreamIO::setToFrameNumber: failed to seek forward\n"); 00741 delete au; 00742 return false; 00743 } 00744 // dprintf_full("MPGStreamIO::setToFrameNumber: cur=%i new=%i newFP=%li addedAUSize=%i\n", 00745 // currentFrameNumber,frameNumber,newFilePos,au->size); 00746 newFilePos+=au->size; 00747 currentFrameNumber++; 00748 delete au; 00749 00750 } 00751 else { // seek backward 00752 // go back one au entry 00753 fseek(helpFile,-auSize,SEEK_CUR); 00754 tmp = fread((char *) &(au->size), 1, auSize, helpFile); 00755 // now that we have read the au, reset it to 00756 // the previous position 00757 fseek(helpFile,-auSize,SEEK_CUR); 00758 00759 if(auSize!=tmp) { 00760 // if a seek fails undo all changes to filepointers 00761 fseek(helpFile,currentHelpPos,SEEK_SET); 00762 fseek(io,currentFilePos,SEEK_SET); 00763 dprintf_err("MPGStreamIO::setToFrameNumber: failed to seek backward\n"); 00764 delete au; 00765 return false; 00766 } 00767 newFilePos-=au->size; 00768 currentFrameNumber--; 00769 delete au; 00770 } 00771 } 00772 else { 00773 // no HelpFile 00774 // we could parse vor VOP header, but we don't :-) 00775 dprintf_err("MPGStreamIO::setToFrameNumber: failed. no helpfile\n"); 00776 return false; 00777 } 00778 } // while 00779 00780 // if we come that far, we can reposition the movie 00781 if(newFilePos>0) { 00782 //helpFile should be at correct position 00783 fseek(io,newFilePos,SEEK_SET); 00784 currentFrameNumber=frameNumber; 00785 return true; 00786 } 00787 else { 00788 // BUG??? We tried to set to a negative position 00789 dprintf_err("MPGStreamIO::setToFrameNumber: Negative new file pointer\r\n"); 00790 // just set to zero; 00791 // set to beginning 00792 fseek(io,0,SEEK_SET); 00793 if(helpFile) 00794 fseek(helpFile,0, SEEK_SET); 00795 atFileStart = true; 00796 currentFrameNumber=0; 00797 00798 return true; 00799 } 00800 } 00801 00802 } 00803 else { 00804 // no need to reposition 00805 return true; 00806 } 00807 return true; 00808 } 00809 00810 00811 long MPGStreamIO::setToClosestIFrame(u32 frameNumber, bool backwards) { 00812 dprintf_full("MPGStreamIO::setToClosestIFrame searching direction: %s\n",backwards?"backwards":"forwards"); 00813 if(!setToFrameNumber(frameNumber)) 00814 return (-1); 00815 00816 00817 if(frameNumber==0 || es->isAudioStream()) { 00818 dprintf_full("MPGStreamIO::setToClosestIFrame returning %u (%s stream)\n", 00819 frameNumber, es->isAudioStream() ? "audio" : "video"); 00820 return frameNumber; 00821 } 00822 00823 long currentFilePos=ftell(io); 00824 long currentHelpPos=0; 00825 long storedFrameNumber = currentFrameNumber; 00826 int auSize = sizeof(AU) - sizeof(u8 *); 00827 int tmp=0; 00828 AU au; 00829 00830 if(helpFile) 00831 currentHelpPos=ftell(helpFile); 00832 00833 long newFilePos=currentFilePos; 00834 bool firstFrame=true; 00835 00836 // get the AU for the next read Frame call 00837 tmp = fread((char *) &(au.size), 1, auSize, helpFile); 00838 if (auSize==tmp) { 00839 newFilePos+=au.size; 00840 } else { 00841 //FIXME: maybe we have probs on very last frame :( 00842 state=STREAMERR; 00843 } 00844 00845 while ((currentFrameNumber>=0) && (currentFrameNumber <= es->getNumberOfMediaSamples())) { 00846 if (backwards || firstFrame) { 00847 fseek(helpFile, -auSize, SEEK_CUR); 00848 } 00849 tmp = fread((char *) &(au.size), 1, auSize, helpFile); 00850 00851 if(auSize!=tmp) { 00852 // if a seek fails undo all changes to filepointers 00853 fseek(helpFile,currentHelpPos,SEEK_SET); 00854 fseek(io,currentFilePos,SEEK_SET); 00855 currentFrameNumber = storedFrameNumber; 00856 dprintf_err("MPGStreamIO::setToClosestIFrame: failed to set to I-frame\n"); 00857 return currentFrameNumber; 00858 } 00859 dprintf_full("frame %i type %s CTS %i\n",currentFrameNumber,Frame::VOPTypeToChar((Frame::VOP_TYPE)au.frameType),au.cts); 00860 if (backwards) { 00861 fseek(helpFile,-auSize,SEEK_CUR); 00862 newFilePos -= au.size; 00863 } 00864 if (!backwards && !firstFrame) { 00865 newFilePos += au.size; 00866 } 00867 firstFrame=false; 00868 00869 if(au.frameType==(u32)Frame::I_VOP 00870 || au.frameType == (u32) Frame::HEADER_VOP) { 00871 dprintf_full("MPGStreamIO::setToClosestIFrame: found %s at frame %i\n", 00872 Frame::VOPTypeToChar((Frame::VOP_TYPE)au.frameType), currentFrameNumber); 00873 if (!backwards) { //go back to actual frame 00874 newFilePos -= au.size; 00875 fseek(helpFile,-auSize,SEEK_CUR); 00876 } 00877 // point to last read AU in MPGStream 00878 fseek(io,newFilePos,SEEK_SET); 00879 return currentFrameNumber; 00880 } 00881 if (backwards) 00882 currentFrameNumber--; 00883 else 00884 currentFrameNumber++; 00885 } 00886 00887 00888 //error: reset to beginning or end 00889 dprintf_err("MPGStreamIO::setToClosestIFrame() FAILED, currentFrameNumber = %u, nMediaSamples = %u " 00890 "repositioning to %s\n", 00891 currentFrameNumber, es->getNumberOfMediaSamples(), 00892 backwards ? "START" : "END"); 00893 if (backwards) { 00894 fseek(io,0,SEEK_SET); 00895 if(helpFile) 00896 fseek(helpFile,0, SEEK_SET); 00897 atFileStart = true; 00898 currentFrameNumber=0; 00899 } else { 00900 fseek(io,0,SEEK_END); 00901 if(helpFile) 00902 fseek(helpFile,0, SEEK_END); 00903 atFileStart = false; 00904 currentFrameNumber=es->getNumberOfMediaSamples(); 00905 close(true); 00906 state=STREAMEOF; 00907 } 00908 return currentFrameNumber; 00909 }