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 
00211                         //debugLog<<"ProcessBaseHeader : ###### Read was short."<<endl;
00212                         //debugLog<<"ProcessBaseHeader : ** "<<mBuffer->numBytesAvail()<<" avail, "<<mBuffer->spaceLeft()<<" space left."<<endl;
00213                         locNumRead = locNumRead;
00214                 }
00215 
00216                 bool locRetVal = pendingPage->header()->setBaseHeader((unsigned char*)locBuff);         //Views pointer only.
00217                 if (locRetVal == false) {
00218                         delete[] locBuff;
00219                         return PROCESS_FAILED_TO_SET_HEADER;
00220                 }
00221         
00222                 //Set the number of bytes we want for next time
00223                 mNumBytesNeeded = pendingPage->header()->NumPageSegments();
00224 
00225                 //debugLog<<"Setting state to AWAITING_SEG_TABLE"<<endl;
00226                 //Change the state.
00227                 mState = AWAITING_SEG_TABLE;
00228 
00229                 delete[] locBuff;
00230                 //debugLog<<"Bytes needed for seg table = "<<mNumBytesNeeded<<endl;     
00231                 return PROCESS_OK;
00232 }
00233 OggDataBuffer::eProcessResult OggDataBuffer::processSegTable() 
00234 {
00236         //      Gets the number segments from from the page header, reads in that much data,
00237         //       
00238         //      
00239         //
00240         //Assumes a valid pending page, with numPagesegments set in the header already.
00241         //creates a chunk of memory size numpagesegments and stores it,.
00242 
00243         //debugLog<<"Processing Segment Table..."<<endl;
00244 
00245         //TODAY::: What happens when numpage segments is zero.
00246 
00247         //Save a local copy of the number of page segments - Get this from the already set header.
00248         unsigned char locNumSegs = pendingPage->header()->NumPageSegments();
00249 
00250         //debugLog<<"Num segments = "<<(int)locNumSegs<<endl;
00251 
00252         //Make a local buffer the size of the segment table. 0 - 255
00253         unsigned char* locBuff = new unsigned char[locNumSegs];                         //Given to setSegmentTable. Not deleted here.
00254         
00256 
00257         //Read the segment table from the buffer to locBuff
00258         unsigned long locNumRead = mBuffer->read(locBuff, (unsigned long)locNumSegs);
00259         
00260         if (locNumRead < locNumSegs) {
00261                 //TODO::: Handle this case
00262 
00263                 //debugLog<<"ProcessSegTable : ##### Short read"<<endl;
00264                 //debugLog<<"ProcessSegTable : ** "<<mBuffer->numBytesAvail()<<" avail, "<<mBuffer->spaceLeft()<<" space left."<<endl;
00265                 
00266         }
00267 
00268 
00269         //Make a new segment table from the bufferd data.
00270         pendingPage->header()->setSegmentTable(locBuff);                        //This function accepts responsibility for the pointer.
00271         locBuff = NULL;
00272         
00273         //Set the number of bytes we want for next time - which is the size of the page data.
00274         mNumBytesNeeded = pendingPage->header()->calculateDataSize();
00275 
00276         //debugLog<<"Num bytes needed for data = "<< mNumBytesNeeded<<endl;
00277         //debugLog<<"Transition to AWAITING_DATA"<<endl;
00278         
00279         mState = AWAITING_DATA;
00280         return PROCESS_OK;
00281 
00282 }
00283 
00284 OggDataBuffer::eProcessResult OggDataBuffer::processDataSegment() 
00285 {
00286         //unsigned long locPageDataSize = pendingPage->header()->dataSize();  //unused
00287         
00288         //debugLog<<"ProcessDataSegment : Page data size = "<<locPageDataSize<<endl;
00289         unsigned char* locBuff = NULL;
00290         //unsigned long locPacketOffset = 0;
00291 
00292         //TODO::: Should this be const ?
00293         //THis is a raw pointer into the segment table, don't delete it.
00294         unsigned char* locSegTable = pendingPage->header()->SegmentTable();                     //View only don't delete.
00295         unsigned int locNumSegs = pendingPage->header()->NumPageSegments();
00296         
00297         //debugLog<<"ProcessDataSegment : Num segs = "<<locNumSegs<<endl;
00298 
00299 
00300         unsigned long locCurrPackSize = 0;
00301         bool locIsFirstPacket = true;
00302         LOOG_INT64 locPrevGranPos = 0;
00303 
00304         for (unsigned long i = 0; i < locNumSegs; i++) {
00305                 //Packet sums the lacing values of the segment table.
00306                 locCurrPackSize += locSegTable[i];
00307 
00308                 //If its the last segment  in the page or if the lacing value is not 255(ie packet boundary.
00309 
00310                 /* TRUTH TABLE:
00311                         last lacing value                                                       lacing value is *not* 255
00312                         =================                                                       =========================
00313                         true                                                                            true                                            }       If its the last one or a packet boundary(255 lacing value) we add it.
00314                         true                                                                            false                                           }
00315                         false                                                                           true                                            }
00316                         false                                                                           false                                           If it is a 255 (packet continues) and it's not the last one do nothibng
00317                         it is the last lacing value on the page
00318 
00319 
00320                         Lacing values for a Packet never end with 255... if multiple of 255 have a next 0 lacing value.
00321                 */
00322                 
00323                 if ( (locSegTable[i] != 255) || (locNumSegs - 1 == i) ) {
00324                         //If its the last lacing value or the the lacing value is not 255 (ie packet boundry)
00325                         
00326                         //This pointer is given to the packet... it deletes it.
00327                         locBuff = new unsigned char[locCurrPackSize];                           //Given away to constructor of StampedOggPacket.
00328 
00329                         //STREAM ACCESS:::
00330                         //Read data from the stream into the local buffer.
00331                         
00332                         unsigned long locNumRead = mBuffer->read(locBuff, locCurrPackSize);
00333                         
00334                         if (locNumRead < locCurrPackSize) {
00335                                 //TODO::: Handle this case.
00336 
00337                                 //debugLog<<"ProcessDataSegment : ###### Short read"<<endl;
00338                                 //debugLog<<"ProcessDataSegment : ** "<<mBuffer->numBytesAvail()<<" avail, "<<mBuffer->spaceLeft()<<" space left."<<endl;
00339                                 locNumRead = locNumRead;
00340                         }
00341 
00342                         //debugLog<<"Adding packet - size = "<<locCurrPackSize<<endl;
00343                         
00344                         //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
00345                         // lacing value is not equal to 255.
00346                         //ERROR CHECK:::
00347                         bool locIsContinuation = false;
00348                         
00349                         if (locIsFirstPacket) {
00350                                 locIsFirstPacket = false;
00351 
00352                                 //Remember what the granule pos was and get it from the new page.
00353                                 locPrevGranPos = mPrevGranPos;
00354                                 mPrevGranPos = pendingPage->header()->GranulePos();
00355                                 
00356                                 //First packet, check if the continuation flag is set.
00357                                 if ((pendingPage->header()->HeaderFlags() & OggPageHeader::CONTINUATION) == OggPageHeader::CONTINUATION) {
00358                                         //Continuation flag is set.
00359                                         locIsContinuation = true;
00360                                 }
00361                         }
00362                         //locBuff is given to the constructor of Stamped Ogg Packet... it deletes it.
00363                         //The new StampedPacket is given to the page... it deletes it
00364                         pendingPage->addPacket( new StampedOggPacket(locBuff, locCurrPackSize, (locSegTable[i] == 255), locIsContinuation, locPrevGranPos, pendingPage->header()->GranulePos(), StampedOggPacket::OGG_BOTH ) );
00365                         locBuff = NULL;                         //We've given this away.
00366                         //Reset the packet size counter.
00367                         locCurrPackSize = 0;
00368                 }
00369         }
00370 
00371         
00372         //Update the state for how many bytes are now needed
00373         mNumBytesNeeded = OggPageHeader::OGG_BASE_HEADER_SIZE;
00374         
00375         //debugLog<<"ProcessDataSegment : num bytes needed = "<<mNumBytesNeeded<<endl;
00376 
00377         //Dispatch the finished pagbve
00378         eDispatchResult locRet = dispatch(pendingPage);                 //The dispatch function takes responsibility for this page.
00379         pendingPage = NULL;   //We give away the pointer
00380         
00381         if (locRet == DISPATCH_OK) {
00382         //debugLog<<"ProcessDataSegment : Transition to AWAITING_BASE_HEADER"<<endl;
00383                 mState = AWAITING_BASE_HEADER;
00384                 return PROCESS_OK;
00385         } else if (locRet == DISPATCH_FALSE) {
00386                 mState = AWAITING_BASE_HEADER;
00387                 return PROCESS_DISPATCH_FALSE;  
00388         } else {
00389                 //debugLog<<"ProcessDataSegment : Dispatch failed."<<endl;
00390                 return PROCESS_DISPATCH_FAILED;
00391         }
00392                 
00393 }
00394 void OggDataBuffer::clearData() {
00395         mBuffer->reset();
00396         mPrevGranPos = 0;
00397         //debugLog<<"ClearData : Transition back to AWAITING_BASE_HEADER"<<endl;
00398         
00399         
00400         mNumBytesNeeded = OggPageHeader::OGG_BASE_HEADER_SIZE;
00401         mState = AWAITING_BASE_HEADER;
00402 
00404 }
00405 
00406 OggDataBuffer::eProcessResult OggDataBuffer::processBuffer() {
00407                 
00408         eProcessResult locResult = PROCESS_OK;
00409 
00410         while (numBytesAvail() >= mNumBytesNeeded) {
00412                 switch (mState) {
00413 
00414                         //QUERY:::      Should it be a bug when the if state inside the switch falls through,... potential for infinite loop.
00415                         case AWAITING_BASE_HEADER:
00416                                 //debugLog<<"ProcessBuffer : State = AWAITING_BASE_HEADER"<<endl;
00417                                 
00418                                 //If theres enough data to form the base header
00419                                 if (numBytesAvail() >= OggPageHeader::OGG_BASE_HEADER_SIZE) {
00420                                         //debugLog<<"ProcessBuffer : Enough to process..."<<endl;
00421                                         
00422                                         locResult = processBaseHeader();
00423                     
00424                                         if (locResult != PROCESS_OK) {
00425                                                 mState = LOST_PAGE_SYNC;
00426                                                 //Base header process failed
00427                                                 return locResult;
00428                                         }
00429                                 }
00430                                 break;
00431                         
00432                         case AWAITING_SEG_TABLE:
00433                                 //debugLog<<"ProcessBuffer : State = AWAITING_SEG_TABLE"<<endl;
00434                                 
00435                                 //If there is enough data to get the segt table
00436                                 if (numBytesAvail() >= pendingPage->header()->NumPageSegments()) {
00437                                         //debugLog<<"ProcessBuffer : Enough to process..."<<endl;
00438                                         
00439                                         locResult = processSegTable();
00440                
00441                                         if (locResult != PROCESS_OK) {
00442                                                 mState = LOST_PAGE_SYNC;
00443                                                 //segment table process failed
00444                                                 return locResult;
00445                                         }
00446                                 }
00447                                 break;
00448 
00449                         case AWAITING_DATA:
00450                                 //debugLog<<"ProcessBuffer : State = AWAITING_DATA"<<endl;
00451                                 //If all the data segment is available
00452                                 if (numBytesAvail() >= pendingPage->header()->dataSize()) {
00453                                         //debugLog<<"ProcessBuffer : Enough to process..."<<endl;
00454 
00455                                         //FIX::: Need error check.
00456                                         locResult = processDataSegment();
00457                                         
00458                                         if (locResult == PROCESS_DISPATCH_FAILED) {
00459                                                 mState = LOST_PAGE_SYNC;
00460                                                 //segment table process failed
00461                                                 return locResult;
00462                                         }
00463 
00464                                 }       
00465                                 break;
00466                         case LOST_PAGE_SYNC:
00467                                 //TODO::: Insert resync code here.
00468 
00469                                 //debugLog<<"ProcessBuffer : State = LOST_PAGE_SYNC"<<endl;
00470                                 return PROCESS_LOST_SYNC;
00471                         default:
00472                                 //TODO::: What are we supposed to do with this. Anything need cleaning up ?
00473                                 
00474                                 //debugLog<<"ProcessBuffer : Ogg Buffer Error"<<endl;
00475                                 return PROCESS_UNKNOWN_INTERNAL_ERROR;
00476                                 break;
00477                 }
00478         }
00479 
00480         //There wasn't enough data to progress if we are here.
00481         return locResult;
00482 
00483 }
00484 
00485 //Debug Only
00486 void OggDataBuffer::debugWrite(string inString) {
00487         //debugLog<<inString<<endl;
00488 }

Generated on Tue Feb 15 14:54:21 2005 for oggdsf by  doxygen 1.3.9