OggPacketiser.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 #include "stdafx.h"
00032 #include <libOOOgg/OggPacketiser.h>
00033 
00034 OggPacketiser::OggPacketiser(void) 
00035         :       mPacketSink(NULL)
00036         ,       mPendingPacket(NULL)
00037         ,       mPacketiserState(PKRSTATE_OK)
00038         ,       mLooseMode(true)                                                //FIX::: This affects the validator.
00039         ,       mNumIgnorePackets(0)
00040         //,     mPrevGranPos(0)
00041         //,     mCurrentGranPos(0)
00042 {
00043         //debugLog.open("g:\\logs\\packetise.log", ios_base::out);
00044 
00045 }
00046 OggPacketiser::OggPacketiser(IStampedOggPacketSink* inPacketSink)
00047         :       mPacketSink(inPacketSink)
00048         ,       mPendingPacket(NULL)
00049         ,       mPacketiserState(PKRSTATE_OK)
00050         ,       mLooseMode(true)                                                //FIX::: This affects the validator.
00051         ,       mNumIgnorePackets(0)
00052         //,     mPrevGranPos(0)
00053         //,     mCurrentGranPos(0)
00054 {
00055         //debugLog.open("g:\\logs\\packetise.log", ios_base::out);
00056 }
00057 
00058 OggPacketiser::~OggPacketiser(void)
00059 {
00060         //Don't delete the packet sink
00061         //debugLog.close();
00062 }
00063 
00064 IStampedOggPacketSink* OggPacketiser::packetSink() {
00065         return mPacketSink;
00066 }
00067 void OggPacketiser::setPacketSink(IStampedOggPacketSink* inPacketSink) {
00068         mPacketSink = inPacketSink;
00069 }
00070 bool OggPacketiser::reset() {
00071         //debugLog<<"Reset : "<<endl;
00072         delete mPendingPacket;
00073         mPendingPacket = NULL;
00074         mNumIgnorePackets = 0;
00075         mPacketiserState = PKRSTATE_OK;
00076         //mPrevGranPos = 0;
00077         //mCurrentGranPos = 0;
00078         return true;
00079 }
00080 bool OggPacketiser::acceptOggPage(OggPage* inOggPage) {                         //AOP::: Needs closer look
00081         //All callers to acceptOggPage give away their pointer
00082         // to this function. All functions implementing this interface
00083         // are responsible for deleting this page. All callers
00084         // should NULL their pointer immediately after calling
00085         // to avoid reusing them.
00086         // 
00087 
00088         //debugLog<<"acceptOggPage : Gran = "<<inOggPage->header()->GranulePos()<<"Num packs = "<<inOggPage->numPackets()<<endl;
00089 
00090         //If the page isn't a -1 page and it's got a different granpos save it.
00091         //if ( (inOggPage->header()->GranulePos() != -1) && (inOggPage->header()->GranulePos() != mCurrentGranPos)) {
00092         //      mPrevGranPos = mCurrentGranPos;
00093 
00094         //      //If the previous is higher than the
00095         //      if (mPrevGranPos > mCurrentGranPos) {
00096         //              mPrevGranPos = -1;
00097         //      }
00098         //      mCurrentGranPos = inOggPage->header()->GranulePos();
00099         //}
00100 
00101         //If the page header says its a continuation page...
00102         if ((inOggPage->header()->HeaderFlags() & 1) == 1) {
00103                 //debugLog<<"acceptOggPage : Page says cont..."<<endl;
00104                 
00106                 if (inOggPage->numPackets() > 0) {
00107                         //debugLog<<"acceptOggPage : ...and there is at least 1 packet..."<<endl;
00108                 
00109                         //... and we were expecting a continuation...
00110                         if (mPacketiserState == PKRSTATE_AWAITING_CONTINUATION) {
00111                                 //debugLog<<"acceptOggPage : ... and we were waiting for a cont..."<<endl;
00112 
00113                                 //... and the first packet is marked as a continuation...
00114                                 if (inOggPage->getStampedPacket(0)->isContinuation()) {
00115                                         //debugLog<<"acceptOggPage : ... and the first packet is a cont..."<<endl;
00116 
00117                                         //... merge this packet into our pending page.
00118                                         //ASSERT when mPacketiserState = PKRSTATE_AWAITING_CONTINUATION, mPending page != NULL
00119                                         mPendingPacket->merge(inOggPage->getStampedPacket(0));
00120                                         
00121                                         //If even after merging this packet is still truncated...
00122                                         if (mPendingPacket->isTruncated()) {
00123                                                 //debugLog<<"acceptOggPage : ... but the pending packet is still truncated..."<<endl;
00124                                                 //Packet still not full. special case full page.
00125                                                 //===
00126                                                 // The only way the the pending packet can be truncated is if
00127                                                 //  the first packet in the page is truncated, and the first
00128                                                 //  packet in a page can only be truncated if it's also the 
00129                                                 //  only packet on the page.
00130                                                 //Considering it is incomplete ending a page the granule pos
00131                                                 // will be -1.
00132                                                 //This is a special type of page :
00133                                                 // 1 incomlpete packet on the page
00134                                                 // Continuation flag set
00135                                                 // No complete packets end on this page
00136                                                 // Granule pos is -1
00137 
00138                                                 //debugLog<<"acceptOggPage : Go to cont state."<<endl;
00139                                                 //We are still waiting for another continuation...
00140                                                 mPacketiserState = PKRSTATE_AWAITING_CONTINUATION;              //This should be redundant, we should already be in this state.
00141                                                 //First packet on page is now merged into pending packet.
00142                                         } else {
00143                                                 //debugLog<<"acceptOggPage : ... now we can deliver it..."<<endl;
00144                                                 //... the pending packet is now complete.
00145                                                 
00146                                                 //TODO::: Static alternative here ?
00147                                                 
00148                                                 //Deliver the packet to the packet sink...
00149                                                 if (dispatchStampedOggPacket(mPendingPacket) == false) {
00150                                                         //debugLog<<"acceptOggPage : DELIVERY FAILED !"<<endl;
00151                                                         mPacketiserState = PKRSTATE_OK;
00152                                                         mPendingPacket = NULL;
00153                                                         delete inOggPage;
00154                                                         return false;
00155                                                 }
00156                                                 //debugLog<<"acceptOggPage : ... delivery sucessful..."<<endl;
00157                                                 //debugLog<<"acceptOggPage : Back to OK State..."<<endl;
00158                                                 //Go back to OK state
00159                                                 mPacketiserState = PKRSTATE_OK;
00160                                                 mPendingPacket = NULL;
00161                                                 //First packet on page is merged and delivered.
00162                                         }
00163                                         //debugLog<<"acceptOggPage : Send all the other packets besides first and last..."<<endl;
00164                                         //Send every packet except the first and last to the packet sink.
00165                                         processPage(inOggPage, false, false);
00166                                 } else {
00167                                         //debugLog<<"acceptOggPage : INTERNAL ERROR - Header says cont but packet doesn't."<<endl;
00168                                         //Header flag says continuation but first packet is not continued.
00169                                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00170                                         
00171                                         delete inOggPage;
00172                                         throw 0;
00173                                 }
00174                         } else {
00175                                 //debugLog<<"acceptOggPage : UNEXPECTED CONT !"<<endl;
00176                                 if (mLooseMode == true) {
00177                                         //debugLog<<"acceptOggPage : ... but we are ignoring it !"<<endl;
00178                                         //Just ignore when we get continuation pages, just drop the broken bit of packet.
00179 
00180                                         mPendingPacket = NULL;   //MEMCHECK::: Did i just leak memory ?
00181                                         mPacketiserState = PKRSTATE_OK;
00182 
00183                                         //TODO::: Should really return false here if this returns false.
00184                                         if( processPage(inOggPage, false, false) == false) {
00185                                                 //TODO::: State change ???
00186                                                 delete inOggPage;
00187                                                 return false;
00188                                         }
00189                                 } else {
00190                                         //debugLog<<"acceptOggPage : FAILURE !!!!"<<endl;
00191                                         //Unexpected continuation
00192                                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00193                                         throw 0;
00194                                 }
00195                         }
00196                 } else {
00197                         //debugLog<<"acceptOggPage : UNKNOWN CASE"<<endl;
00198                         //Is this something ?
00199                         //UNKNOWN CASE::: Header continuation flag set, but no packets on page.
00200                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00201                         delete inOggPage;
00202                         throw 0;
00203                 }
00204         } else {
00205                 //debugLog<<"acceptOggPage : We have a normal page... dumping all but the last..."<<endl;
00206                 //Normal page, no continuations... just dump the packets, except the last one
00207                 if (inOggPage->numPackets() == 1) {
00208 
00209                         //I think the bug is here... by sending a trunc packet and not updating state.
00210 
00211                         //debugLog<<"acceptOggPage : Only one packet on this normal page..."<<endl;
00212 
00213                         if (inOggPage->getPacket(0)->isTruncated()) {
00214                                 //debugLog<<"acceptOggPage : ...and it's truncated... so we save it."<<endl;
00215                                 //ASSERT : mPending packet is NULL, because this is not a continuation page.
00216                                 mPendingPacket = (StampedOggPacket*)inOggPage->getStampedPacket(0)->clone();
00217                                 //debugLog<<"acceptOggPage : Moving to CONT state."<<endl;
00218                                 mPacketiserState = PKRSTATE_AWAITING_CONTINUATION;
00219 
00220                         } else {
00221                                 //debugLog<<"acceptOggPage : Only one packet on this normal page..."<<endl;
00222                                 if (processPage(inOggPage, true, true) == false ) {                     //If there was only one pack process it.
00223                                         //debugLog<<"acceptOggPage : FAIL STATE DELIVERY"<<endl;
00224                                         //TODO::: State change
00225                                         delete inOggPage;
00226                                         return false;
00227                                 }
00228 
00229                                 //We should never go into the if below now as the packet is taken care of.
00230                         }
00231                 } else {
00232                         //debugLog<<"acceptOggPage : More than one packet so dumping all but last..."<<endl;
00233                         if (processPage(inOggPage, true, false) == false ) {                    //If there was only one packet, no packets would be written
00234                                 //debugLog<<"acceptOggPage : FAIL STATE DELIVERY"<<endl;
00235                                 //TODO::: State change
00236                                 delete inOggPage;
00237                                 return false;                   
00238                         }
00239                 }
00240                 
00241                 //The first packet is delivered.
00242         }
00243 
00244         //debugLog<<"acceptOggPage : First pack should be delivered..."<<endl;
00245         //ASSERT: By this point something has been done with the first packet.
00246 
00247         // It was either merged with pending page and possibly delivered
00248         // or it was delivered by process page.
00249         //Code following assumes the first packet is dealt with already.
00250         
00251         //Now we deal with the last packet...
00252         //ASSERT : The last packet has only been sent if there was 1 or less packets.
00253 
00254         //If there is at least two packet on the page... ie at least one more packet we haven't processed.
00255         if (inOggPage->numPackets() > 1) {
00256                 //debugLog<<"acceptOggPage : There is at least one packet on the page we haven't processed"<<endl;
00257                 //... and we are in the OK state
00258                 if (mPacketiserState == PKRSTATE_OK) {
00259                         //debugLog<<"acceptOggPage : ... and we are in the OK state..."<<endl;
00260                         //If the last packet is truncated.
00261                         if (inOggPage->getPacket(inOggPage->numPackets() - 1)->isTruncated()) {
00262                                 //debugLog<<"acceptOggPage : ... but the last packet is trunced... so we save it and wait for cont..."<<endl;
00263                                 //The last packet is truncated. Save it and await continuation.
00264                                 
00265                                 //debugLog<<"acceptOggPage : Moving to CONT state..."<<endl;
00266                                 mPacketiserState = PKRSTATE_AWAITING_CONTINUATION;
00267                         
00268                                 //ASSERT when mPacketiserState = OK, mPendingPacket = NULL
00269                                 mPendingPacket = (StampedOggPacket*)(inOggPage->getStampedPacket(inOggPage->numPackets() - 1)->clone());
00270                                 //This packet is not delivered, it waits for a continuation.
00271                         } else {
00272                                 //We are in the OK state, with no pending packets, and the last packet is not truncated.
00273                                 //debugLog<<"acceptOggPage : The last page is not trunc so we send it..."<<endl;
00274                                 //Deliver to the packet sink.
00275                                 if ( dispatchStampedOggPacket( (StampedOggPacket*)(inOggPage->getStampedPacket(inOggPage->numPackets() - 1)->clone()) ) == false ) {
00276                                         //debugLog<<"acceptOggPage : Delivery failed..."<<endl;
00277                                         //TODO::: State change ?
00278                                         delete inOggPage;
00279                                         return false;
00280                                 }
00281                                 //The last packet is complete. So send it.
00282                         }
00283                 } else if (mPacketiserState == PKRSTATE_AWAITING_CONTINUATION) {
00284                         //FIX::: This case should never occur.
00285                         //debugLog<<"acceptOggPage : NEVER BE HERE 1"<<endl;
00286                         
00287                         //Packetiser state is not ok... what to do abo8ut it.
00288                         
00289                         //See special page case above.
00290                         //This can only happen when we went through the special case above, and kept
00291                         // the state in  the continuation state. But by definition it is impossible
00292                         // for a subsequent packet on this page to be a continuation packet
00293                         // as continuation packets can only be the first packet on the page.
00294                         //This is more likely to be due to inconsistency of state code than invalidaity
00295                         // of file.
00296                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00297                         delete inOggPage;
00298                         throw 0;
00299                 } else {
00300                         //debugLog<<"acceptOggPage : NEVER BE HERE 2"<<endl;
00301                         //Shouldn't be here
00302                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00303                         delete inOggPage;
00304                         throw 0;
00305                 }
00306         } else {
00307                 //debugLog<<"acceptOggPage : 1 packet on page only, and we've taken care of it."<<endl;
00308                 //Zero packets on page.
00309         }
00310         //debugLog<<"acceptOggPage : All ok... returning..."<<endl<<endl;
00311         delete inOggPage;
00312         return true;
00313 }
00314 
00315 bool OggPacketiser::processPage(OggPage* inOggPage, bool inIncludeFirst, bool inIncludeLast) {
00316         //Returns false only if one of the acceptStampedOggPacket calls return false... means we should stop sending stuff and return.
00317         bool locIsOK = true;
00318         //debugLog<<"processPage : "<<endl;
00319         //Adjusts the loop parameters so that only packets excluding those specified are written.
00320         for (   int i = ((inIncludeFirst) ? 0 : 1); 
00321                         i < ((int)inOggPage->numPackets()) - ((inIncludeLast) ? 0 : 1);
00322                         i++) 
00323         {
00324                                 //debugLog<<"processPage : Packet "<< i <<endl;         
00325                                 locIsOK = (locIsOK && dispatchStampedOggPacket((StampedOggPacket*)inOggPage->getStampedPacket(i)->clone()));    //Gives away new packet.
00326                                 if (!locIsOK) {
00327                                         //debugLog<<"processPage : FAIL STATE"<<endl;
00328                                         //TODO::: State change ???
00329                                         return false;
00330                                 }
00331         }
00332         //debugLog<<"processPage : returning..."<<endl;
00333         return true;
00334 
00335 }
00336 
00337 bool OggPacketiser::dispatchStampedOggPacket(StampedOggPacket* inPacket) {      //Accepts packet... and gives it away or deletes it.
00338         if (mNumIgnorePackets > 0) {
00339                 //Ignore this packet.
00340                 mNumIgnorePackets--;
00341 
00342                 //MEMCHECK::: Should probably delete this packet here.]
00343                 delete inPacket;
00344                 return true;
00345         } else {
00346                 //Modify the header packet to include the gran pos of previous page.
00347                 //if (mPrevGranPos != -1) {
00348                 //      inPacket->setTimeStamp(mPrevGranPos, mCurrentGranPos, StampedOggPacket::OGG_BOTH);
00349                 //}
00350                 //Dispatch it.
00351                 return mPacketSink->acceptStampedOggPacket(inPacket);
00352         }
00353 }
00354 
00355 void OggPacketiser::setNumIgnorePackets(unsigned long inNumIgnorePackets) {
00356         mNumIgnorePackets = inNumIgnorePackets;
00357 }
00358 unsigned long OggPacketiser::numIgnorePackets() {
00359         return mNumIgnorePackets;
00360 }

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