182 lines
7.1 KiB
C++
Executable File
182 lines
7.1 KiB
C++
Executable File
/**********
|
|
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 2.1 of the License, or (at your
|
|
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
|
|
|
|
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-2015 Live Networks, Inc. All rights reserved.
|
|
// A class that encapsulates a Matroska file.
|
|
// C++ header
|
|
|
|
#ifndef _MATROSKA_FILE_HH
|
|
#define _MATROSKA_FILE_HH
|
|
|
|
#ifndef _RTP_SINK_HH
|
|
#include "RTPSink.hh"
|
|
#endif
|
|
#ifndef _HASH_TABLE_HH
|
|
#include "HashTable.hh"
|
|
#endif
|
|
|
|
class MatroskaTrack; // forward
|
|
class MatroskaDemux; // forward
|
|
|
|
class MatroskaFile: public Medium {
|
|
public:
|
|
typedef void (onCreationFunc)(MatroskaFile* newFile, void* clientData);
|
|
static void createNew(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData,
|
|
char const* preferredLanguage = "eng");
|
|
// Note: Unlike most "createNew()" functions, this one doesn't return a new object immediately. Instead, because this class
|
|
// requires file reading (to parse the Matroska '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()".
|
|
|
|
MatroskaTrack* lookup(unsigned trackNumber) const;
|
|
|
|
// Create a demultiplexor for extracting tracks from this file. (Separate clients will typically have separate demultiplexors.)
|
|
MatroskaDemux* newDemux();
|
|
|
|
// Parameters of the file ('Segment'); set when the file is parsed:
|
|
unsigned timecodeScale() { return fTimecodeScale; } // in nanoseconds
|
|
float segmentDuration() { return fSegmentDuration; } // in units of "timecodeScale()"
|
|
float fileDuration(); // in seconds
|
|
|
|
char const* fileName() const { return fFileName; }
|
|
|
|
unsigned chosenVideoTrackNumber() { return fChosenVideoTrackNumber; }
|
|
unsigned chosenAudioTrackNumber() { return fChosenAudioTrackNumber; }
|
|
unsigned chosenSubtitleTrackNumber() { return fChosenSubtitleTrackNumber; }
|
|
|
|
FramedSource*
|
|
createSourceForStreaming(FramedSource* baseSource, unsigned 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(unsigned 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
|
|
|
|
private:
|
|
MatroskaFile(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData,
|
|
char const* preferredLanguage);
|
|
// called only by createNew()
|
|
virtual ~MatroskaFile();
|
|
|
|
static void handleEndOfTrackHeaderParsing(void* clientData);
|
|
void handleEndOfTrackHeaderParsing();
|
|
|
|
void addTrack(MatroskaTrack* newTrack, unsigned trackNumber);
|
|
void addCuePoint(double cueTime, u_int64_t clusterOffsetInFile, unsigned blockNumWithinCluster);
|
|
Boolean lookupCuePoint(double& cueTime, u_int64_t& resultClusterOffsetInFile, unsigned& resultBlockNumWithinCluster);
|
|
void printCuePoints(FILE* fid);
|
|
|
|
void removeDemux(MatroskaDemux* demux);
|
|
|
|
private:
|
|
friend class MatroskaFileParser;
|
|
friend class MatroskaDemux;
|
|
char const* fFileName;
|
|
onCreationFunc* fOnCreation;
|
|
void* fOnCreationClientData;
|
|
char const* fPreferredLanguage;
|
|
|
|
unsigned fTimecodeScale; // in nanoseconds
|
|
float fSegmentDuration; // in units of "fTimecodeScale"
|
|
u_int64_t fSegmentDataOffset, fClusterOffset, fCuesOffset;
|
|
|
|
class MatroskaTrackTable* fTrackTable;
|
|
HashTable* fDemuxesTable;
|
|
class CuePoint* fCuePoints;
|
|
unsigned fChosenVideoTrackNumber, fChosenAudioTrackNumber, fChosenSubtitleTrackNumber;
|
|
class MatroskaFileParser* fParserForInitialization;
|
|
};
|
|
|
|
// We define our own track type codes as bits (powers of 2), so we can use the set of track types as a bitmap, representing a set:
|
|
// (Note that MATROSKA_TRACK_TYPE_OTHER must be last, and have the largest value.)
|
|
#define MATROSKA_TRACK_TYPE_VIDEO 0x01
|
|
#define MATROSKA_TRACK_TYPE_AUDIO 0x02
|
|
#define MATROSKA_TRACK_TYPE_SUBTITLE 0x04
|
|
#define MATROSKA_TRACK_TYPE_OTHER 0x08
|
|
|
|
class MatroskaTrack {
|
|
public:
|
|
MatroskaTrack();
|
|
virtual ~MatroskaTrack();
|
|
|
|
// track parameters
|
|
unsigned trackNumber;
|
|
u_int8_t trackType;
|
|
Boolean isEnabled, isDefault, isForced;
|
|
unsigned defaultDuration;
|
|
char* name;
|
|
char* language;
|
|
char* codecID;
|
|
unsigned samplingFrequency;
|
|
unsigned numChannels;
|
|
char const* mimeType;
|
|
unsigned codecPrivateSize;
|
|
u_int8_t* codecPrivate;
|
|
Boolean codecPrivateUsesH264FormatForH265; // a hack specifically for H.265 video tracks
|
|
Boolean codecIsOpus; // a hack for Opus audio
|
|
unsigned headerStrippedBytesSize;
|
|
u_int8_t* headerStrippedBytes;
|
|
unsigned subframeSizeSize; // 0 means: frames do not have subframes (the default behavior)
|
|
Boolean haveSubframes() const { return subframeSizeSize > 0; }
|
|
};
|
|
|
|
class MatroskaDemux: public Medium {
|
|
public:
|
|
FramedSource* newDemuxedTrack();
|
|
FramedSource* newDemuxedTrack(unsigned& resultTrackNumber);
|
|
// Returns a new stream ("FramedSource" subclass) that represents the next preferred media
|
|
// track (video, audio, subtitle - in that order) from the file. (Preferred media tracks
|
|
// are based on the file's language preference.)
|
|
// 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 MatroskaFile;
|
|
friend class MatroskaFileParser;
|
|
class MatroskaDemuxedTrack* lookupDemuxedTrack(unsigned trackNumber);
|
|
|
|
MatroskaDemux(MatroskaFile& ourFile); // we're created only by a "MatroskaFile" (a friend)
|
|
virtual ~MatroskaDemux();
|
|
|
|
private:
|
|
friend class MatroskaDemuxedTrack;
|
|
void removeTrack(unsigned trackNumber);
|
|
void continueReading(); // called by a demuxed track to tell us that it has a pending read ("doGetNextFrame()")
|
|
void seekToTime(double& seekNPT);
|
|
|
|
static void handleEndOfFile(void* clientData);
|
|
void handleEndOfFile();
|
|
|
|
private:
|
|
MatroskaFile& fOurFile;
|
|
class MatroskaFileParser* fOurParser;
|
|
HashTable* fDemuxedTracksTable;
|
|
|
|
// Used to implement "newServerMediaSubsession()":
|
|
u_int8_t fNextTrackTypeToCheck;
|
|
};
|
|
|
|
#endif
|