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 }
1.3.9