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 //#define OGGCODECS_LOGGING
00039 AnxStreamMapper::AnxStreamMapper(OggDemuxSourceFilter* inOwningFilter)
00040         :       OggStreamMapper(inOwningFilter)
00041         ,       mAnnodexSerial(0)
00042         ,       mSeenAnnodexBOS(false)
00043         ,       mReadyForCodecs(false)
00044         ,       mSeenCMML(false)
00045         ,       mDemuxState(eAnxDemuxState::SEEN_NOTHING)
00046         ,       mAnxVersion(0)
00047         ,       mAnnodexHeader(NULL)
00048 {
00049 #ifdef OGGCODECS_LOGGING
00050         debugLog.open("G:\\logs\\anxmapper.log", ios_base::out);
00051 #endif
00052 }
00053 
00054 AnxStreamMapper::~AnxStreamMapper(void)
00055 {
00056         debugLog.close();
00057 }
00058 
00059 bool AnxStreamMapper::isReady() {
00060         if (mAnxVersion == 0) {
00061                 return false;
00062         } else if (mAnxVersion == ANX_VERSION_3_0) {
00063                 return OggStreamMapper::isReady();
00064         } else {
00065                 bool retVal = true;
00066                 bool locWasAny = false;
00067                 //Use 1 instead of 0... cmml is always ready and terminates the graph creation early.
00068                 //We want to know when everything else is ready.
00069 
00070                 //XXXXXXXXXXXXXX:::: Big dirty hack to deal with badly ordered header packets !!
00071                 //=======================================================================
00072                 //The side effect is... a file will hang if it has unknown streams.
00073                 //=======================================================================
00074                 if (mSeenStreams.size() == 0) {
00075                         retVal = true;
00076                 } else {
00077                         retVal = false;
00078                 }
00079                 
00080                 for (unsigned long i = 1; i < mStreamList.size(); i++) {
00081                         locWasAny = true;
00082                         retVal = retVal && mStreamList[i]->streamReady();
00083                         //debugLog<<"Stream "<<i<<" ";
00084                         if (retVal) {
00085                                 //debugLog<<"READY !!!!!!"<<endl;
00086                         } else {
00087                                 //debugLog<<"NOT READY !!!!"<<endl;
00088                         }
00089                 }
00090                 //=======================================================================
00091                 if (locWasAny && retVal) {
00092                         debugLog<<"Streams READY"<<endl;
00093                 } else {
00094                         debugLog<<"Streams NOT READY"<<endl;
00095                 }
00096                 return locWasAny && retVal;
00097         }
00098 }
00099 
00100 bool AnxStreamMapper::isAnnodexEOS(OggPage* inOggPage) {
00101         if ((inOggPage->header()->StreamSerialNo() == mAnnodexSerial) &&
00102                                 (inOggPage->header()->isEOS())) {
00103                 return true;
00104         } else {
00105                 return false;
00106         }
00107 
00108 }
00109 bool AnxStreamMapper::isAnnodexBOS(OggPage* inOggPage) {
00110         if  ((inOggPage->numPackets() != 1) ||
00111                                 (inOggPage->getPacket(0)->packetSize() < 12) ||
00112                                 (strncmp((const char*)inOggPage->getPacket(0)->packetData(), "Annodex\0", 8) != 0) || 
00113                                 (!inOggPage->header()->isBOS())) {
00114                 return false;
00115         } else {
00116                 return true;
00117         }
00118 }
00119 
00120 bool AnxStreamMapper::isFisheadBOS(OggPage* inOggPage) {
00121         if  ((inOggPage->numPackets() != 1) ||
00122                                 //(inOggPage->getPacket(0)->packetSize() < 12) ||
00123                                 (strncmp((const char*)inOggPage->getPacket(0)->packetData(), "fishead\0", 8) != 0) || 
00124                                 (!inOggPage->header()->isBOS())) {
00125                 return false;
00126         } else {
00127                 return true;
00128         }
00129 }
00130 bool AnxStreamMapper::isAnxDataPage(OggPage* inOggPage, bool inAnxDataAreBOS) {
00131 
00132         //isBOS                 inAnxDataAreBOS         isValid
00133         //
00134         //true                  true                            true
00135         //true                  false                           false
00136         //false                 true                            false
00137         //false                 false                           true
00138         if  ((inOggPage->numPackets() != 1) ||
00139                                 (inOggPage->getPacket(0)->packetSize() < 12) ||
00140                                 (strncmp((const char*)inOggPage->getPacket(0)->packetData(), "AnxData\0", 8) != 0) || 
00141                                 
00142                                 ( (inOggPage->header()->isBOS()) != inAnxDataAreBOS )) {
00143                 return false;
00144         } else {
00145                 return true;
00146         }
00147 }
00151 unsigned long AnxStreamMapper::getAnxVersion(OggPage* inOggPage) {
00152         if (isAnnodexBOS(inOggPage)) {
00153                         //8 and 10 are the offsets into the header for version number.
00154                         return ((iLE_Math::charArrToUShort(inOggPage->getPacket(0)->packetData() + 8)) << 16) + iLE_Math::charArrToUShort(inOggPage->getPacket(0)->packetData() + 10);
00155         } else if (isFisheadBOS(inOggPage)) {
00156                         return ((iLE_Math::charArrToUShort(inOggPage->getPacket(0)->packetData() + 8)) << 16) + iLE_Math::charArrToUShort(inOggPage->getPacket(0)->packetData() + 10);
00157         } else {
00158                 return 0;
00159         }
00160 
00161         
00162 
00163 }
00164 
00165 bool AnxStreamMapper::handleAnxVersion_2_0(OggPage* inOggPage) {
00166         // LEAK::: Check memory deleting.
00167         const bool ANXDATA_ARE_BOS = true;
00168 
00169         bool locTemp = false;
00170 
00171         vector<unsigned long>::iterator it;
00172         int i = 0;
00173         debugLog<<"handleAnxVersion_2_0 : State = "<<mDemuxState<<endl;
00174         switch (mDemuxState) {
00175                 case SEEN_NOTHING:
00176                         //debugLog<<"SEEN_NOTHING"<<endl;
00177                         //We must find an annodex BOS page.
00178                         if (!isAnnodexBOS(inOggPage)) {
00179                                 mDemuxState = INVALID_STATE;
00180                                 delete inOggPage;
00181                                 return false;
00182                         } else {
00183                                 delete mAnnodexHeader;
00184                                 mAnnodexHeader = inOggPage->getPacket(0)->clone();
00185                                 mAnnodexSerial = inOggPage->header()->StreamSerialNo();
00186                                 mDemuxState = SEEN_ANNODEX_BOS;
00187                                 return true;
00188                         }
00189                         break;          //Can never be here.
00190 
00191                 case SEEN_ANNODEX_BOS:
00192                         //debugLog<<"SEEN_ANNODEX_BOS"<<endl;
00193                         //We should be getting Anxdata headers here.
00194                         if (!isAnxDataPage(inOggPage, ANXDATA_ARE_BOS)) {
00195                                 mDemuxState = INVALID_STATE;
00196                                 return false;
00197                         } else {
00198                                 //This should be the CMML AnxData header.
00199                                 mSeenStreams.clear();
00200                                 mAnxDataHeaders.clear();
00201                                 //mSeenStreams.push_back(inOggPage->header()->StreamSerialNo());
00202                                 mAnxDataHeaders.push_back(inOggPage->getPacket(0)->clone());
00203                                 mDemuxState = SEEN_AN_ANXDATA;
00204 
00205                                 
00206                                 //Add the CMML Stream
00207                                 OggStream* locStream = new CMMLStream(inOggPage, mOwningFilter, true);  //The page is only given for viewing
00208                                 if (locStream != NULL) {
00209                                         //debugLog<<"Adding CMML Stream"<<endl;
00210                                         mStreamList.push_back(locStream);
00211                                 }
00212 
00213                                 return true;
00214                         }
00215                                 
00216 
00217                         break;          //Can never be here.
00218 
00219                 case SEEN_AN_ANXDATA:
00220                         //debugLog<<"SEEN_AN_ANXDATA"<<endl;
00221                         if (isAnnodexEOS(inOggPage)) {
00222                                 //This is the end of the stream headers.
00223                                 mDemuxState = OGG_STATE;
00224                                 //debugLog<<"Found an Annodex EOS... transitioning."<<endl;
00225                                 return true;
00226                         } else if (isAnxDataPage(inOggPage, ANXDATA_ARE_BOS)) {
00227                                 //handle another anxdata page.
00228                                 //debugLog<<"Found another anxdata..."<<endl;
00229                                 mSeenStreams.push_back(inOggPage->header()->StreamSerialNo());
00230                                 mAnxDataHeaders.push_back(inOggPage->getPacket(0)->clone());
00231                                 mDemuxState = SEEN_AN_ANXDATA;
00232                                 return true;
00233                         } else {
00234                                 mDemuxState = INVALID_STATE;
00235                                 return false;
00236                                 //Invalid.
00237                         }
00238                         break;
00239                 case OGG_STATE:
00240                         //debugLog<<"OGG_STATE"<<endl;
00241                         //We've seen the annodex EOS... so we can proceed as if it's a normal ogg file.
00242                         // The CMML stream is already made.
00243 
00244                         for(i = 0, it = mSeenStreams.begin(); it != mSeenStreams.end(); i++, ++it) {
00245                                 debugLog<<"handleAnxVersion_2_0 : Checking seen stream "<<i<<endl;
00246                                 if (mSeenStreams[i] == inOggPage->header()->StreamSerialNo()) {
00247                                         //If the page is a BOS we need to start a new stream
00248                                         const bool ALLOW_OTHERS_TO_SEEK = true;
00249                                         debugLog<<"handleAnxVersion_2_0 : Creating stream "<<endl;
00250                                         OggStream* locStream = OggStreamFactory::CreateStream(inOggPage, mOwningFilter, ALLOW_OTHERS_TO_SEEK);
00251                                         //FIX::: Need to check for NULL
00252                                         if (locStream != NULL) {
00253                                                 debugLog<<"handleAnxVersion_2_0 : Stream Created "<<endl;
00254                                                 mStreamList.push_back(locStream);
00255                                         } else {
00256                                                 debugLog<<"handleAnxVersion_2_0 : ***** Stream NOT Created *****"<<endl;
00257                                         }
00258                                         mSeenStreams.erase(it);
00259                                         delete inOggPage;
00260                                         return true;
00261                                 }
00262                         }
00263 
00264                         //If we are here, the stream is not in the list.
00265                         //At the moment we assume it's because it's been seen, and removed... this is a bad assumption !
00266                         debugLog<<"handleAnxVersion_2_0 : Dispatching page "<<endl;
00267 
00268                         locTemp = dispatchPage(inOggPage);
00269                         if (locTemp) {
00270                                 debugLog<<"handleAnxVersion_2_0 : Sispatch oK "<<endl;
00271                         } else {
00272                                 debugLog<<"handleAnxVersion_2_0 : Dispatch faild "<<endl;
00273                         }
00274                         return locTemp;
00275                         break;
00276                 case INVALID_STATE:
00277                 default:
00278                         debugLog<<"handleAnxVersion_2_0 : INVALID STATE "<<endl;
00279                         return false;
00280                         break;
00281 
00282 
00283 
00284         }
00285 }
00286 
00287 bool AnxStreamMapper::handleAnxVersion_3_0(OggPage* inOggPage) 
00288 {
00289         mDemuxState = OGG_STATE;
00290         return OggStreamMapper::acceptOggPage(inOggPage);
00291         //switch (mDemuxState) {
00292         //      case SEEN_NOTHING:
00293         //              //We must find an annodex BOS page.
00294         //              break;
00295         //      case SEEN_ANNODEX_BOS:
00296         //              break;
00297         //      case SEEN_AN_ANXDATA:
00298         //              break;
00299         //      case OGG_STATE:
00300         //              break;
00301         //      case INVALID_STATE:
00302         //      default:
00303         //              break;
00304 
00305 
00306 
00307         //}
00308         //return false;
00309 }
00310 
00311 bool AnxStreamMapper::acceptOggPage(OggPage* inOggPage)                 //Deletes or gives away page.
00312 {
00313 
00314         if (mDemuxState == SEEN_NOTHING) {
00315                 mAnxVersion = getAnxVersion(inOggPage);
00316                 //debugLog<<"Version is "<<mAnxVersion<<endl;
00317         }
00318         //debugLog<<"Accepting Page..."<<endl;
00319         switch (mAnxVersion) {
00320                 case ANX_VERSION_2_0:
00321                         //Potential memory leaks here !
00322                         
00323                         return handleAnxVersion_2_0(inOggPage);
00324                         break;
00325                 case ANX_VERSION_3_0:
00326                         debugLog<<"handleAnxVersion_3_0 "<<endl;
00327                         return handleAnxVersion_3_0(inOggPage);
00328                 default:
00329                         mDemuxState = INVALID_STATE;
00330                         return false;
00331 
00332         }
00333 
00334 
00335 
00336         //debugLog<<endl<<"-------- accepting page ------"<<endl;
00337         //if (!mReadyForCodecs) {
00338         //      if (inOggPage->header()->isBOS()) {
00339         //              if (!mSeenAnnodexBOS) {
00340         //                      //This is an annodex BOS page
00341         //                      //Need to verify it's an annodex page too
00342         //                      mAnnodexSerial = inOggPage->header()->StreamSerialNo();
00343         //                      mSeenAnnodexBOS = true;
00344         //                      
00345         //                      //Need to save the data from the header here.
00346         //              } else {
00347         //                      //This is anxdata
00348         //                      
00349 
00350         //                      if ( (mSeenCMML == false) ) {
00351         //                              //This is a really nasty way to do it ! Fix this up properly later.
00352         //                              char* locStr = (char*)(inOggPage->getPacket(0)->packetData() + 28);
00353         //                              if (strstr(locStr, "text/x-cmml") != NULL) {
00354         //                                      mSeenCMML = true;
00355         //                                      OggStream* locStream = new CMMLStream(inOggPage, mOwningFilter, true);  //The page is only given for viewing
00356         //                                      if (locStream != NULL) {
00357         //                                              mStreamList.push_back(locStream);
00358         //                                      }
00359         //                              }
00360         //                      } else {
00361         //                      //Need to save header data here.
00362         //                              mSeenStreams.push_back(inOggPage->header()->StreamSerialNo());
00363         //                      }
00364         //              }
00365         //      }
00366 
00367 
00368         //      if (inOggPage->header()->isEOS()) {
00369         //              if (mSeenAnnodexBOS) {
00370         //                      //This is the annodex EOS page
00371         //                      mReadyForCodecs = true;
00372         //              } else {
00373         //                      //ERROR... got an EOS before we've seen the annodex BOS
00374         //                      delete inOggPage;
00375         //                      return false;
00376         //              }
00377         //      }
00378         //      delete inOggPage;
00379         //      return true;
00380         //} else {
00381         //      vector<unsigned long>::iterator it;
00382         //      int i;
00383         //      for(i = 0, it = mSeenStreams.begin(); it != mSeenStreams.end(); i++, ++it) {
00384         //      //for (int i = 0; i < mSeenStreams.size(); i++) {
00385         //              if (mSeenStreams[i] == inOggPage->header()->StreamSerialNo()) {
00386         //                      //If the page is a BOS we need to start a new stream
00387         //                      const bool ALLOW_OTHERS_TO_SEEK = true;
00388         //                      OggStream* locStream = OggStreamFactory::CreateStream(inOggPage, mOwningFilter, ALLOW_OTHERS_TO_SEEK);
00389         //                      //FIX::: Need to check for NULL
00390         //                      if (locStream != NULL) {
00391         //                              mStreamList.push_back(locStream);
00392         //                      }
00393         //                      mSeenStreams.erase(it);
00394         //                      delete inOggPage;
00395         //                      return true;
00396         //              }
00397         //      }
00398 
00399         //      //If we are here, the stream is not in the list.
00400         //      //At the moment we assume it's because it's been seen, and removed... this is a bad assumption !
00401 
00402         //      return dispatchPage(inOggPage);
00403         //}
00404 }
00405 
00406 bool AnxStreamMapper::toStartOfData() {
00407 
00408         if (mAnxVersion == ANX_VERSION_3_0) {
00409                 return OggStreamMapper::toStartOfData();
00410         } else {
00411                 debugLog<<"toStartOfData : S "<<endl;
00412                 //Specialise for anx... adds one extra ignore packet to the flush to account for the anxdata pages only
00413                 // if it's 2.0 version.
00414                 //debugLog<<"ANX::: To start of data size = "<<mStreamList.size()<<endl;
00415                 if (isReady()) {  //CHECK::: Should check for allow dsipatch ???
00416                         for (unsigned long i = 0; i < mStreamList.size(); i++) {
00417                                 //Flush each stream, then ignore the codec headers.
00418                                 if (mAnxVersion == ANX_VERSION_2_0) {
00419                                         //debugLog<<"Flushing stream "<<i<<" for "<<mStreamList[i]->numCodecHeaders() + 1<<endl;
00420                                         mStreamList[i]->flush((unsigned short)(mStreamList[i]->numCodecHeaders() + 1));  //+1 = AnxData Header...
00421                                 } else {
00422                                         mStreamList[i]->flush((unsigned short)(mStreamList[i]->numCodecHeaders()));
00423                                 }
00424                         }       
00425                         return true;
00426                 } else {
00427                         //debugLog<<"Something bad happened !!!!&&&&"<<endl;
00428                         return false;
00429                 }
00430         }
00431 }

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