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 server demultiplexor for a Matroska file
19// Implementation
20
21#include "MatroskaFileServerDemux.hh"
22#include "MP3AudioMatroskaFileServerMediaSubsession.hh"
23#include "MatroskaFileServerMediaSubsession.hh"
24
25void MatroskaFileServerDemux
26::createNew(UsageEnvironment& env, char const* fileName,
27 onCreationFunc* onCreation, void* onCreationClientData,
28 char const* preferredLanguage) {
29 (void)new MatroskaFileServerDemux(env, fileName,
30 onCreation, onCreationClientData,
31 preferredLanguage);
32}
33
34ServerMediaSubsession* MatroskaFileServerDemux::newServerMediaSubsession() {
35 unsigned dummyResultTrackNumber;
36 return newServerMediaSubsession(dummyResultTrackNumber);
37}
38
39ServerMediaSubsession* MatroskaFileServerDemux
40::newServerMediaSubsession(unsigned& resultTrackNumber) {
41 ServerMediaSubsession* result;
42 resultTrackNumber = 0;
43
44 for (result = NULL; result == NULL && fNextTrackTypeToCheck != MATROSKA_TRACK_TYPE_OTHER; fNextTrackTypeToCheck <<= 1) {
45 if (fNextTrackTypeToCheck == MATROSKA_TRACK_TYPE_VIDEO) resultTrackNumber = fOurMatroskaFile->chosenVideoTrackNumber();
46 else if (fNextTrackTypeToCheck == MATROSKA_TRACK_TYPE_AUDIO) resultTrackNumber = fOurMatroskaFile->chosenAudioTrackNumber();
47 else if (fNextTrackTypeToCheck == MATROSKA_TRACK_TYPE_SUBTITLE) resultTrackNumber = fOurMatroskaFile->chosenSubtitleTrackNumber();
48
49 result = newServerMediaSubsessionByTrackNumber(resultTrackNumber);
50 }
51
52 return result;
53}
54
55ServerMediaSubsession* MatroskaFileServerDemux
56::newServerMediaSubsessionByTrackNumber(unsigned trackNumber) {
57 MatroskaTrack* track = fOurMatroskaFile->lookup(trackNumber);
58 if (track == NULL) return NULL;
59
60 // Use the track's "codecID" string to figure out which "ServerMediaSubsession" subclass to use:
61 ServerMediaSubsession* result = NULL;
62 if (strcmp(track->mimeType, "audio/MPEG") == 0) {
63 result = MP3AudioMatroskaFileServerMediaSubsession::createNew(*this, track);
64 } else {
65 result = MatroskaFileServerMediaSubsession::createNew(*this, track);
66 }
67
68 if (result != NULL) {
69#ifdef DEBUG
70 fprintf(stderr, "Created 'ServerMediaSubsession' object for track #%d: %s (%s)\n", track->trackNumber, track->codecID, track->mimeType);
71#endif
72 }
73
74 return result;
75}
76
77FramedSource* MatroskaFileServerDemux::newDemuxedTrack(unsigned clientSessionId, unsigned trackNumber) {
78 MatroskaDemux* demuxToUse = NULL;
79
80 if (clientSessionId != 0 && clientSessionId == fLastClientSessionId) {
81 demuxToUse = fLastCreatedDemux; // use the same demultiplexor as before
82 // Note: This code relies upon the fact that the creation of streams for different
83 // client sessions do not overlap - so all demuxed tracks are created for one "MatroskaDemux" at a time.
84 // Also, the "clientSessionId != 0" test is a hack, because 'session 0' is special; its audio and video streams
85 // are created and destroyed one-at-a-time, rather than both streams being
86 // created, and then (later) both streams being destroyed (as is the case
87 // for other ('real') session ids). Because of this, a separate demultiplexor is used for each 'session 0' track.
88 }
89
90 if (demuxToUse == NULL) demuxToUse = fOurMatroskaFile->newDemux();
91
92 fLastClientSessionId = clientSessionId;
93 fLastCreatedDemux = demuxToUse;
94
95 return demuxToUse->newDemuxedTrackByTrackNumber(trackNumber);
96}
97
98MatroskaFileServerDemux
99::MatroskaFileServerDemux(UsageEnvironment& env, char const* fileName,
100 onCreationFunc* onCreation, void* onCreationClientData,
101 char const* preferredLanguage)
102 : Medium(env),
103 fFileName(fileName), fOnCreation(onCreation), fOnCreationClientData(onCreationClientData),
104 fNextTrackTypeToCheck(0x1), fLastClientSessionId(0), fLastCreatedDemux(NULL) {
105 MatroskaFile::createNew(env, fileName, onMatroskaFileCreation, this, preferredLanguage);
106}
107
108MatroskaFileServerDemux::~MatroskaFileServerDemux() {
109 Medium::close(fOurMatroskaFile);
110}
111
112void MatroskaFileServerDemux::onMatroskaFileCreation(MatroskaFile* newFile, void* clientData) {
113 ((MatroskaFileServerDemux*)clientData)->onMatroskaFileCreation(newFile);
114}
115
116void MatroskaFileServerDemux::onMatroskaFileCreation(MatroskaFile* newFile) {
117 fOurMatroskaFile = newFile;
118
119 // Now, call our own creation notification function:
120 if (fOnCreation != NULL) (*fOnCreation)(this, fOnCreationClientData);
121}
122