AnnodexRecomposer.cpp

Go to the documentation of this file.
00001 //===========================================================================
00002 //Copyright (C) 2005 Zentaro Kavanagh
00003 //Copyright (C) 2005 Commonwealth Scientific and Industrial Research
00004 //                   Organisation (CSIRO) Australia
00005 //
00006 //Redistribution and use in source and binary forms, with or without
00007 //modification, are permitted provided that the following conditions
00008 //are met:
00009 //
00010 //- Redistributions of source code must retain the above copyright
00011 //  notice, this list of conditions and the following disclaimer.
00012 //
00013 //- Redistributions in binary form must reproduce the above copyright
00014 //  notice, this list of conditions and the following disclaimer in the
00015 //  documentation and/or other materials provided with the distribution.
00016 //
00017 //- Neither the name of Zentaro Kavanagh nor the names of contributors 
00018 //  may be used to endorse or promote products derived from this software 
00019 //  without specific prior written permission.
00020 //
00021 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 //``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00024 //PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
00025 //CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026 //EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00027 //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 //PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 //===========================================================================
00033 
00034 
00035 #include "stdafx.h"
00036 
00037 #include <libOOOggChef/AnnodexRecomposer.h>
00038 #include <libOOOggChef/CMMLRecomposer.h>
00039 #include <libOOOggChef/utils.h>
00040 
00041 #include <libOOOgg/libOOOgg.h>
00042 #include <libOOOggSeek/AutoAnxSeekTable.h>
00043 
00044 #include <assert.h>
00045 
00046 #include <fstream>
00047 #include <iostream>
00048 #include <string>
00049 #include <vector>
00050 
00051 using namespace std;
00052 
00053 
00054 #undef DEBUG
00055 
00064 AnnodexRecomposer::AnnodexRecomposer(string inFilename,
00065                                                                          BufferWriter inBufferWriter,
00066                                                                          void* inBufferWriterUserData,
00067                                                                          string inCachedSeekTableFilename)
00068         :       mDemuxState(SEEN_NOTHING)
00069         ,       mDemuxParserState(LOOK_FOR_HEADERS)
00070         ,       mBufferWriter(inBufferWriter)
00071         ,       mBufferWriterUserData(inBufferWriterUserData)
00072 {
00073         // These need to go in the constructor body, because we can't assign
00074         // strings in the initialiser list
00075         
00076         mFilename = inFilename;
00077         mCachedSeekTableFilename = inCachedSeekTableFilename;
00078 }
00079 
00080 AnnodexRecomposer::~AnnodexRecomposer(void)
00081 {
00082 }
00083 
00088 bool AnnodexRecomposer::recomposeStreamFrom(double inStartingTimeOffset,
00089         const vector<string>* inWantedMIMETypes)
00090 {
00091         mWantedMIMETypes = inWantedMIMETypes;
00092 
00093 #ifdef DEBUG
00094         mDebugFile.open("G:\\Logs\\AnnodexRecomposer.log", ios_base::out);
00095         mDebugFile << "AnnodexRecomposer 1 " << endl;
00096 #endif
00097 
00098         static const size_t BUFF_SIZE = 8192;
00099 
00100         // Optimisation: If the client only wants CMML, and a file with .cmml
00101         // exists, recompose from that instead of the original .anx file, which
00102         // will be orders of magnitudes faster!
00103         string locCMMLFilename = mFilename + ".cmml";
00104         if (wantOnlyCMML(mWantedMIMETypes) && fileExists(locCMMLFilename)) {
00105 #ifdef DEBUG
00106                 mDebugFile << "Client wants CMML: " + locCMMLFilename + " exists" << endl;
00107 #endif
00108                 CMMLRecomposer *locCMMLRecomposer = new CMMLRecomposer(locCMMLFilename,
00109                         mBufferWriter, mBufferWriterUserData);
00110                 return locCMMLRecomposer->recomposeStreamFrom(inStartingTimeOffset,
00111                         inWantedMIMETypes);
00112         }
00113 
00114         // Turn the starting time offset into DirectSeconds
00115         mRequestedStartTime = (LOOG_UINT64) inStartingTimeOffset * 10000000;
00116 
00117         // Open the file and prepare the OggDataBuffer to receive pages
00118         fstream locFile;
00119         locFile.open(mFilename.c_str(), ios_base::in | ios_base::binary);
00120 
00121         // Build a seek table from the file, so we can find out the end location of
00122         // the stream headers, and the byte position of the user's requested start
00123         // time
00124         AutoAnxSeekTable *locSeekTable = new AutoAnxSeekTable(mFilename);
00125         if (mCachedSeekTableFilename != "" && fileExists(mCachedSeekTableFilename)) {
00126                 locSeekTable->buildTableFromFile(mCachedSeekTableFilename);
00127         } else {
00128                 locSeekTable->buildTable();
00129         }
00130 
00131         if (mCachedSeekTableFilename != "" && !fileExists(mCachedSeekTableFilename)) {
00132                 locSeekTable->serialiseInto(mCachedSeekTableFilename);
00133         }
00134         
00135         // Find out where the non-header packets (i.e. the stream body) starts
00136 
00137         // n.b. We should be using the following line of code to do this:
00138         //
00139         //  unsigned long locStartOfBodyOffset = locSeekTable->getStartPos(0).second;
00140         //
00141         // ... since that should return the body offset, but there's a bug in
00142         // AutoAnxSeekTable (or AutoOggSeekTable) which makes that sometimes
00143         // return 0, which makes it useless for our purposes.  So, we force feed
00144         // the first 640K of the file, which should be enough to detect any headers ;)
00145 
00146         unsigned long locStartOfBodyOffset = 640 * 1024;
00147 
00148 #ifdef DEBUG
00149         mDebugFile << "Filename: " << mFilename << endl;
00150         mDebugFile << "locStartOfBodyOffset: " << locStartOfBodyOffset << endl;
00151 #endif
00152 
00153         // Output CMML preamble if the user wants it
00154         if (wantOnlyCMML(mWantedMIMETypes)) {
00155                 const string CMML_PREAMBLE = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<cmml>\n";
00156                 mBufferWriter((unsigned char *) CMML_PREAMBLE.c_str(), (unsigned long) CMML_PREAMBLE.length(), mBufferWriterUserData);
00157         }
00158 
00159         // Grab the headers from the stream
00160         mDemuxParserState = LOOK_FOR_HEADERS;
00161         {
00162                 OggDataBuffer locOggBuffer;
00163                 locOggBuffer.registerVirtualCallback(this);
00164 
00165                 unsigned long locBytesRead = 0;
00166                 char *locBuffer = new char[BUFF_SIZE];
00167                 while (locBytesRead < locStartOfBodyOffset)
00168                 {
00169                         // MIN is defined in OggPaginator.h (and in about three zillion other
00170                         // projects)
00171                         unsigned long locBytesToRead =
00172                                 MIN(locStartOfBodyOffset - locBytesRead, BUFF_SIZE);
00173                         locFile.read(locBuffer, locBytesToRead);
00174                         unsigned long locBytesReadThisIteration = locFile.gcount();
00175                         if (locBytesReadThisIteration <= 0) {
00176                                 break;
00177                         }
00178                         locOggBuffer.feed((unsigned char *) locBuffer, locBytesReadThisIteration);
00179                 }
00180         }
00181 
00182         // Get the offset into the file from the requested start time
00183         unsigned long locRequestedStartTimeOffset =
00184                 locSeekTable->getStartPos(mRequestedStartTime).second;
00185 
00186         // Clear the file's flags, to avoid any fallout from reading the headers
00187         locFile.clear();
00188         locFile.seekg(locRequestedStartTimeOffset);
00189 
00190 #ifdef DEBUG
00191         mDebugFile << "mRequestedStartTime: " << mRequestedStartTime << endl;
00192         mDebugFile << "locRequestedStartTimeOffset: " << locRequestedStartTimeOffset << endl;
00193         mDebugFile << "Current position: " << locFile.tellg() << endl;
00194 #endif
00195 
00196         // TODO: This is a hack, since sometimes AutoAnxTable returns 0 when it
00197         // really shouldn't ...
00198         size_t locCurrentPosition = locFile.tellg();
00199         if (locCurrentPosition == 0) {
00200 #ifdef DEBUG
00201                 mDebugFile << "Resetting mDemuxState to SEEN_NOTHING bofore LOOK_FOR_BODY" << endl;
00202 #endif
00203                 mDemuxState = SEEN_NOTHING;
00204         }
00205 
00206 #ifdef DEBUG
00207         for (set<tSerial_HeadCountPair>::iterator i = mWantedStreamSerialNumbers.begin(); i != mWantedStreamSerialNumbers.end(); i++) {
00208                 mDebugFile << "Serialno: " << i->first << endl;
00209         }
00210 
00211         mDebugFile << "mDemuxState before LOOK_FOR_BODY is " << mDemuxState << endl;
00212 #endif
00213 
00214         mDemuxParserState = LOOK_FOR_BODY;
00215         {
00216                 OggDataBuffer locOggBuffer;
00217                 locOggBuffer.registerVirtualCallback(this);
00218 
00219                 char *locBuffer = new char[BUFF_SIZE];
00220                 for (;;)
00221                 {
00222                         locFile.read(locBuffer, BUFF_SIZE);
00223                         unsigned long locBytesReadThisIteration = locFile.gcount();
00224                         if (locBytesReadThisIteration <= 0) {
00225                                 break;
00226                         }
00227                         locOggBuffer.feed((unsigned char *) locBuffer, locBytesReadThisIteration);
00228                 }
00229         }
00230 
00231         // Output CMML preamble if the user wants it
00232         if (wantOnlyCMML(mWantedMIMETypes)) {
00233                 const string CMML_POSTAMBLE = "\n</cmml>";
00234                 mBufferWriter((unsigned char *) CMML_POSTAMBLE.c_str(), (unsigned long) CMML_POSTAMBLE.length(), mBufferWriterUserData);
00235         }
00236 
00237         // Tidy up
00238         locFile.close();
00239 
00240 #ifdef DEBUG
00241         mDebugFile << "----------------" << endl;
00242         mDebugFile.close();
00243 #endif
00244 
00245         return true;
00246 }
00247 
00248 bool isAnnodexBOSPage (OggPage *inOggPage)
00249 {
00250         return (
00251                         inOggPage->numPackets() == 1
00252                 &&      inOggPage->header()->isBOS()
00253                 &&      strncmp((char*)inOggPage->getPacket(0)->packetData(),
00254                             "Annodex\0", 8) == 0
00255                    );
00256 }
00257 
00258 bool isFisheadPage (OggPage *inOggPage)
00259 {
00260         return (
00261                         inOggPage->numPackets() == 1
00262                 &&      inOggPage->header()->isBOS()
00263                 &&      strncmp((char*)inOggPage->getPacket(0)->packetData(),
00264                             "fishead\0", 8) == 0
00265                    );
00266 }
00267 
00268 bool isAnxDataPage (OggPage *inOggPage)
00269 {
00270         return (
00271                         inOggPage->numPackets() == 1
00272                 &&      inOggPage->header()->isBOS()
00273                 &&      strncmp((char*)inOggPage->getPacket(0)->packetData(),
00274                             "AnxData\0", 8) == 0
00275                    );
00276 }
00277 
00278 bool isAnnodexEOSPage (OggPage *inOggPage, unsigned long locAnnodexSerialNumber)
00279 {
00280         return (
00281                         inOggPage->header()->isEOS()
00282                 &&      inOggPage->header()->StreamSerialNo() == locAnnodexSerialNumber
00283                    );
00284 }
00285 
00286 unsigned long secondaryHeaders(OggPacket* inPacket, const unsigned short inAnnodexMajorVersion)
00287 {
00288         if (inAnnodexMajorVersion == 2) {
00289 
00290                 const unsigned short NUM_SEC_HEADERS_OFFSET = 24;
00291 
00292                 return iLE_Math::charArrToULong(inPacket->packetData() +
00293                                                                                 NUM_SEC_HEADERS_OFFSET);
00294 
00295         } else if (inAnnodexMajorVersion == 3) {
00296 
00297                 // We're hardcoding the codec types in here for now: see the comment
00298                 // above the mimeType function for why.
00299 
00300                 unsigned long locSecondaryHeaders = 0;
00301 
00302                 char* locPacketData = (char*) inPacket->packetData();
00303                 if (memcmp(locPacketData, "\001vorbis", 7) == 0) {
00304                         locSecondaryHeaders = 3;
00305                 } else if (memcmp(locPacketData, "\200theora", 7) == 0) {
00306                         locSecondaryHeaders = 3;
00307                 } else if (memcmp(locPacketData, "CMML\0\0\0\0", 8) == 0) {
00308                         locSecondaryHeaders = 3;
00309                 } else {
00310                         locSecondaryHeaders = 3;
00311                 }
00312 
00313                 return locSecondaryHeaders;
00314 
00315         } else {
00316                 // Neither V2 nor V3: ack!
00317                 return 0;
00318         }
00319 }
00320 
00321 void setPresentationTimeOnAnnodexHeaderPage (OggPage *inOggPage, LOOG_UINT64 inPresentationTime)
00322 {
00323         // Offsets for Annodex v2 (the "timebase" field)
00324         const unsigned short V2_PRESENTATION_TIME_NUMERATOR_OFFSET = 12;
00325         const unsigned short V2_PRESENTATION_TIME_DENOMINATOR_OFFSET =
00326                 V2_PRESENTATION_TIME_NUMERATOR_OFFSET + 8;
00327 
00328         // Offsets for Annodex v3 (the "presentation time" field)
00329         const unsigned short V3_PRESENTATION_TIME_NUMERATOR_OFFSET = 12;
00330         const unsigned short V3_PRESENTATION_TIME_DENOMINATOR_OFFSET =
00331                 V3_PRESENTATION_TIME_NUMERATOR_OFFSET + 8;
00332 
00333         // Figure out whether we're dealing with V2 or V3 and set the presentation
00334         // time offsets appropriately
00335         unsigned short locPresentationTimeNumeratorOffset = 0;
00336         unsigned short locPresentationTimeDenominatorOffset = 0;
00337         if (isAnnodexBOSPage(inOggPage)) {
00338                 // Annodex V2
00339                 locPresentationTimeNumeratorOffset = V2_PRESENTATION_TIME_NUMERATOR_OFFSET;
00340                 locPresentationTimeDenominatorOffset = V2_PRESENTATION_TIME_DENOMINATOR_OFFSET;
00341         } else if (isFisheadPage(inOggPage)) {
00342                 // Annodex V3
00343                 locPresentationTimeNumeratorOffset = V3_PRESENTATION_TIME_NUMERATOR_OFFSET;
00344                 locPresentationTimeDenominatorOffset = V3_PRESENTATION_TIME_DENOMINATOR_OFFSET;
00345         } else {
00346                 // We don't recognise this page: return early before we do anything
00347                 // harmful
00348                 return;
00349         }
00350 
00351         unsigned char* locPacketData = inOggPage->getPacket(0)->packetData();
00352 
00353         // Get pointers for the offsets into the packet
00354         unsigned char* locNumeratorPointer = locPacketData + locPresentationTimeNumeratorOffset;
00355         unsigned char* locDenominatorPointer = locPacketData + locPresentationTimeDenominatorOffset;
00356         
00357         // Set the presentation time on the packet in DirectSeconds (using the
00358         // denominator to indicate that the units are in DirectSeconds)
00359         iLE_Math::Int64ToCharArr(inPresentationTime, locNumeratorPointer);
00360         iLE_Math::Int64ToCharArr(10000000, locDenominatorPointer);
00361 
00362         // Recompute the Ogg page's checksum
00363         inOggPage->computeAndSetCRCChecksum();
00364 }
00365 
00366 #ifdef WIN32
00367 # define strncasecmp _strnicmp
00368 #endif /* will be undef'ed below */
00369 string mimeType(OggPacket* inPacket, const unsigned short inAnnodexMajorVersion)
00370 {
00371         if (inAnnodexMajorVersion == 2) {
00372                 const unsigned short CONTENT_TYPE_OFFSET = 28;
00373 
00374                 if (strncasecmp((char *) inPacket->packetData() + CONTENT_TYPE_OFFSET,
00375                         "Content-Type: ", 14) == 0)
00376                 {
00377                         const unsigned short MIME_TYPE_OFFSET = 28 + 14;
00378                         const unsigned short MAX_MIME_TYPE_LENGTH = 256;
00379                         char *locMimeType = new char[MAX_MIME_TYPE_LENGTH];
00380                         sscanf((char *) inPacket->packetData() + MIME_TYPE_OFFSET, "%s\r\n", locMimeType);
00381                         return locMimeType;
00382                 } else {
00383                         return NULL;
00384                 }
00385         } else if (inAnnodexMajorVersion == 3) {
00386                 // Ahem, we should _really_ peek into the fisbone track to do this
00387                 // properly, but considering that you need to understand the codecs to
00388                 // build the seek table anyway, yet another codec dependency here
00389                 // isn't going to kill us.  Obviously this is a very bad long-term
00390                 // solution since the V3 Annodex skeleton is meant to be completely
00391                 // codec-independent, but too much of this framework is currently
00392                 // littered with codec knowledge.
00393                 string locMimeType;
00394 
00395                 char* locPacketData = (char*) inPacket->packetData();
00396                 if (memcmp(locPacketData, "\001vorbis", 7) == 0) {
00397                         locMimeType = "audio/x-vorbis";
00398                 } else if (memcmp(locPacketData, "\200theora", 7) == 0) {
00399                         locMimeType = "video/x-theora";
00400                 } else if (memcmp(locPacketData, "CMML\0\0\0\0", 8) == 0) {
00401                         locMimeType = "text/x-cmml";
00402                 } else if (memcmp(locPacketData, "fisbone\0", 8) == 0) {
00403                         locMimeType = "_skeleton";
00404                 }
00405 
00406                 return locMimeType;
00407 
00408         } else {
00409                 // Neither V2 nor V3: exit with extreme prejudice
00410                 return NULL;
00411         }
00412 }
00413 #ifdef WIN32
00414 # undef strcasecmp
00415 #endif
00416 
00417 bool AnnodexRecomposer::acceptOggPage(OggPage* inOggPage)
00418 {
00419         if (mDemuxParserState == LOOK_FOR_HEADERS) {
00420 
00421                 switch (mDemuxState) {
00422 
00423                         case SEEN_NOTHING:
00424                                 if (isAnnodexBOSPage(inOggPage) || isFisheadPage(inOggPage)) {
00425                                         mDemuxState = SEEN_ANNODEX_BOS;
00426 
00427                                         // Do we have a V2 or V3 Annodex file?
00428                                         if (isAnnodexBOSPage(inOggPage)) {
00429 #ifdef DEBUG
00430                                                 mDebugFile << "Found Annodex v2 file" << endl;
00431 #endif
00432                                                 mAnnodexMajorVersion = 2;
00433                                         } else if (isFisheadPage(inOggPage)) {
00434 #ifdef DEBUG
00435                                                 mDebugFile << "Found Annodex v3 file" << endl;
00436 #endif
00437                                                 mAnnodexMajorVersion = 3;
00438                                         }
00439 
00440                                         // Remember the Annodex stream's serial number, so we can output it later
00441                                         mAnnodexSerialNumber = inOggPage->header()->StreamSerialNo();
00442                                         mWantedStreamSerialNumbers.insert(make_pair<unsigned long, unsigned long>(mAnnodexSerialNumber, 0));
00443 
00444                                         // Fix up the presentation time of the Annodex BOS page if we're not
00445                                         // serving out the data from time 0
00446                                         if (mRequestedStartTime != 0) {
00447                                                 setPresentationTimeOnAnnodexHeaderPage(inOggPage, mRequestedStartTime);
00448                                         }
00449 
00450                                         if (!wantOnlyPacketBody(mWantedMIMETypes)) {
00451                                                 // Send out the page
00452                                                 unsigned char *locRawPageData = inOggPage->createRawPageData();
00453                                                 mBufferWriter(locRawPageData,
00454                                                         inOggPage->pageSize(), mBufferWriterUserData);
00455                                                 delete locRawPageData;
00456                                         }
00457                                 } else {
00458                                         // The Annodex/Fishead BOS page should always be the very first page of
00459                                         // the stream, so if we don't see it, the stream's invalid
00460                                         mDemuxState = INVALID;
00461                                 }
00462                                 break;
00463 
00464                         case SEEN_ANNODEX_BOS:
00465                                 if (isAnnodexEOSPage(inOggPage, mAnnodexSerialNumber)) {
00466 #ifdef DEBUG
00467                                         mDebugFile << "Seen Annodex skeleton EOS" << endl;
00468 #endif
00469                                         mDemuxState = SEEN_ANNODEX_EOS;
00470                                         if (!wantOnlyPacketBody(mWantedMIMETypes)) {
00471                                                 unsigned char *locRawPageData = inOggPage->createRawPageData();
00472                                                 mBufferWriter(locRawPageData,
00473                                                         inOggPage->pageSize(), mBufferWriterUserData);
00474                                                 delete locRawPageData;
00475                                         }
00476                                 } else if ((    mAnnodexMajorVersion == 2 && isAnxDataPage(inOggPage))
00477                                                         ||      mAnnodexMajorVersion == 3) {
00478                                         unsigned long locSerialNumber = inOggPage->header()->StreamSerialNo();
00479                                         string locMimeType = mimeType(inOggPage->getPacket(0), mAnnodexMajorVersion);
00480 
00481                                         for (unsigned int i = 0; i < mWantedMIMETypes->size(); i++) {
00482                                                 const string locWantedMIMEType = mWantedMIMETypes->at(i);
00483                                                 if (    locWantedMIMEType == locMimeType
00484                                                         ||      locWantedMIMEType == "*/*" /* accept all */
00485                                                         ||      locWantedMIMEType == "application/x-annodex") {
00486                                                         // Create an association of serial no and num headers
00487                                                         tSerial_HeadCountPair locMap;
00488                                                         locMap.first = locSerialNumber;
00489                                                         locMap.second = secondaryHeaders(inOggPage->getPacket(0), mAnnodexMajorVersion);
00490 
00491                                                         // Add the association to our stream list
00492                                                         if ((mWantedStreamSerialNumbers.insert(locMap)).second) {
00493 #ifdef DEBUG
00494                                                                 mDebugFile << "Added " << locSerialNumber << " with " << locMap.second << " to mWantedStreamSerialNumbers" << endl;
00495 #endif
00496                                                         }
00497 
00498                                                         if (!wantOnlyPacketBody(mWantedMIMETypes)) {
00499                                                                 unsigned char *locRawPageData = inOggPage->createRawPageData();
00500                                                                 mBufferWriter(locRawPageData,
00501                                                                         inOggPage->pageSize(), mBufferWriterUserData);
00502                                                                 delete locRawPageData;
00503                                                         }
00504                                                 }
00505                                         }
00506                                 } else {
00507                                         // We didn't spot either an AnxData page or the Annodex
00508                                         // EOS (v2), or a fisbone/header page (v3).  WTF?
00509                                         mDemuxState = INVALID;
00510                                 }
00511                                 break;
00512 
00513                         case SEEN_ANNODEX_EOS:
00514                                 if (mAnnodexMajorVersion == 2) {
00515                                         // Only output headers for the streams that the user wants
00516                                         // in their request
00517                                         for (set<tSerial_HeadCountPair>::iterator i = mWantedStreamSerialNumbers.begin(); i != mWantedStreamSerialNumbers.end(); i++) {
00518                                                 if (i->first == inOggPage->header()->StreamSerialNo()) {
00519                                                         if (i->second >= 1) {
00520                                                                 i->second--;
00521                                                                 if (wantOnlyPacketBody(mWantedMIMETypes)) {
00522                                                                         OggPacket* locPacket = inOggPage->getPacket(0);
00523                                                                         mBufferWriter(locPacket->packetData(),
00524                                                                                 locPacket->packetSize(), mBufferWriterUserData);
00525                                                                 } else {
00526                                                                         unsigned char *locRawPageData = inOggPage->createRawPageData();
00527                                                                         mBufferWriter(locRawPageData,
00528                                                                                 inOggPage->pageSize(), mBufferWriterUserData);
00529                                                                         delete locRawPageData;
00530                                                                 }
00531                                                         } 
00532                                                 }
00533                                         }
00534 
00535                                         bool allEmpty = true;
00536                                         for (set<tSerial_HeadCountPair>::iterator i = mWantedStreamSerialNumbers.begin(); i != mWantedStreamSerialNumbers.end(); i++) {
00537                                                 if (i->second != 0) {
00538                                                         allEmpty = false;
00539                                                 }
00540                                         }
00541 
00542                                         if (allEmpty) {
00543                                                 mDemuxState = SEEN_ALL_CODEC_HEADERS;
00544                                         }
00545                                 } else if (mAnnodexMajorVersion == 3) {
00546                                         // Annodex V3: once we hit the Annodex EOS, all the page headers are done
00547                                         mDemuxState = SEEN_ALL_CODEC_HEADERS;
00548                                 }
00549                                 break;
00550                         case SEEN_ALL_CODEC_HEADERS:
00551                                 // Seen all the headers: don't do anything
00552                                 break;
00553                         case INVALID:
00554                                 break;
00555                         default:
00556                                 break;
00557                 }
00558 
00559         } else if (mDemuxParserState == LOOK_FOR_BODY) {
00560 
00561                 switch (mDemuxState) {
00562 
00563                         case SEEN_NOTHING:
00564                                 if (isAnnodexBOSPage(inOggPage) || isFisheadPage(inOggPage)) {
00565                                         mDemuxState = SEEN_ANNODEX_BOS;
00566                                 } else {
00567                                         // The Annodex BOS page should always be the very first page of
00568                                         // the stream, so if we don't see it, the stream's invalid
00569                                         mDemuxState = INVALID;
00570                                 }
00571                                 break;
00572 
00573                         case SEEN_ANNODEX_BOS:
00574                                 if (isAnnodexEOSPage(inOggPage, mAnnodexSerialNumber)) {
00575                                         mDemuxState = SEEN_ANNODEX_EOS;
00576                                 } else if (             (mAnnodexMajorVersion == 2 && isAnxDataPage(inOggPage))
00577                                                         ||       mAnnodexMajorVersion == 3) {
00578                                         // Do nothing
00579                                 } else {
00580                                         // We didn't spot either an AnxData page or the Annodex EOS: WTF?
00581                                         mDemuxState = INVALID;
00582                                 }
00583                                 break;
00584 
00585                         case SEEN_ANNODEX_EOS:
00586                                 mDemuxState = SEEN_ALL_CODEC_HEADERS;
00587                                 // Fallthrough!
00588                         case SEEN_ALL_CODEC_HEADERS:
00589                                 {
00590                                         // Ignore any header packets which we may encounter
00591                                         if ((inOggPage->header()->HeaderFlags() & OggPageHeader::BOS) != 0) {
00592                                                 break;
00593                                         }
00594 
00595                                         // Only output streams which the user requested
00596                                         for (set<tSerial_HeadCountPair>::iterator i = mWantedStreamSerialNumbers.begin(); i != mWantedStreamSerialNumbers.end(); i++) {
00597                                                 if (i->first == inOggPage->header()->StreamSerialNo()) {
00598 #ifdef DEBUG
00599                                                         mDebugFile << "Outputting page for serialno " << i->first << endl;
00600 #endif
00601                                                         if (wantOnlyPacketBody(mWantedMIMETypes)) {
00602                                                                 for (unsigned long j = 0; j < inOggPage->numPackets(); j++) {
00603                                                                         OggPacket* locPacket = inOggPage->getPacket(j);
00604                                                                         if (locPacket->packetSize() > 0) {
00605                                                                                 mBufferWriter(locPacket->packetData(),
00606                                                                                         locPacket->packetSize(), mBufferWriterUserData);
00607                                                                         }
00608                                                                 }
00609                                                         } else {
00610                                                                 unsigned char *locRawPageData = inOggPage->createRawPageData();                                                         
00611                                                                 mBufferWriter(locRawPageData,
00612                                                                         inOggPage->pageSize(), mBufferWriterUserData);
00613                                                                 delete locRawPageData;
00614                                                         }
00615                                                 }
00616                                         }
00617                                 }
00618                                 break;
00619                         case INVALID:
00620                                 break;
00621                         default:
00622                                 break;
00623                 }
00624 
00625         } else {
00626                 // Should never get here!
00627                 assert(0);
00628         }
00629 
00630         // Tidy up
00631         delete inOggPage;
00632         inOggPage = NULL;
00633 
00634         return true;
00635 }

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