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

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