1 | /********** |
2 | This library is free software; you can redistribute it and/or modify it under |
3 | the terms of the GNU Lesser General Public License as published by the |
4 | Free Software Foundation; either version 3 of the License, or (at your |
5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
6 | |
7 | This library is distributed in the hope that it will be useful, but WITHOUT |
8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
10 | more details. |
11 | |
12 | You should have received a copy of the GNU Lesser General Public License |
13 | along with this library; if not, write to the Free Software Foundation, Inc., |
14 | 51 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 | |
34 | class MatroskaTrack; // forward |
35 | class MatroskaDemux; // forward |
36 | |
37 | class MatroskaFile: public Medium { |
38 | public: |
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 | |
80 | private: |
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*& , unsigned& , |
108 | u_int8_t*& , unsigned& , |
109 | u_int8_t*& , unsigned& ); |
110 | // "identificationHeader", "commentHeader", "setupHeader" are dynamically allocated by this function, and must be delete[]d afterwards |
111 | |
112 | private: |
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 | |
138 | class MatroskaTrack { |
139 | public: |
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 ; |
159 | u_int8_t* ; |
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 | |
169 | class MatroskaDemux: public Medium { |
170 | public: |
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 | |
186 | protected: |
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 | |
194 | private: |
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 | |
203 | private: |
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 | |