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                                                         delete inOggPage;
00152                                                         return false;
00153                                                 }
00154                                                 //debugLog<<"acceptOggPage : ... delivery sucessful..."<<endl;
00155                                                 //debugLog<<"acceptOggPage : Back to OK State..."<<endl;
00156                                                 //Go back to OK state
00157                                                 mPacketiserState = PKRSTATE_OK;
00158                                                 mPendingPacket = NULL;
00159                                                 //First packet on page is merged and delivered.
00160                                         }
00161                                         //debugLog<<"acceptOggPage : Send all the other packets besides first and last..."<<endl;
00162                                         //Send every packet except the first and last to the packet sink.
00163                                         processPage(inOggPage, false, false);
00164                                 } else {
00165                                         //debugLog<<"acceptOggPage : INTERNAL ERROR - Header says cont but packet doesn't."<<endl;
00166                                         //Header flag says continuation but first packet is not continued.
00167                                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00168                                         delete inOggPage;
00169                                         throw 0;
00170                                 }
00171                         } else {
00172                                 //debugLog<<"acceptOggPage : UNEXPECTED CONT !"<<endl;
00173                                 if (mLooseMode == true) {
00174                                         //debugLog<<"acceptOggPage : ... but we are ignoring it !"<<endl;
00175                                         //Just ignore when we get continuation pages, just drop the broken bit of packet.
00176 
00177                                         mPendingPacket = NULL;   //MEMCHECK::: Did i just leak memory ?
00178                                         mPacketiserState = PKRSTATE_OK;
00179 
00180                                         //TODO::: Should really return false here if this returns false.
00181                                         if( processPage(inOggPage, false, false) == false) {
00182                                                 //TODO::: State change ???
00183                                                 delete inOggPage;
00184                                                 return false;
00185                                         }
00186                                 } else {
00187                                         //debugLog<<"acceptOggPage : FAILURE !!!!"<<endl;
00188                                         //Unexpected continuation
00189                                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00190                                         throw 0;
00191                                 }
00192                         }
00193                 } else {
00194                         //debugLog<<"acceptOggPage : UNKNOWN CASE"<<endl;
00195                         //Is this something ?
00196                         //UNKNOWN CASE::: Header continuation flag set, but no packets on page.
00197                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00198                         delete inOggPage;
00199                         throw 0;
00200                 }
00201         } else {
00202                 //debugLog<<"acceptOggPage : We have a normal page... dumping all but the last..."<<endl;
00203                 //Normal page, no continuations... just dump the packets, except the last one
00204                 if (inOggPage->numPackets() == 1) {
00205 
00206                         //I think the bug is here... by sending a trunc packet and not updating state.
00207 
00208                         //debugLog<<"acceptOggPage : Only one packet on this normal page..."<<endl;
00209 
00210                         if (inOggPage->getPacket(0)->isTruncated()) {
00211                                 //debugLog<<"acceptOggPage : ...and it's truncated... so we save it."<<endl;
00212                                 //ASSERT : mPending packet is NULL, because this is not a continuation page.
00213                                 mPendingPacket = (StampedOggPacket*)inOggPage->getStampedPacket(0)->clone();
00214                                 //debugLog<<"acceptOggPage : Moving to CONT state."<<endl;
00215                                 mPacketiserState = PKRSTATE_AWAITING_CONTINUATION;
00216 
00217                         } else {
00218                                 //debugLog<<"acceptOggPage : Only one packet on this normal page..."<<endl;
00219                                 if (processPage(inOggPage, true, true) == false ) {                     //If there was only one pack process it.
00220                                         //debugLog<<"acceptOggPage : FAIL STATE DELIVERY"<<endl;
00221                                         //TODO::: State change
00222                                         delete inOggPage;
00223                                         return false;
00224                                 }
00225 
00226                                 //We should never go into the if below now as the packet is taken care of.
00227                         }
00228                 } else {
00229                         //debugLog<<"acceptOggPage : More than one packet so dumping all but last..."<<endl;
00230                         if (processPage(inOggPage, true, false) == false ) {                    //If there was only one packet, no packets would be written
00231                                 //debugLog<<"acceptOggPage : FAIL STATE DELIVERY"<<endl;
00232                                 //TODO::: State change
00233                                 delete inOggPage;
00234                                 return false;                   
00235                         }
00236                 }
00237                 
00238                 //The first packet is delivered.
00239         }
00240 
00241         //debugLog<<"acceptOggPage : First pack should be delivered..."<<endl;
00242         //ASSERT: By this point something has been done with the first packet.
00243 
00244         // It was either merged with pending page and possibly delivered
00245         // or it was delivered by process page.
00246         //Code following assumes the first packet is dealt with already.
00247         
00248         //Now we deal with the last packet...
00249         //ASSERT : The last packet has only been sent if there was 1 or less packets.
00250 
00251         //If there is at least two packet on the page... ie at least one more packet we haven't processed.
00252         if (inOggPage->numPackets() > 1) {
00253                 //debugLog<<"acceptOggPage : There is at least one packet on the page we haven't processed"<<endl;
00254                 //... and we are in the OK state
00255                 if (mPacketiserState == PKRSTATE_OK) {
00256                         //debugLog<<"acceptOggPage : ... and we are in the OK state..."<<endl;
00257                         //If the last packet is truncated.
00258                         if (inOggPage->getPacket(inOggPage->numPackets() - 1)->isTruncated()) {
00259                                 //debugLog<<"acceptOggPage : ... but the last packet is trunced... so we save it and wait for cont..."<<endl;
00260                                 //The last packet is truncated. Save it and await continuation.
00261                                 
00262                                 //debugLog<<"acceptOggPage : Moving to CONT state..."<<endl;
00263                                 mPacketiserState = PKRSTATE_AWAITING_CONTINUATION;
00264                         
00265                                 //ASSERT when mPacketiserState = OK, mPendingPacket = NULL
00266                                 mPendingPacket = (StampedOggPacket*)(inOggPage->getStampedPacket(inOggPage->numPackets() - 1)->clone());
00267                                 //This packet is not delivered, it waits for a continuation.
00268                         } else {
00269                                 //We are in the OK state, with no pending packets, and the last packet is not truncated.
00270                                 //debugLog<<"acceptOggPage : The last page is not trunc so we send it..."<<endl;
00271                                 //Deliver to the packet sink.
00272                                 if ( dispatchStampedOggPacket( (StampedOggPacket*)(inOggPage->getStampedPacket(inOggPage->numPackets() - 1)->clone()) ) == false ) {
00273                                         //debugLog<<"acceptOggPage : Delivery failed..."<<endl;
00274                                         //TODO::: State change ?
00275                                         delete inOggPage;
00276                                         return false;
00277                                 }
00278                                 //The last packet is complete. So send it.
00279                         }
00280                 } else if (mPacketiserState == PKRSTATE_AWAITING_CONTINUATION) {
00281                         //FIX::: This case should never occur.
00282                         //debugLog<<"acceptOggPage : NEVER BE HERE 1"<<endl;
00283                         
00284                         //Packetiser state is not ok... what to do abo8ut it.
00285                         
00286                         //See special page case above.
00287                         //This can only happen when we went through the special case above, and kept
00288                         // the state in  the continuation state. But by definition it is impossible
00289                         // for a subsequent packet on this page to be a continuation packet
00290                         // as continuation packets can only be the first packet on the page.
00291                         //This is more likely to be due to inconsistency of state code than invalidaity
00292                         // of file.
00293                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00294                         delete inOggPage;
00295                         throw 0;
00296                 } else {
00297                         //debugLog<<"acceptOggPage : NEVER BE HERE 2"<<endl;
00298                         //Shouldn't be here
00299                         mPacketiserState = PKRSTATE_INVALID_STREAM;
00300                         delete inOggPage;
00301                         throw 0;
00302                 }
00303         } else {
00304                 //debugLog<<"acceptOggPage : 1 packet on page only, and we've taken care of it."<<endl;
00305                 //Zero packets on page.
00306         }
00307         //debugLog<<"acceptOggPage : All ok... returning..."<<endl<<endl;
00308         delete inOggPage;
00309         return true;
00310 }
00311 
00312 bool OggPacketiser::processPage(OggPage* inOggPage, bool inIncludeFirst, bool inIncludeLast) {
00313         //Returns false only if one of the acceptStampedOggPacket calls return false... means we should stop sending stuff and return.
00314         bool locIsOK = true;
00315         //debugLog<<"processPage : "<<endl;
00316         //Adjusts the loop parameters so that only packets excluding those specified are written.
00317         for (   int i = ((inIncludeFirst) ? 0 : 1); 
00318                         i < ((int)inOggPage->numPackets()) - ((inIncludeLast) ? 0 : 1);
00319                         i++) 
00320         {
00321                                 //debugLog<<"processPage : Packet "<< i <<endl;         
00322                                 locIsOK = (locIsOK && dispatchStampedOggPacket((StampedOggPacket*)inOggPage->getStampedPacket(i)->clone()));    //Gives away new packet.
00323                                 if (!locIsOK) {
00324                                         //debugLog<<"processPage : FAIL STATE"<<endl;
00325                                         //TODO::: State change ???
00326                                         return false;
00327                                 }
00328         }
00329         //debugLog<<"processPage : returning..."<<endl;
00330         return true;
00331 
00332 }
00333 
00334 bool OggPacketiser::dispatchStampedOggPacket(StampedOggPacket* inPacket) {      //Accepts packet... and gives it away or deletes it.
00335         if (mNumIgnorePackets > 0) {
00336                 //Ignore this packet.
00337                 mNumIgnorePackets--;
00338 
00339                 //MEMCHECK::: Should probably delete this packet here.]
00340                 delete inPacket;
00341                 return true;
00342         } else {
00343                 //Modify the header packet to include the gran pos of previous page.
00344                 if (mPrevGranPos != -1) {
00345                         inPacket->setTimeStamp(mPrevGranPos, mCurrentGranPos, StampedOggPacket::OGG_BOTH);
00346                 }
00347                 //Dispatch it.
00348                 return mPacketSink->acceptStampedOggPacket(inPacket);
00349         }
00350 }
00351 
00352 void OggPacketiser::setNumIgnorePackets(unsigned long inNumIgnorePackets) {
00353         mNumIgnorePackets = inNumIgnorePackets;
00354 }
00355 unsigned long OggPacketiser::numIgnorePackets() {
00356         return mNumIgnorePackets;
00357 }

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