/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. (See .) This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2021 Live Networks, Inc. All rights reserved. // A class that encapsulates an Ogg file // C++ header #ifndef _OGG_FILE_HH #define _OGG_FILE_HH #ifndef _RTP_SINK_HH #include "RTPSink.hh" #endif #ifndef _HASH_TABLE_HH #include "HashTable.hh" #endif class OggTrack; // forward class OggDemux; // forward typedef void OggDemuxOnDeletionFunc(void* objectToNotify, OggDemux* demuxBeingDeleted); class OggFile: public Medium { public: typedef void (onCreationFunc)(OggFile* newFile, void* clientData); static void createNew(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData); // Note: Unlike most "createNew()" functions, this one doesn't return a new object // immediately. Instead, because this class requires file reading (to parse the // Ogg track headers) before a new object can be initialized, the creation of a new object // is signalled by calling - from the event loop - an 'onCreationFunc' that is passed as // a parameter to "createNew()". OggTrack* lookup(u_int32_t trackNumber); OggDemux* newDemux(OggDemuxOnDeletionFunc* onDeletionFunc = NULL, void* objectToNotify = NULL); // Creates a demultiplexor for extracting tracks from this file. // (Separate clients will typically have separate demultiplexors.) char const* fileName() const { return fFileName; } unsigned numTracks() const; FramedSource* createSourceForStreaming(FramedSource* baseSource, u_int32_t trackNumber, unsigned& estBitrate, unsigned& numFiltersInFrontOfTrack); // Takes a data source (which must be a demultiplexed track from this file) and returns // a (possibly modified) data source that can be used for streaming. RTPSink* createRTPSinkForTrackNumber(u_int32_t trackNumber, Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic); // Creates a "RTPSink" object that would be appropriate for streaming the specified track, // or NULL if no appropriate "RTPSink" exists class OggTrackTable& trackTable() { return *fTrackTable; } private: OggFile(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData); // called only by createNew() virtual ~OggFile(); static void handleEndOfBosPageParsing(void* clientData); void handleEndOfBosPageParsing(); void addTrack(OggTrack* newTrack); void removeDemux(OggDemux* demux); private: friend class OggFileParser; friend class OggDemux; char const* fFileName; onCreationFunc* fOnCreation; void* fOnCreationClientData; class OggTrackTable* fTrackTable; HashTable* fDemuxesTable; class OggFileParser* fParserForInitialization; }; class OggTrack { public: OggTrack(); virtual ~OggTrack(); // track parameters u_int32_t trackNumber; // bitstream serial number char const* mimeType; // NULL if not known unsigned samplingFrequency, numChannels; // for audio tracks unsigned estBitrate; // estimate, in kbps (for RTCP) // Special headers for Vorbis audio, Theora video, and Opus audio tracks: struct _vtoHdrs { u_int8_t* header[3]; // "identification", "comment", "setup" unsigned headerSize[3]; // Fields specific to Vorbis audio: unsigned blocksize[2]; // samples per frame (packet) unsigned uSecsPerPacket[2]; // computed as (blocksize[i]*1000000)/samplingFrequency unsigned vorbis_mode_count; unsigned ilog_vorbis_mode_count_minus_1; u_int8_t* vorbis_mode_blockflag; // an array (of size "vorbis_mode_count") of indexes into the (2-entry) "blocksize" array // Fields specific to Theora video: u_int8_t KFGSHIFT; unsigned uSecsPerFrame; } vtoHdrs; Boolean weNeedHeaders() const { return vtoHdrs.header[0] == NULL || vtoHdrs.header[1] == NULL || (vtoHdrs.header[2] == NULL && strcmp(mimeType, "audio/OPUS") != 0); } }; class OggTrackTableIterator { public: OggTrackTableIterator(class OggTrackTable& ourTable); virtual ~OggTrackTableIterator(); OggTrack* next(); private: HashTable::Iterator* fIter; }; class OggDemux: public Medium { public: FramedSource* newDemuxedTrack(u_int32_t& resultTrackNumber); // Returns a new stream ("FramedSource" subclass) that represents the next media track // from the file. This function returns NULL when no more media tracks exist. FramedSource* newDemuxedTrackByTrackNumber(unsigned trackNumber); // As above, but creates a new stream for a specific track number within the Matroska file. // (You should not call this function more than once with the same track number.) // Note: We assume that: // - Every track created by "newDemuxedTrack()" is later read // - All calls to "newDemuxedTrack()" are made before any track is read protected: friend class OggFile; friend class OggFileParser; class OggDemuxedTrack* lookupDemuxedTrack(u_int32_t trackNumber); OggDemux(OggFile& ourFile); virtual ~OggDemux(); private: friend class OggDemuxedTrack; void removeTrack(u_int32_t trackNumber); void continueReading(); // called by a demuxed track to tell us that it has a pending read ("doGetNextFrame()") static void handleEndOfFile(void* clientData); void handleEndOfFile(); private: OggFile& fOurFile; class OggFileParser* fOurParser; HashTable* fDemuxedTracksTable; OggTrackTableIterator* fIter; }; #endif