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 source that consists of multiple byte-stream files, read sequentially.
19// (The input is an array of file names, with a terminating 'file name' of NULL.)
20// Implementation
21
22#include "ByteStreamMultiFileSource.hh"
23
24ByteStreamMultiFileSource
25::ByteStreamMultiFileSource(UsageEnvironment& env, char const** fileNameArray,
26 unsigned preferredFrameSize, unsigned playTimePerFrame)
27 : FramedSource(env),
28 fPreferredFrameSize(preferredFrameSize), fPlayTimePerFrame(playTimePerFrame),
29 fCurrentlyReadSourceNumber(0), fHaveStartedNewFile(False) {
30 // Begin by counting the number of sources (by looking for a terminating 'file name' of NULL):
31 for (fNumSources = 0; ; ++fNumSources) {
32 if (fileNameArray[fNumSources] == NULL) break;
33 }
34
35 // Next, copy the source file names into our own array:
36 fFileNameArray = new char const*[fNumSources];
37 if (fFileNameArray == NULL) return;
38 unsigned i;
39 for (i = 0; i < fNumSources; ++i) {
40 fFileNameArray[i] = strDup(fileNameArray[i]);
41 }
42
43 // Next, set up our array of component ByteStreamFileSources
44 // Don't actually create these yet; instead, do this on demand
45 fSourceArray = new ByteStreamFileSource*[fNumSources];
46 if (fSourceArray == NULL) return;
47 for (i = 0; i < fNumSources; ++i) {
48 fSourceArray[i] = NULL;
49 }
50}
51
52ByteStreamMultiFileSource::~ByteStreamMultiFileSource() {
53 unsigned i;
54 for (i = 0; i < fNumSources; ++i) {
55 Medium::close(fSourceArray[i]);
56 }
57 delete[] fSourceArray;
58
59 for (i = 0; i < fNumSources; ++i) {
60 delete[] (char*)(fFileNameArray[i]);
61 }
62 delete[] fFileNameArray;
63}
64
65ByteStreamMultiFileSource* ByteStreamMultiFileSource
66::createNew(UsageEnvironment& env, char const** fileNameArray,
67 unsigned preferredFrameSize, unsigned playTimePerFrame) {
68 ByteStreamMultiFileSource* newSource
69 = new ByteStreamMultiFileSource(env, fileNameArray,
70 preferredFrameSize, playTimePerFrame);
71
72 return newSource;
73}
74
75void ByteStreamMultiFileSource::doGetNextFrame() {
76 do {
77 // First, check whether we've run out of sources:
78 if (fCurrentlyReadSourceNumber >= fNumSources) break;
79
80 fHaveStartedNewFile = False;
81 ByteStreamFileSource*& source
82 = fSourceArray[fCurrentlyReadSourceNumber];
83 if (source == NULL) {
84 // The current source hasn't been created yet. Do this now:
85 source = ByteStreamFileSource::createNew(envir(),
86 fFileNameArray[fCurrentlyReadSourceNumber],
87 fPreferredFrameSize, fPlayTimePerFrame);
88 if (source == NULL) break;
89 fHaveStartedNewFile = True;
90 }
91
92 // (Attempt to) read from the current source.
93 source->getNextFrame(fTo, fMaxSize,
94 afterGettingFrame, this,
95 onSourceClosure, this);
96 return;
97 } while (0);
98
99 // An error occurred; consider ourselves closed:
100 handleClosure();
101}
102
103void ByteStreamMultiFileSource
104 ::afterGettingFrame(void* clientData,
105 unsigned frameSize, unsigned numTruncatedBytes,
106 struct timeval presentationTime,
107 unsigned durationInMicroseconds) {
108 ByteStreamMultiFileSource* source
109 = (ByteStreamMultiFileSource*)clientData;
110 source->fFrameSize = frameSize;
111 source->fNumTruncatedBytes = numTruncatedBytes;
112 source->fPresentationTime = presentationTime;
113 source->fDurationInMicroseconds = durationInMicroseconds;
114 FramedSource::afterGetting(source);
115}
116
117void ByteStreamMultiFileSource::onSourceClosure(void* clientData) {
118 ByteStreamMultiFileSource* source
119 = (ByteStreamMultiFileSource*)clientData;
120 source->onSourceClosure1();
121}
122
123void ByteStreamMultiFileSource::onSourceClosure1() {
124 // This routine was called because the currently-read source was closed
125 // (probably due to EOF). Close this source down, and move to the
126 // next one:
127 ByteStreamFileSource*& source
128 = fSourceArray[fCurrentlyReadSourceNumber++];
129 Medium::close(source);
130 source = NULL;
131
132 // Try reading again:
133 doGetNextFrame();
134}
135