00001 //=========================================================================== 00002 //Copyright (C) 2003, 2004 Zentaro Kavanagh 00003 // 00004 //Redistribution and use in source and binary forms, with or without 00005 //modification, are permitted provided that the following conditions 00006 //are met: 00007 // 00008 //- Redistributions of source code must retain the above copyright 00009 // notice, this list of conditions and the following disclaimer. 00010 // 00011 //- Redistributions in binary form must reproduce the above copyright 00012 // notice, this list of conditions and the following disclaimer in the 00013 // documentation and/or other materials provided with the distribution. 00014 // 00015 //- Neither the name of Zentaro Kavanagh nor the names of contributors 00016 // may be used to endorse or promote products derived from this software 00017 // without specific prior written permission. 00018 // 00019 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00020 //``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00022 //PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR 00023 //CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00024 //EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00025 //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00026 //PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00027 //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00028 //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00029 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 //=========================================================================== 00031 00032 #include "stdafx.h" 00033 #include <libOOOgg/OggDataBuffer.h> 00034 00035 00036 //LEAK CHECKED - 2004/10/17 - OK. 00037 //LEAK FOUND - 2004/11/29 - acceptOggPage 00038 OggDataBuffer::OggDataBuffer(void) 00039 : mBuffer(NULL) 00040 , mPrevGranPos(0) 00041 , pendingPage(NULL) 00042 , mState(AWAITING_BASE_HEADER) 00043 , mNumBytesNeeded(OggPageHeader::OGG_BASE_HEADER_SIZE) 00044 { 00045 mBuffer = new CircularBuffer(MAX_OGG_PAGE_SIZE); //Deleted in destructor 00046 //debugLog.open("G:\\logs\\OggDataBuffer.log", ios_base::out); 00047 } 00048 00049 //Debug only 00050 //OggDataBuffer::OggDataBuffer(bool x) 00051 // : mBuffer(NULL) 00052 // , mPrevGranPos(0) 00053 //{ 00054 // mBuffer = new CircularBuffer(MAX_OGG_PAGE_SIZE); //Deleted in destructor 00055 // 00056 // //debugLog.open("G:\\logs\\OggDataBufferSeek.log", ios_base::out); 00057 // pendingPage = NULL; 00058 // mState = AWAITING_BASE_HEADER; 00059 // mNumBytesNeeded = OggPageHeader::OGG_BASE_HEADER_SIZE; 00060 //} 00061 // 00062 00063 OggDataBuffer::~OggDataBuffer(void) 00064 { 00065 delete mBuffer; 00066 delete pendingPage; 00067 //debugLog.close(); 00068 00069 } 00070 00071 00080 bool OggDataBuffer::registerStaticCallback(fPageCallback inPageCallback, void* inUserData) 00081 { 00082 //Holds the static callback and nulls the virtual one. 00083 mStaticCallback = inPageCallback; 00084 mStaticCallbackUserData = (void *) inUserData; 00085 mVirtualCallback = NULL; 00086 00087 return true; 00088 } 00089 00090 //bool OggDataBuffer::registerSerialNo(SerialNoRego* inSerialRego) { 00091 // if (inSerialRego != NULL) { 00092 // mSerialNoCallList.push_back(inSerialRego); 00093 // return true; 00094 // } else { 00095 // return false; 00096 // } 00097 //} 00098 00099 00105 bool OggDataBuffer::registerVirtualCallback(IOggCallback* inPageCallback) { 00106 //Holds the virtual callback and nulls the static one. 00107 mVirtualCallback = inPageCallback; 00108 mStaticCallback = NULL; 00109 00110 return true; 00111 00112 } 00113 00114 00115 unsigned long OggDataBuffer::numBytesAvail() { 00116 //Returns how many bytes are available in the buffer 00117 unsigned long locBytesAvail = mBuffer->numBytesAvail(); 00118 00119 //debugLog<<"Bytes avail = "<<locBytesAvail<<endl; 00120 return locBytesAvail; 00121 } 00122 00123 OggDataBuffer::eState OggDataBuffer::state() { 00124 //returns the state of the stream 00125 return mState; 00126 } 00127 //This function accepts the responsibility for the incoming page. 00128 OggDataBuffer::eDispatchResult OggDataBuffer::dispatch(OggPage* inOggPage) { 00129 //TODO::: Who owns this pointer inOggPage ? 00130 00131 //debugLog<<"Dispatching page..."<<endl<<endl; 00132 00133 //Fire off the oggpage to whoever is registered to get it 00134 if (mVirtualCallback != NULL) { 00135 if (mVirtualCallback->acceptOggPage(inOggPage) == true) { //Page given away, never used again. 00136 return DISPATCH_OK; 00137 } else { 00138 return DISPATCH_FALSE; 00139 } 00140 } else if (mStaticCallback != NULL) { 00141 if (mStaticCallback(inOggPage, mStaticCallbackUserData) == true) { 00142 return DISPATCH_OK; 00143 } else { 00144 return DISPATCH_FALSE; 00145 } 00146 } 00147 00148 //Delete the page... if the called functions wanted a copy they should have taken one for themsselves. 00149 //Not any more acceptOggPage takes responsibility for the memory you pass into it. See IOggCallback.h 00150 //delete inOggPage; 00151 pendingPage = NULL; 00152 return DISPATCH_NO_CALLBACK; 00153 } 00154 00155 OggDataBuffer::eFeedResult OggDataBuffer::feed(const unsigned char* inData, unsigned long inNumBytes) { 00156 if (inNumBytes != 0) { 00157 if (inData != NULL) { 00158 //Buffer is not null and there is at least 1 byte of data. 00159 00160 //debugLog<<"Fed "<<inNumBytes<<" bytes..."<<endl; 00161 unsigned long locNumWritten = mBuffer->write(inData, inNumBytes); 00162 00163 if (locNumWritten < inNumBytes) { 00164 //TODO::: What does happen in this case. 00165 00166 //Handle this case... you lose data. 00167 //Buffer is full 00168 00169 //debugLog<<"Feed : Could count feed in " <<inNumBytes<<" bytes"<<endl 00170 // <<"Feed : ** "<<mBuffer->numBytesAvail()<<" avail, "<<mBuffer->spaceLeft()<<" space left."<<endl; 00171 00172 locNumWritten = locNumWritten; 00173 } 00174 return (eFeedResult)processBuffer(); 00175 } else { 00176 //Numbytes not equal to zero but inData pointer is NULL 00177 00178 //debugLog<<"Feed : Fed NULL Pointer"<<endl; 00179 return FEED_NULL_POINTER; 00180 } 00181 } else { 00182 //numbytes was zero... we do nothing and it's not an error. 00183 00184 //debugLog<<"Feed : Fed *zero* bytes... Not an error, do nothing, return ok."<<endl; 00185 return FEED_OK; 00186 } 00187 00188 00189 } 00190 OggDataBuffer::eProcessResult OggDataBuffer::processBaseHeader() 00191 { 00192 //debugLog<<"Processing base header..."<<endl; 00193 00194 //Delete the previous page 00195 delete pendingPage; 00196 00197 //Make a fresh ogg page 00198 pendingPage = new OggPage; //Either deleted in destructor, or given away by virtue of dispatch method. 00199 00200 //Make a local buffer for the header 00201 unsigned char* locBuff = new unsigned char[OggPageHeader::OGG_BASE_HEADER_SIZE]; //deleted before this function returns 00202 00203 //debugLog<<"ProcessBaseHeader : Reading from stream..."<<endl; 00204 00205 //STREAM ACCESS::: Read 00206 unsigned long locNumRead = mBuffer->read(locBuff, OggPageHeader::OGG_BASE_HEADER_SIZE); 00207 00208 if (locNumRead < OggPageHeader::OGG_BASE_HEADER_SIZE) { 00209 //TODO::: Handle this case... we read less than we expected. 00210 //The buffer handles it for us, it won't let us read less, and will return 0 00211 // This is fine for valid files, but still needs to be reviewed. 00212 00213 //debugLog<<"ProcessBaseHeader : ###### Read was short."<<endl; 00214 //debugLog<<"ProcessBaseHeader : ** "<<mBuffer->numBytesAvail()<<" avail, "<<mBuffer->spaceLeft()<<" space left."<<endl; 00215 locNumRead = locNumRead; 00216 } 00217 00218 bool locRetVal = pendingPage->header()->setBaseHeader((unsigned char*)locBuff); //Views pointer only. 00219 if (locRetVal == false) { 00220 delete[] locBuff; 00221 return PROCESS_FAILED_TO_SET_HEADER; 00222 } 00223 00224 //Set the number of bytes we want for next time 00225 mNumBytesNeeded = pendingPage->header()->NumPageSegments(); 00226 00227 //debugLog<<"Setting state to AWAITING_SEG_TABLE"<<endl; 00228 //Change the state. 00229 mState = AWAITING_SEG_TABLE; 00230 00231 delete[] locBuff; 00232 //debugLog<<"Bytes needed for seg table = "<<mNumBytesNeeded<<endl; 00233 return PROCESS_OK; 00234 } 00235 OggDataBuffer::eProcessResult OggDataBuffer::processSegTable() 00236 { 00238 // Gets the number segments from from the page header, reads in that much data, 00239 // 00240 // 00241 // 00242 //Assumes a valid pending page, with numPagesegments set in the header already. 00243 //creates a chunk of memory size numpagesegments and stores it,. 00244 00245 //debugLog<<"Processing Segment Table..."<<endl; 00246 00247 //TODAY::: What happens when numpage segments is zero. 00248 00249 //Save a local copy of the number of page segments - Get this from the already set header. 00250 unsigned char locNumSegs = pendingPage->header()->NumPageSegments(); 00251 00252 //debugLog<<"Num segments = "<<(int)locNumSegs<<endl; 00253 00254 //Make a local buffer the size of the segment table. 0 - 255 00255 unsigned char* locBuff = new unsigned char[locNumSegs]; //Given to setSegmentTable. Not deleted here. 00256 00258 00259 //Read the segment table from the buffer to locBuff 00260 unsigned long locNumRead = mBuffer->read(locBuff, (unsigned long)locNumSegs); 00261 00262 if (locNumRead < locNumSegs) { 00263 //TODO::: Handle this case 00264 00265 //debugLog<<"ProcessSegTable : ##### Short read"<<endl; 00266 //debugLog<<"ProcessSegTable : ** "<<mBuffer->numBytesAvail()<<" avail, "<<mBuffer->spaceLeft()<<" space left."<<endl; 00267 00268 } 00269 00270 00271 //Make a new segment table from the bufferd data. 00272 pendingPage->header()->setSegmentTable(locBuff); //This function accepts responsibility for the pointer. 00273 locBuff = NULL; 00274 00275 //Set the number of bytes we want for next time - which is the size of the page data. 00276 mNumBytesNeeded = pendingPage->header()->calculateDataSize(); 00277 00278 //debugLog<<"Num bytes needed for data = "<< mNumBytesNeeded<<endl; 00279 //debugLog<<"Transition to AWAITING_DATA"<<endl; 00280 00281 mState = AWAITING_DATA; 00282 return PROCESS_OK; 00283 00284 } 00285 00286 OggDataBuffer::eProcessResult OggDataBuffer::processDataSegment() 00287 { 00288 //unsigned long locPageDataSize = pendingPage->header()->dataSize(); //unused 00289 00290 //debugLog<<"ProcessDataSegment : Page data size = "<<locPageDataSize<<endl; 00291 unsigned char* locBuff = NULL; 00292 //unsigned long locPacketOffset = 0; 00293 00294 //TODO::: Should this be const ? 00295 //THis is a raw pointer into the segment table, don't delete it. 00296 unsigned char* locSegTable = pendingPage->header()->SegmentTable(); //View only don't delete. 00297 unsigned int locNumSegs = pendingPage->header()->NumPageSegments(); 00298 00299 //debugLog<<"ProcessDataSegment : Num segs = "<<locNumSegs<<endl; 00300 00301 00302 unsigned long locCurrPackSize = 0; 00303 bool locIsFirstPacket = true; 00304 LOOG_INT64 locPrevGranPos = 0; 00305 00306 for (unsigned long i = 0; i < locNumSegs; i++) { 00307 //Packet sums the lacing values of the segment table. 00308 locCurrPackSize += locSegTable[i]; 00309 00310 //If its the last segment in the page or if the lacing value is not 255(ie packet boundary. 00311 00312 /* TRUTH TABLE: 00313 last lacing value lacing value is *not* 255 00314 ================= ========================= 00315 true true } If its the last one or a packet boundary(255 lacing value) we add it. 00316 true false } 00317 false true } 00318 false false If it is a 255 (packet continues) and it's not the last one do nothibng 00319 it is the last lacing value on the page 00320 00321 00322 Lacing values for a Packet never end with 255... if multiple of 255 have a next 0 lacing value. 00323 */ 00324 00325 if ( (locSegTable[i] != 255) || (locNumSegs - 1 == i) ) { 00326 //If its the last lacing value or the the lacing value is not 255 (ie packet boundry) 00327 00328 //This pointer is given to the packet... it deletes it. 00329 locBuff = new unsigned char[locCurrPackSize]; //Given away to constructor of StampedOggPacket. 00330 00331 //STREAM ACCESS::: 00332 //Read data from the stream into the local buffer. 00333 00334 unsigned long locNumRead = mBuffer->read(locBuff, locCurrPackSize); 00335 00336 if (locNumRead < locCurrPackSize) { 00337 //TODO::: Handle this case. 00338 00339 //debugLog<<"ProcessDataSegment : ###### Short read"<<endl; 00340 //debugLog<<"ProcessDataSegment : ** "<<mBuffer->numBytesAvail()<<" avail, "<<mBuffer->spaceLeft()<<" space left."<<endl; 00341 locNumRead = locNumRead; 00342 } 00343 00344 //debugLog<<"Adding packet - size = "<<locCurrPackSize<<endl; 00345 00346 //A packet ends when a lacing value is not 255. So the check for != 255 means the isComplete property of the packet is not set unless the 00347 // lacing value is not equal to 255. 00348 //ERROR CHECK::: 00349 bool locIsContinuation = false; 00350 00351 if (locIsFirstPacket) { 00352 locIsFirstPacket = false; 00353 00354 //Remember what the granule pos was and get it from the new page. 00355 locPrevGranPos = mPrevGranPos; 00356 mPrevGranPos = pendingPage->header()->GranulePos(); 00357 00358 //First packet, check if the continuation flag is set. 00359 if ((pendingPage->header()->HeaderFlags() & OggPageHeader::CONTINUATION) == OggPageHeader::CONTINUATION) { 00360 //Continuation flag is set. 00361 locIsContinuation = true; 00362 } 00363 } 00364 //locBuff is given to the constructor of Stamped Ogg Packet... it deletes it. 00365 //The new StampedPacket is given to the page... it deletes it 00366 pendingPage->addPacket( new StampedOggPacket(locBuff, locCurrPackSize, (locSegTable[i] == 255), locIsContinuation, locPrevGranPos, pendingPage->header()->GranulePos(), StampedOggPacket::OGG_BOTH ) ); 00367 locBuff = NULL; //We've given this away. 00368 //Reset the packet size counter. 00369 locCurrPackSize = 0; 00370 } 00371 } 00372 00373 00374 //Update the state for how many bytes are now needed 00375 mNumBytesNeeded = OggPageHeader::OGG_BASE_HEADER_SIZE; 00376 00377 //debugLog<<"ProcessDataSegment : num bytes needed = "<<mNumBytesNeeded<<endl; 00378 00379 //Dispatch the finished pagbve 00380 eDispatchResult locRet = dispatch(pendingPage); //The dispatch function takes responsibility for this page. 00381 pendingPage = NULL; //We give away the pointer 00382 00383 if (locRet == DISPATCH_OK) { 00384 //debugLog<<"ProcessDataSegment : Transition to AWAITING_BASE_HEADER"<<endl; 00385 mState = AWAITING_BASE_HEADER; 00386 return PROCESS_OK; 00387 } else if (locRet == DISPATCH_FALSE) { 00388 mState = AWAITING_BASE_HEADER; 00389 return PROCESS_DISPATCH_FALSE; 00390 } else { 00391 //debugLog<<"ProcessDataSegment : Dispatch failed."<<endl; 00392 return PROCESS_DISPATCH_FAILED; 00393 } 00394 00395 } 00396 void OggDataBuffer::clearData() { 00397 mBuffer->reset(); 00398 mPrevGranPos = 0; 00399 //debugLog<<"ClearData : Transition back to AWAITING_BASE_HEADER"<<endl; 00400 00401 00402 mNumBytesNeeded = OggPageHeader::OGG_BASE_HEADER_SIZE; 00403 mState = AWAITING_BASE_HEADER; 00404 00406 } 00407 00408 OggDataBuffer::eProcessResult OggDataBuffer::processBuffer() { 00409 00410 eProcessResult locResult = PROCESS_OK; 00411 00412 while (numBytesAvail() >= mNumBytesNeeded) { 00414 switch (mState) { 00415 00416 //QUERY::: Should it be a bug when the if state inside the switch falls through,... potential for infinite loop. 00417 case AWAITING_BASE_HEADER: 00418 //debugLog<<"ProcessBuffer : State = AWAITING_BASE_HEADER"<<endl; 00419 00420 //If theres enough data to form the base header 00421 if (numBytesAvail() >= OggPageHeader::OGG_BASE_HEADER_SIZE) { 00422 //debugLog<<"ProcessBuffer : Enough to process..."<<endl; 00423 00424 locResult = processBaseHeader(); 00425 00426 if (locResult != PROCESS_OK) { 00427 mState = LOST_PAGE_SYNC; 00428 //Base header process failed 00429 return locResult; 00430 } 00431 } 00432 break; 00433 00434 case AWAITING_SEG_TABLE: 00435 //debugLog<<"ProcessBuffer : State = AWAITING_SEG_TABLE"<<endl; 00436 00437 //If there is enough data to get the segt table 00438 if (numBytesAvail() >= pendingPage->header()->NumPageSegments()) { 00439 //debugLog<<"ProcessBuffer : Enough to process..."<<endl; 00440 00441 locResult = processSegTable(); 00442 00443 if (locResult != PROCESS_OK) { 00444 mState = LOST_PAGE_SYNC; 00445 //segment table process failed 00446 return locResult; 00447 } 00448 } 00449 break; 00450 00451 case AWAITING_DATA: 00452 //debugLog<<"ProcessBuffer : State = AWAITING_DATA"<<endl; 00453 //If all the data segment is available 00454 if (numBytesAvail() >= pendingPage->header()->dataSize()) { 00455 //debugLog<<"ProcessBuffer : Enough to process..."<<endl; 00456 00457 //FIX::: Need error check. 00458 locResult = processDataSegment(); 00459 00460 if (locResult == PROCESS_DISPATCH_FAILED) { 00461 mState = LOST_PAGE_SYNC; 00462 //segment table process failed 00463 return locResult; 00464 } 00465 00466 } 00467 break; 00468 case LOST_PAGE_SYNC: 00469 //TODO::: Insert resync code here. 00470 00471 //debugLog<<"ProcessBuffer : State = LOST_PAGE_SYNC"<<endl; 00472 return PROCESS_LOST_SYNC; 00473 default: 00474 //TODO::: What are we supposed to do with this. Anything need cleaning up ? 00475 00476 //debugLog<<"ProcessBuffer : Ogg Buffer Error"<<endl; 00477 return PROCESS_UNKNOWN_INTERNAL_ERROR; 00478 break; 00479 } 00480 } 00481 00482 //There wasn't enough data to progress if we are here. 00483 return locResult; 00484 00485 } 00486 00487 //Debug Only 00488 void OggDataBuffer::debugWrite(string inString) { 00489 //debugLog<<inString<<endl; 00490 }
1.3.9