1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15**********/
16// "liveMedia"
17// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
18// A class that encapsulates a Matroska file.
19// C++ header
20
21#ifndef _MATROSKA_FILE_HH
22#define _MATROSKA_FILE_HH
23
24#ifndef _RTP_SINK_HH
25#include "RTPSink.hh"
26#endif
27#ifndef _FILE_SINK_HH
28#include "FileSink.hh"
29#endif
30#ifndef _HASH_TABLE_HH
31#include "HashTable.hh"
32#endif
33
34class MatroskaTrack; // forward
35class MatroskaDemux; // forward
36
37class MatroskaFile: public Medium {
38public:
39 typedef void (onCreationFunc)(MatroskaFile* newFile, void* clientData);
40 static void createNew(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData,
41 char const* preferredLanguage = "eng");
42 // Note: Unlike most "createNew()" functions, this one doesn't return a new object immediately. Instead, because this class
43 // requires file reading (to parse the Matroska 'Track' headers) before a new object can be initialized, the creation of a new
44 // object is signalled by calling - from the event loop - an 'onCreationFunc' that is passed as a parameter to "createNew()".
45
46 MatroskaTrack* lookup(unsigned trackNumber) const;
47
48 // Create a demultiplexor for extracting tracks from this file. (Separate clients will typically have separate demultiplexors.)
49 MatroskaDemux* newDemux();
50
51 // Parameters of the file ('Segment'); set when the file is parsed:
52 unsigned timecodeScale() { return fTimecodeScale; } // in nanoseconds
53 float segmentDuration() { return fSegmentDuration; } // in units of "timecodeScale()"
54 float fileDuration(); // in seconds
55
56 char const* fileName() const { return fFileName; }
57
58 unsigned chosenVideoTrackNumber() { return fChosenVideoTrackNumber; }
59 unsigned chosenAudioTrackNumber() { return fChosenAudioTrackNumber; }
60 unsigned chosenSubtitleTrackNumber() { return fChosenSubtitleTrackNumber; }
61
62 FramedSource*
63 createSourceForStreaming(FramedSource* baseSource, unsigned trackNumber,
64 unsigned& estBitrate, unsigned& numFiltersInFrontOfTrack);
65 // Takes a data source (which must be a demultiplexed track from this file) and returns
66 // a (possibly modified) data source that can be used for streaming.
67
68 char const* trackMIMEType(unsigned trackNumber) const;
69 // in the form "<medium-name>/<CODEC-NAME>", or NULL if no such track exists
70
71 RTPSink* createRTPSinkForTrackNumber(unsigned trackNumber, Groupsock* rtpGroupsock,
72 unsigned char rtpPayloadTypeIfDynamic);
73 // Creates a "RTPSink" object that would be appropriate for streaming the specified track,
74 // or NULL if no appropriate "RTPSink" exists
75
76 FileSink* createFileSinkForTrackNumber(unsigned trackNumber, char const* fileName);
77 // Creates a "FileSink" object that would be appropriate for recording the contents of
78 // the specified track, or NULL if no appropriate "FileSink" exists.
79
80private:
81 MatroskaFile(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData,
82 char const* preferredLanguage);
83 // called only by createNew()
84 virtual ~MatroskaFile();
85
86 static void handleEndOfTrackHeaderParsing(void* clientData);
87 void handleEndOfTrackHeaderParsing();
88
89 void addTrack(MatroskaTrack* newTrack, unsigned trackNumber);
90 void addCuePoint(double cueTime, u_int64_t clusterOffsetInFile, unsigned blockNumWithinCluster);
91 Boolean lookupCuePoint(double& cueTime, u_int64_t& resultClusterOffsetInFile, unsigned& resultBlockNumWithinCluster);
92 void printCuePoints(FILE* fid);
93
94 void removeDemux(MatroskaDemux* demux);
95
96 void getH264ConfigData(MatroskaTrack const* track,
97 u_int8_t*& sps, unsigned& spsSize,
98 u_int8_t*& pps, unsigned& ppsSize);
99 // "sps","pps" are dynamically allocated by this function, and must be delete[]d afterwards
100 void getH265ConfigData(MatroskaTrack const* track,
101 u_int8_t*& vps, unsigned& vpsSize,
102 u_int8_t*& sps, unsigned& spsSize,
103 u_int8_t*& pps, unsigned& ppsSize);
104 // "vps","sps","pps" are dynamically allocated by this function, and must be delete[]d afterwards
105
106 void getVorbisOrTheoraConfigData(MatroskaTrack const* track,
107 u_int8_t*& identificationHeader, unsigned& identificationHeaderSize,
108 u_int8_t*& commentHeader, unsigned& commentHeaderSize,
109 u_int8_t*& setupHeader, unsigned& setupHeaderSize);
110 // "identificationHeader", "commentHeader", "setupHeader" are dynamically allocated by this function, and must be delete[]d afterwards
111
112private:
113 friend class MatroskaFileParser;
114 friend class MatroskaDemux;
115 char const* fFileName;
116 onCreationFunc* fOnCreation;
117 void* fOnCreationClientData;
118 char const* fPreferredLanguage;
119
120 unsigned fTimecodeScale; // in nanoseconds
121 float fSegmentDuration; // in units of "fTimecodeScale"
122 u_int64_t fSegmentDataOffset, fClusterOffset, fCuesOffset;
123
124 class MatroskaTrackTable* fTrackTable;
125 HashTable* fDemuxesTable;
126 class CuePoint* fCuePoints;
127 unsigned fChosenVideoTrackNumber, fChosenAudioTrackNumber, fChosenSubtitleTrackNumber;
128 class MatroskaFileParser* fParserForInitialization;
129};
130
131// 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:
132// (Note that MATROSKA_TRACK_TYPE_OTHER must be last, and have the largest value.)
133#define MATROSKA_TRACK_TYPE_VIDEO 0x01
134#define MATROSKA_TRACK_TYPE_AUDIO 0x02
135#define MATROSKA_TRACK_TYPE_SUBTITLE 0x04
136#define MATROSKA_TRACK_TYPE_OTHER 0x08
137
138class MatroskaTrack {
139public:
140 MatroskaTrack();
141 virtual ~MatroskaTrack();
142
143 // track parameters
144 unsigned trackNumber;
145 u_int8_t trackType;
146 Boolean isEnabled, isDefault, isForced;
147 unsigned defaultDuration;
148 char* name;
149 char* language;
150 char* codecID;
151 unsigned samplingFrequency;
152 unsigned numChannels;
153 char const* mimeType;
154 unsigned codecPrivateSize;
155 u_int8_t* codecPrivate;
156 Boolean codecPrivateUsesH264FormatForH265; // a hack specifically for H.265 video tracks
157 Boolean codecIsOpus; // a hack for Opus audio
158 unsigned headerStrippedBytesSize;
159 u_int8_t* headerStrippedBytes;
160 char const* colorSampling;
161 char const* colorimetry;
162 unsigned pixelWidth;
163 unsigned pixelHeight;
164 unsigned bitDepth;
165 unsigned subframeSizeSize; // 0 means: frames do not have subframes (the default behavior)
166 Boolean haveSubframes() const { return subframeSizeSize > 0; }
167};
168
169class MatroskaDemux: public Medium {
170public:
171 FramedSource* newDemuxedTrack();
172 FramedSource* newDemuxedTrack(unsigned& resultTrackNumber);
173 // Returns a new stream ("FramedSource" subclass) that represents the next preferred media
174 // track (video, audio, subtitle - in that order) from the file. (Preferred media tracks
175 // are based on the file's language preference.)
176 // This function returns NULL when no more media tracks exist.
177
178 FramedSource* newDemuxedTrackByTrackNumber(unsigned trackNumber);
179 // As above, but creates a new stream for a specific track number within the Matroska file.
180 // (You should not call this function more than once with the same track number.)
181
182 // Note: We assume that:
183 // - Every track created by "newDemuxedTrack()" is later read
184 // - All calls to "newDemuxedTrack()" are made before any track is read
185
186protected:
187 friend class MatroskaFile;
188 friend class MatroskaFileParser;
189 class MatroskaDemuxedTrack* lookupDemuxedTrack(unsigned trackNumber);
190
191 MatroskaDemux(MatroskaFile& ourFile); // we're created only by a "MatroskaFile" (a friend)
192 virtual ~MatroskaDemux();
193
194private:
195 friend class MatroskaDemuxedTrack;
196 void removeTrack(unsigned trackNumber);
197 void continueReading(); // called by a demuxed track to tell us that it has a pending read ("doGetNextFrame()")
198 void seekToTime(double& seekNPT);
199
200 static void handleEndOfFile(void* clientData);
201 void handleEndOfFile();
202
203private:
204 MatroskaFile& fOurFile;
205 class MatroskaFileParser* fOurParser;
206 HashTable* fDemuxedTracksTable;
207
208 // Used to implement "newServerMediaSubsession()":
209 u_int8_t fNextTrackTypeToCheck;
210};
211
212#endif
213