AnxStreamMapper.cpp

Go to the documentation of this file.
00001 //===========================================================================
00002 //Copyright (C) 2003, 2004 Zentaro Kavanagh
00003 //
00004 //Copyright (C) 2003, 2004 Commonwealth Scientific and Industrial Research
00005 //   Organisation (CSIRO) Australia
00006 //
00007 //Redistribution and use in source and binary forms, with or without
00008 //modification, are permitted provided that the following conditions
00009 //are met:
00010 //
00011 //- Redistributions of source code must retain the above copyright
00012 //  notice, this list of conditions and the following disclaimer.
00013 //
00014 //- Redistributions in binary form must reproduce the above copyright
00015 //  notice, this list of conditions and the following disclaimer in the
00016 //  documentation and/or other materials provided with the distribution.
00017 //
00018 //- Neither the name of Zentaro Kavanagh nor the names of contributors 
00019 //  may be used to endorse or promote products derived from this software 
00020 //  without specific prior written permission.
00021 //
00022 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 //``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00025 //PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
00026 //CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027 //EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00028 //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00029 //PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00030 //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00031 //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 //===========================================================================
00034 
00035 #include "stdafx.h"
00036 #include "anxstreammapper.h"
00037 
00038 AnxStreamMapper::AnxStreamMapper(OggDemuxSourceFilter* inOwningFilter)
00039         :       OggStreamMapper(inOwningFilter)
00040         ,       mAnnodexSerial(0)
00041         ,       mSeenAnnodexBOS(false)
00042         ,       mReadyForCodecs(false)
00043         ,       mSeenCMML(false)
00044         ,       mDemuxState(eAnxDemuxState::SEEN_NOTHING)
00045         ,       mAnxVersion(0)
00046         ,       mAnnodexHeader(NULL)
00047 {
00048 #ifdef OGGCODECS_LOGGING
00049         debugLog.open("G:\\logs\\anxmapper.log", ios_base::out);
00050 #endif
00051 }
00052 
00053 AnxStreamMapper::~AnxStreamMapper(void)
00054 {
00055         debugLog.close();
00056 }
00057 
00058 bool AnxStreamMapper::isReady() {
00059         bool retVal = true;
00060         bool locWasAny = false;
00061         //Use 1 instead of 0... cmml is always ready and terminates the graph creation early.
00062         //We want to know when everything else is ready.
00063 
00064         //XXXXXXXXXXXXXX:::: Big dirty hack to deal with badly ordered header packets !!
00065         //=======================================================================
00066         //The side effect is... a file will hang if it has unknown streams.
00067         //=======================================================================
00068         if (mSeenStreams.size() == 0) {
00069                 retVal = true;
00070         } else {
00071                 retVal = false;
00072         }
00073         
00074         for (unsigned long i = 1; i < mStreamList.size(); i++) {
00075                 locWasAny = true;
00076                 retVal = retVal && mStreamList[i]->streamReady();
00077                 //debugLog<<"Stream "<<i<<" ";
00078                 if (retVal) {
00079                         //debugLog<<"READY !!!!!!"<<endl;
00080                 } else {
00081                         //debugLog<<"NOT READY !!!!"<<endl;
00082                 }
00083         }
00084         //=======================================================================
00085         if (locWasAny && retVal) {
00086                 debugLog<<"Streams READY"<<endl;
00087         } else {
00088                 debugLog<<"Streams NOT READY"<<endl;
00089         }
00090         return locWasAny && retVal;
00091 }
00092 
00093 bool AnxStreamMapper::isAnnodexEOS(OggPage* inOggPage) {
00094         if ((inOggPage->header()->StreamSerialNo() == mAnnodexSerial) &&
00095                                 (inOggPage->header()->isEOS())) {
00096                 return true;
00097         } else {
00098                 return false;
00099         }
00100 
00101 }
00102 bool AnxStreamMapper::isAnnodexBOS(OggPage* inOggPage) {
00103         if  ((inOggPage->numPackets() != 1) ||
00104                                 (inOggPage->getPacket(0)->packetSize() < 12) ||
00105                                 (strncmp((const char*)inOggPage->getPacket(0)->packetData(), "Annodex\0", 8) != 0) || 
00106                                 (!inOggPage->header()->isBOS())) {
00107                 return false;
00108         } else {
00109                 return true;
00110         }
00111 }
00112 
00113 bool AnxStreamMapper::isAnxDataPage(OggPage* inOggPage, bool inAnxDataAreBOS) {
00114 
00115         //isBOS                 inAnxDataAreBOS         isValid
00116         //
00117         //true                  true                            true
00118         //true                  false                           false
00119         //false                 true                            false
00120         //false                 false                           true
00121         if  ((inOggPage->numPackets() != 1) ||
00122                                 (inOggPage->getPacket(0)->packetSize() < 12) ||
00123                                 (strncmp((const char*)inOggPage->getPacket(0)->packetData(), "AnxData\0", 8) != 0) || 
00124                                 
00125                                 ( (inOggPage->header()->isBOS()) != inAnxDataAreBOS )) {
00126                 return false;
00127         } else {
00128                 return true;
00129         }
00130 }
00134 unsigned long AnxStreamMapper::getAnxVersion(OggPage* inOggPage) {
00135         if (isAnnodexBOS(inOggPage)) {
00136                         //8 and 10 are the offsets into the header for version number.
00137                         return ((iLE_Math::charArrToUShort(inOggPage->getPacket(0)->packetData() + 8)) << 16) + iLE_Math::charArrToUShort(inOggPage->getPacket(0)->packetData() + 10);
00138         } else {
00139                 return 0;
00140         }
00141 
00142         
00143 
00144 }
00145 
00146 bool AnxStreamMapper::handleAnxVersion_2_0(OggPage* inOggPage) {
00147         // LEAK::: Check memory deleting.
00148         const bool ANXDATA_ARE_BOS = true;
00149 
00150         bool locTemp = false;
00151 
00152         vector<unsigned long>::iterator it;
00153         int i = 0;
00154         debugLog<<"handleAnxVersion_2_0 : State = "<<mDemuxState<<endl;
00155         switch (mDemuxState) {
00156                 case SEEN_NOTHING:
00157                         //debugLog<<"SEEN_NOTHING"<<endl;
00158                         //We must find an annodex BOS page.
00159                         if (!isAnnodexBOS(inOggPage)) {
00160                                 mDemuxState = INVALID_STATE;
00161                                 delete inOggPage;
00162                                 return false;
00163                         } else {
00164                                 delete mAnnodexHeader;
00165                                 mAnnodexHeader = inOggPage->getPacket(0)->clone();
00166                                 mAnnodexSerial = inOggPage->header()->StreamSerialNo();
00167                                 mDemuxState = SEEN_ANNODEX_BOS;
00168                                 return true;
00169                         }
00170                         break;          //Can never be here.
00171 
00172                 case SEEN_ANNODEX_BOS:
00173                         //debugLog<<"SEEN_ANNODEX_BOS"<<endl;
00174                         //We should be getting Anxdata headers here.
00175                         if (!isAnxDataPage(inOggPage, ANXDATA_ARE_BOS)) {
00176                                 mDemuxState = INVALID_STATE;
00177                                 return false;
00178                         } else {
00179                                 //This should be the CMML AnxData header.
00180                                 mSeenStreams.clear();
00181                                 mAnxDataHeaders.clear();
00182                                 //mSeenStreams.push_back(inOggPage->header()->StreamSerialNo());
00183                                 mAnxDataHeaders.push_back(inOggPage->getPacket(0)->clone());
00184                                 mDemuxState = SEEN_AN_ANXDATA;
00185 
00186                                 
00187                                 //Add the CMML Stream
00188                                 OggStream* locStream = new CMMLStream(inOggPage, mOwningFilter, true);  //The page is only given for viewing
00189                                 if (locStream != NULL) {
00190                                         //debugLog<<"Adding CMML Stream"<<endl;
00191                                         mStreamList.push_back(locStream);
00192                                 }
00193 
00194                                 return true;
00195                         }
00196                                 
00197 
00198                         break;          //Can never be here.
00199 
00200                 case SEEN_AN_ANXDATA:
00201                         //debugLog<<"SEEN_AN_ANXDATA"<<endl;
00202                         if (isAnnodexEOS(inOggPage)) {
00203                                 //This is the end of the stream headers.
00204                                 mDemuxState = OGG_STATE;
00205                                 //debugLog<<"Found an Annodex EOS... transitioning."<<endl;
00206                                 return true;
00207                         } else if (isAnxDataPage(inOggPage, ANXDATA_ARE_BOS)) {
00208                                 //handle another anxdata page.
00209                                 //debugLog<<"Found another anxdata..."<<endl;
00210                                 mSeenStreams.push_back(inOggPage->header()->StreamSerialNo());
00211                                 mAnxDataHeaders.push_back(inOggPage->getPacket(0)->clone());
00212                                 mDemuxState = SEEN_AN_ANXDATA;
00213                                 return true;
00214                         } else {
00215                                 mDemuxState = INVALID_STATE;
00216                                 return false;
00217                                 //Invalid.
00218                         }
00219                         break;
00220                 case OGG_STATE:
00221                         //debugLog<<"OGG_STATE"<<endl;
00222                         //We've seen the annodex EOS... so we can proceed as if it's a normal ogg file.
00223                         // The CMML stream is already made.
00224 
00225                         for(i = 0, it = mSeenStreams.begin(); it != mSeenStreams.end(); i++, ++it) {
00226                                 debugLog<<"handleAnxVersion_2_0 : Checking seen stream "<<i<<endl;
00227                                 if (mSeenStreams[i] == inOggPage->header()->StreamSerialNo()) {
00228                                         //If the page is a BOS we need to start a new stream
00229                                         const bool ALLOW_OTHERS_TO_SEEK = true;
00230                                         debugLog<<"handleAnxVersion_2_0 : Creating stream "<<endl;
00231                                         OggStream* locStream = OggStreamFactory::CreateStream(inOggPage, mOwningFilter, ALLOW_OTHERS_TO_SEEK);
00232                                         //FIX::: Need to check for NULL
00233                                         if (locStream != NULL) {
00234                                                 debugLog<<"handleAnxVersion_2_0 : Stream Created "<<endl;
00235                                                 mStreamList.push_back(locStream);
00236                                         } else {
00237                                                 debugLog<<"handleAnxVersion_2_0 : ***** Stream NOT Created *****"<<endl;
00238                                         }
00239                                         mSeenStreams.erase(it);
00240                                         delete inOggPage;
00241                                         return true;
00242                                 }
00243                         }
00244 
00245                         //If we are here, the stream is not in the list.
00246                         //At the moment we assume it's because it's been seen, and removed... this is a bad assumption !
00247                         debugLog<<"handleAnxVersion_2_0 : Dispatching page "<<endl;
00248 
00249                         locTemp = dispatchPage(inOggPage);
00250                         if (locTemp) {
00251                                 debugLog<<"handleAnxVersion_2_0 : Sispatch oK "<<endl;
00252                         } else {
00253                                 debugLog<<"handleAnxVersion_2_0 : Dispatch faild "<<endl;
00254                         }
00255                         return locTemp;
00256                         break;
00257                 case INVALID_STATE:
00258                 default:
00259                         debugLog<<"handleAnxVersion_2_0 : INVALID STATE "<<endl;
00260                         return false;
00261                         break;
00262 
00263 
00264 
00265         }
00266 }
00267 
00268 bool AnxStreamMapper::handleAnxVersion_3_0(OggPage* inOggPage) {
00269         switch (mDemuxState) {
00270                 case SEEN_NOTHING:
00271                         //We must find an annodex BOS page.
00272                         break;
00273                 case SEEN_ANNODEX_BOS:
00274                         break;
00275                 case SEEN_AN_ANXDATA:
00276                         break;
00277                 case OGG_STATE:
00278                         break;
00279                 case INVALID_STATE:
00280                 default:
00281                         break;
00282 
00283 
00284 
00285         }
00286         return false;
00287 }
00288 
00289 bool AnxStreamMapper::acceptOggPage(OggPage* inOggPage)                 //Deletes or gives away page.
00290 {
00291 
00292         if (mDemuxState == SEEN_NOTHING) {
00293                 mAnxVersion = getAnxVersion(inOggPage);
00294                 //debugLog<<"Version is "<<mAnxVersion<<endl;
00295         }
00296         //debugLog<<"Accepting Page..."<<endl;
00297         switch (mAnxVersion) {
00298                 case ANX_VERSION_2_0:
00299                         //Potential memory leaks here !
00300                         
00301                         return handleAnxVersion_2_0(inOggPage);
00302                         break;
00303                 case ANX_VERSION_3_0:
00304                         return handleAnxVersion_3_0(inOggPage);
00305                 default:
00306                         mDemuxState = INVALID_STATE;
00307                         return false;
00308 
00309         }
00310 
00311 
00312 
00313         //debugLog<<endl<<"-------- accepting page ------"<<endl;
00314         //if (!mReadyForCodecs) {
00315         //      if (inOggPage->header()->isBOS()) {
00316         //              if (!mSeenAnnodexBOS) {
00317         //                      //This is an annodex BOS page
00318         //                      //Need to verify it's an annodex page too
00319         //                      mAnnodexSerial = inOggPage->header()->StreamSerialNo();
00320         //                      mSeenAnnodexBOS = true;
00321         //                      
00322         //                      //Need to save the data from the header here.
00323         //              } else {
00324         //                      //This is anxdata
00325         //                      
00326 
00327         //                      if ( (mSeenCMML == false) ) {
00328         //                              //This is a really nasty way to do it ! Fix this up properly later.
00329         //                              char* locStr = (char*)(inOggPage->getPacket(0)->packetData() + 28);
00330         //                              if (strstr(locStr, "text/x-cmml") != NULL) {
00331         //                                      mSeenCMML = true;
00332         //                                      OggStream* locStream = new CMMLStream(inOggPage, mOwningFilter, true);  //The page is only given for viewing
00333         //                                      if (locStream != NULL) {
00334         //                                              mStreamList.push_back(locStream);
00335         //                                      }
00336         //                              }
00337         //                      } else {
00338         //                      //Need to save header data here.
00339         //                              mSeenStreams.push_back(inOggPage->header()->StreamSerialNo());
00340         //                      }
00341         //              }
00342         //      }
00343 
00344 
00345         //      if (inOggPage->header()->isEOS()) {
00346         //              if (mSeenAnnodexBOS) {
00347         //                      //This is the annodex EOS page
00348         //                      mReadyForCodecs = true;
00349         //              } else {
00350         //                      //ERROR... got an EOS before we've seen the annodex BOS
00351         //                      delete inOggPage;
00352         //                      return false;
00353         //              }
00354         //      }
00355         //      delete inOggPage;
00356         //      return true;
00357         //} else {
00358         //      vector<unsigned long>::iterator it;
00359         //      int i;
00360         //      for(i = 0, it = mSeenStreams.begin(); it != mSeenStreams.end(); i++, ++it) {
00361         //      //for (int i = 0; i < mSeenStreams.size(); i++) {
00362         //              if (mSeenStreams[i] == inOggPage->header()->StreamSerialNo()) {
00363         //                      //If the page is a BOS we need to start a new stream
00364         //                      const bool ALLOW_OTHERS_TO_SEEK = true;
00365         //                      OggStream* locStream = OggStreamFactory::CreateStream(inOggPage, mOwningFilter, ALLOW_OTHERS_TO_SEEK);
00366         //                      //FIX::: Need to check for NULL
00367         //                      if (locStream != NULL) {
00368         //                              mStreamList.push_back(locStream);
00369         //                      }
00370         //                      mSeenStreams.erase(it);
00371         //                      delete inOggPage;
00372         //                      return true;
00373         //              }
00374         //      }
00375 
00376         //      //If we are here, the stream is not in the list.
00377         //      //At the moment we assume it's because it's been seen, and removed... this is a bad assumption !
00378 
00379         //      return dispatchPage(inOggPage);
00380         //}
00381 }
00382 
00383 bool AnxStreamMapper::toStartOfData() {
00384         debugLog<<"toStartOfData : S "<<endl;
00385         //Specialise for anx... adds one extra ignore packet to the flush to account for the anxdata pages only
00386         // if it's 2.0 version.
00387         //debugLog<<"ANX::: To start of data size = "<<mStreamList.size()<<endl;
00388         if (isReady()) {  //CHECK::: Should check for allow dsipatch ???
00389                 for (unsigned long i = 0; i < mStreamList.size(); i++) {
00390                         //Flush each stream, then ignore the codec headers.
00391                         if (mAnxVersion == ANX_VERSION_2_0) {
00392                                 //debugLog<<"Flushing stream "<<i<<" for "<<mStreamList[i]->numCodecHeaders() + 1<<endl;
00393                                 mStreamList[i]->flush((unsigned short)(mStreamList[i]->numCodecHeaders() + 1));  //+1 = AnxData Header...
00394                         } else {
00395                                 mStreamList[i]->flush((unsigned short)(mStreamList[i]->numCodecHeaders()));
00396                         }
00397                 }       
00398                 return true;
00399         } else {
00400                 //debugLog<<"Something bad happened !!!!&&&&"<<endl;
00401                 return false;
00402         }
00403 }

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