OggDataBuffer.cpp

Go to the documentation of this file.
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 }

Generated on Thu Feb 16 23:48:15 2006 for oggdsf by  doxygen 1.3.9