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// Interleaving of MP3 ADUs
19// Implementation
20
21#include "MP3ADUinterleaving.hh"
22#include "MP3ADUdescriptor.hh"
23
24#include <string.h>
25
26#ifdef TEST_LOSS
27#include "GroupsockHelper.hh"
28#endif
29
30////////// Interleaving //////////
31
32Interleaving::Interleaving(unsigned cycleSize,
33 unsigned char const* cycleArray)
34 : fCycleSize(cycleSize) {
35 for (unsigned i = 0; i < fCycleSize; ++i) {
36 fInverseCycle[cycleArray[i]] = i;
37 }
38}
39
40Interleaving::~Interleaving() {
41}
42
43////////// MP3ADUinterleaverBase //////////
44
45MP3ADUinterleaverBase::MP3ADUinterleaverBase(UsageEnvironment& env,
46 FramedSource* inputSource)
47 : FramedFilter(env, inputSource) {
48}
49MP3ADUinterleaverBase::~MP3ADUinterleaverBase() {
50}
51
52FramedSource* MP3ADUinterleaverBase::getInputSource(UsageEnvironment& env,
53 char const* inputSourceName) {
54 FramedSource* inputSource;
55 if (!FramedSource::lookupByName(env, inputSourceName, inputSource))
56 return NULL;
57
58 if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) {
59 env.setResultMsg(inputSourceName, " is not an MP3 ADU source");
60 return NULL;
61 }
62
63 return inputSource;
64}
65
66void MP3ADUinterleaverBase::afterGettingFrame(void* clientData,
67 unsigned numBytesRead,
68 unsigned /*numTruncatedBytes*/,
69 struct timeval presentationTime,
70 unsigned durationInMicroseconds) {
71 MP3ADUinterleaverBase* interleaverBase = (MP3ADUinterleaverBase*)clientData;
72 // Finish up after reading:
73 interleaverBase->afterGettingFrame(numBytesRead,
74 presentationTime, durationInMicroseconds);
75
76 // Then, continue to deliver an outgoing frame:
77 interleaverBase->doGetNextFrame();
78}
79
80
81////////// InterleavingFrames (definition) //////////
82
83class InterleavingFrames {
84public:
85 InterleavingFrames(unsigned maxCycleSize);
86 virtual ~InterleavingFrames();
87
88 Boolean haveReleaseableFrame();
89 void getIncomingFrameParams(unsigned char index,
90 unsigned char*& dataPtr,
91 unsigned& bytesAvailable);
92 void getReleasingFrameParams(unsigned char index,
93 unsigned char*& dataPtr,
94 unsigned& bytesInUse,
95 struct timeval& presentationTime,
96 unsigned& durationInMicroseconds);
97 void setFrameParams(unsigned char index,
98 unsigned char icc, unsigned char ii,
99 unsigned frameSize, struct timeval presentationTime,
100 unsigned durationInMicroseconds);
101 unsigned nextIndexToRelease() {return fNextIndexToRelease;}
102 void releaseNext();
103
104private:
105 unsigned fMaxCycleSize;
106 unsigned fNextIndexToRelease;
107 class InterleavingFrameDescriptor* fDescriptors;
108};
109
110////////// MP3ADUinterleaver //////////
111
112
113MP3ADUinterleaver::MP3ADUinterleaver(UsageEnvironment& env,
114 Interleaving const& interleaving,
115 FramedSource* inputSource)
116 : MP3ADUinterleaverBase(env, inputSource),
117 fInterleaving(interleaving),
118 fFrames(new InterleavingFrames(interleaving.cycleSize())),
119 fII(0), fICC(0) {
120}
121
122MP3ADUinterleaver::~MP3ADUinterleaver() {
123 delete fFrames;
124}
125
126MP3ADUinterleaver* MP3ADUinterleaver::createNew(UsageEnvironment& env,
127 Interleaving const& interleaving,
128 FramedSource* inputSource) {
129 return new MP3ADUinterleaver(env, interleaving, inputSource);
130}
131
132void MP3ADUinterleaver::doGetNextFrame() {
133 // If there's a frame immediately available, deliver it, otherwise get new
134 // frames from the source until one's available:
135 if (fFrames->haveReleaseableFrame()) {
136 releaseOutgoingFrame();
137
138 // Call our own 'after getting' function. Because we're not a 'leaf'
139 // source, we can call this directly, without risking infinite recursion.
140 afterGetting(this);
141 } else {
142 fPositionOfNextIncomingFrame = fInterleaving.lookupInverseCycle(fII);
143 unsigned char* dataPtr;
144 unsigned bytesAvailable;
145 fFrames->getIncomingFrameParams(fPositionOfNextIncomingFrame,
146 dataPtr, bytesAvailable);
147
148 // Read the next incoming frame (asynchronously)
149 fInputSource->getNextFrame(dataPtr, bytesAvailable,
150 &MP3ADUinterleaverBase::afterGettingFrame, this,
151 handleClosure, this);
152 }
153}
154
155void MP3ADUinterleaver::releaseOutgoingFrame() {
156 unsigned char* fromPtr;
157 fFrames->getReleasingFrameParams(fFrames->nextIndexToRelease(),
158 fromPtr, fFrameSize,
159 fPresentationTime, fDurationInMicroseconds);
160
161 if (fFrameSize > fMaxSize) {
162 fNumTruncatedBytes = fFrameSize - fMaxSize;
163 fFrameSize = fMaxSize;
164 }
165 memmove(fTo, fromPtr, fFrameSize);
166
167 fFrames->releaseNext();
168}
169
170void MP3ADUinterleaver::afterGettingFrame(unsigned numBytesRead,
171 struct timeval presentationTime,
172 unsigned durationInMicroseconds) {
173 // Set the (icc,ii) and frame size of the newly-read frame:
174 fFrames->setFrameParams(fPositionOfNextIncomingFrame,
175 fICC, fII, numBytesRead,
176 presentationTime, durationInMicroseconds);
177
178 // Prepare our counters for the next frame:
179 if (++fII == fInterleaving.cycleSize()) {
180 fII = 0;
181 fICC = (fICC+1)%8;
182 }
183}
184
185////////// DeinterleavingFrames (definition) //////////
186
187class DeinterleavingFrames {
188public:
189 DeinterleavingFrames();
190 virtual ~DeinterleavingFrames();
191
192 Boolean haveReleaseableFrame();
193 void getIncomingFrameParams(unsigned char*& dataPtr,
194 unsigned& bytesAvailable);
195 void getIncomingFrameParamsAfter(unsigned frameSize,
196 struct timeval presentationTime,
197 unsigned durationInMicroseconds,
198 unsigned char& icc, unsigned char& ii);
199 void getReleasingFrameParams(unsigned char*& dataPtr,
200 unsigned& bytesInUse,
201 struct timeval& presentationTime,
202 unsigned& durationInMicroseconds);
203 void moveIncomingFrameIntoPlace();
204 void releaseNext();
205 void startNewCycle();
206
207private:
208 unsigned fNextIndexToRelease;
209 Boolean fHaveEndedCycle;
210 unsigned fIIlastSeen;
211 unsigned fMinIndexSeen, fMaxIndexSeen; // actually, max+1
212 class DeinterleavingFrameDescriptor* fDescriptors;
213};
214
215////////// MP3ADUdeinterleaver //////////
216
217MP3ADUdeinterleaver::MP3ADUdeinterleaver(UsageEnvironment& env,
218 FramedSource* inputSource)
219 : MP3ADUinterleaverBase(env, inputSource),
220 fFrames(new DeinterleavingFrames),
221 fIIlastSeen(~0), fICClastSeen(~0) {
222}
223
224MP3ADUdeinterleaver::~MP3ADUdeinterleaver() {
225 delete fFrames;
226}
227
228MP3ADUdeinterleaver* MP3ADUdeinterleaver::createNew(UsageEnvironment& env,
229 FramedSource* inputSource) {
230 return new MP3ADUdeinterleaver(env, inputSource);
231}
232
233void MP3ADUdeinterleaver::doGetNextFrame() {
234 // If there's a frame immediately available, deliver it, otherwise get new
235 // frames from the source until one's available:
236 if (fFrames->haveReleaseableFrame()) {
237 releaseOutgoingFrame();
238
239 // Call our own 'after getting' function. Because we're not a 'leaf'
240 // source, we can call this directly, without risking infinite recursion.
241 afterGetting(this);
242 } else {
243#ifdef TEST_LOSS
244 NOTE: This code no longer works, because it uses synchronous reads,
245 which are no longer supported.
246 static unsigned const framesPerPacket = 3;
247 static unsigned const frameCount = 0;
248 static Boolean packetIsLost;
249 while (1) {
250 unsigned packetCount = frameCount/framesPerPacket;
251 if ((frameCount++)%framesPerPacket == 0) {
252 packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss #####
253 }
254
255 if (packetIsLost) {
256 // Read and discard the next input frame (that would be part of
257 // a lost packet):
258 unsigned char dummyBuf[2000];
259 unsigned numBytesRead;
260 struct timeval presentationTime;
261 // (this works only if the source can be read synchronously)
262 fInputSource->syncGetNextFrame(dummyBuf, sizeof dummyBuf,
263 numBytesRead, presentationTime);
264 } else {
265 break; // from while (1)
266 }
267 }
268#endif
269 unsigned char* dataPtr;
270 unsigned bytesAvailable;
271 fFrames->getIncomingFrameParams(dataPtr, bytesAvailable);
272
273 // Read the next incoming frame (asynchronously)
274 fInputSource->getNextFrame(dataPtr, bytesAvailable,
275 &MP3ADUinterleaverBase::afterGettingFrame, this,
276 handleClosure, this);
277 }
278}
279
280void MP3ADUdeinterleaver::afterGettingFrame(unsigned numBytesRead,
281 struct timeval presentationTime,
282 unsigned durationInMicroseconds) {
283 // Get the (icc,ii) and set the frame size of the newly-read frame:
284 unsigned char icc, ii;
285 fFrames->getIncomingFrameParamsAfter(numBytesRead,
286 presentationTime, durationInMicroseconds,
287 icc, ii);
288
289 // Compare these to the values we saw last:
290 if (icc != fICClastSeen || ii == fIIlastSeen) {
291 // We've started a new interleave cycle
292 // (or interleaving was not used). Release all
293 // pending ADU frames to the ADU->MP3 conversion step:
294 fFrames->startNewCycle();
295 } else {
296 // We're still in the same cycle as before.
297 // Move the newly-read frame into place, so it can be used:
298 fFrames->moveIncomingFrameIntoPlace();
299 }
300
301 fICClastSeen = icc;
302 fIIlastSeen = ii;
303}
304
305void MP3ADUdeinterleaver::releaseOutgoingFrame() {
306 unsigned char* fromPtr;
307 fFrames->getReleasingFrameParams(fromPtr, fFrameSize,
308 fPresentationTime, fDurationInMicroseconds);
309
310 if (fFrameSize > fMaxSize) {
311 fNumTruncatedBytes = fFrameSize - fMaxSize;
312 fFrameSize = fMaxSize;
313 }
314 memmove(fTo, fromPtr, fFrameSize);
315
316 fFrames->releaseNext();
317}
318
319////////// InterleavingFrames (implementation) //////////
320
321#define MAX_FRAME_SIZE 2000 /* conservatively high */
322
323class InterleavingFrameDescriptor {
324public:
325 InterleavingFrameDescriptor() {frameDataSize = 0;}
326
327 unsigned frameDataSize; // includes ADU descriptor and (modified) MPEG hdr
328 struct timeval presentationTime;
329 unsigned durationInMicroseconds;
330 unsigned char frameData[MAX_FRAME_SIZE]; // ditto
331};
332
333InterleavingFrames::InterleavingFrames(unsigned maxCycleSize)
334 : fMaxCycleSize(maxCycleSize), fNextIndexToRelease(0),
335 fDescriptors(new InterleavingFrameDescriptor[maxCycleSize]) {
336}
337InterleavingFrames::~InterleavingFrames() {
338 delete[] fDescriptors;
339}
340
341Boolean InterleavingFrames::haveReleaseableFrame() {
342 return fDescriptors[fNextIndexToRelease].frameDataSize > 0;
343}
344
345void InterleavingFrames::getIncomingFrameParams(unsigned char index,
346 unsigned char*& dataPtr,
347 unsigned& bytesAvailable) {
348 InterleavingFrameDescriptor& desc = fDescriptors[index];
349 dataPtr = &desc.frameData[0];
350 bytesAvailable = MAX_FRAME_SIZE;
351}
352
353void InterleavingFrames::getReleasingFrameParams(unsigned char index,
354 unsigned char*& dataPtr,
355 unsigned& bytesInUse,
356 struct timeval& presentationTime,
357 unsigned& durationInMicroseconds) {
358 InterleavingFrameDescriptor& desc = fDescriptors[index];
359 dataPtr = &desc.frameData[0];
360 bytesInUse = desc.frameDataSize;
361 presentationTime = desc.presentationTime;
362 durationInMicroseconds = desc.durationInMicroseconds;
363}
364
365void InterleavingFrames::setFrameParams(unsigned char index,
366 unsigned char icc,
367 unsigned char ii,
368 unsigned frameSize,
369 struct timeval presentationTime,
370 unsigned durationInMicroseconds) {
371 InterleavingFrameDescriptor& desc = fDescriptors[index];
372 desc.frameDataSize = frameSize;
373 desc.presentationTime = presentationTime;
374 desc.durationInMicroseconds = durationInMicroseconds;
375
376 // Advance over the ADU descriptor, to get to the MPEG 'syncword':
377 unsigned char* ptr = &desc.frameData[0];
378 (void)ADUdescriptor::getRemainingFrameSize(ptr);
379
380 // Replace the next 11 bits with (ii,icc):
381 *ptr++ = ii;
382 *ptr &=~ 0xE0;
383 *ptr |= (icc<<5);
384}
385
386void InterleavingFrames::releaseNext() {
387 fDescriptors[fNextIndexToRelease].frameDataSize = 0;
388 fNextIndexToRelease = (fNextIndexToRelease+1)%fMaxCycleSize;
389}
390
391////////// DeinterleavingFrames (implementation) //////////
392
393class DeinterleavingFrameDescriptor {
394public:
395 DeinterleavingFrameDescriptor() {frameDataSize = 0; frameData = NULL;}
396 virtual ~DeinterleavingFrameDescriptor() {delete[] frameData;}
397
398 unsigned frameDataSize; // includes ADU descriptor and (modified) MPEG hdr
399 struct timeval presentationTime;
400 unsigned durationInMicroseconds;
401 unsigned char* frameData;
402};
403
404DeinterleavingFrames::DeinterleavingFrames()
405 : fNextIndexToRelease(0), fHaveEndedCycle(False),
406 fMinIndexSeen(MAX_CYCLE_SIZE), fMaxIndexSeen(0),
407 fDescriptors(new DeinterleavingFrameDescriptor[MAX_CYCLE_SIZE+1]) {
408}
409DeinterleavingFrames::~DeinterleavingFrames() {
410 delete[] fDescriptors;
411}
412
413Boolean DeinterleavingFrames::haveReleaseableFrame() {
414 if (!fHaveEndedCycle) {
415 // Check just the next frame in the sequence
416 return fDescriptors[fNextIndexToRelease].frameDataSize > 0;
417 } else {
418 // We've just ended a cycle, so we can skip over frames that didn't
419 // get filled in (due to packet loss):
420 if (fNextIndexToRelease < fMinIndexSeen) {
421 fNextIndexToRelease = fMinIndexSeen;
422 }
423 while (fNextIndexToRelease < fMaxIndexSeen
424 && fDescriptors[fNextIndexToRelease].frameDataSize == 0) {
425 ++fNextIndexToRelease;
426 }
427 if (fNextIndexToRelease >= fMaxIndexSeen) {
428 // No more frames are available from the cycle that we just ended, so
429 // clear out all previously stored frames, then make available
430 // the last-read frame, and return false for now:
431 for (unsigned i = fMinIndexSeen; i < fMaxIndexSeen; ++i) {
432 fDescriptors[i].frameDataSize = 0;
433 }
434
435 fMinIndexSeen = MAX_CYCLE_SIZE; fMaxIndexSeen = 0;
436 moveIncomingFrameIntoPlace();
437
438 fHaveEndedCycle = False;
439 fNextIndexToRelease = 0;
440 return False;
441 }
442
443 return True;
444 }
445}
446
447void DeinterleavingFrames::getIncomingFrameParams(unsigned char*& dataPtr,
448 unsigned& bytesAvailable) {
449 // Use fDescriptors[MAX_CYCLE_SIZE] to store the incoming frame,
450 // prior to figuring out its real position:
451 DeinterleavingFrameDescriptor& desc = fDescriptors[MAX_CYCLE_SIZE];
452 if (desc.frameData == NULL) {
453 // There's no buffer yet, so allocate a new one:
454 desc.frameData = new unsigned char[MAX_FRAME_SIZE];
455 }
456 dataPtr = desc.frameData;
457 bytesAvailable = MAX_FRAME_SIZE;
458}
459
460void DeinterleavingFrames
461::getIncomingFrameParamsAfter(unsigned frameSize,
462 struct timeval presentationTime,
463 unsigned durationInMicroseconds,
464 unsigned char& icc, unsigned char& ii) {
465 DeinterleavingFrameDescriptor& desc = fDescriptors[MAX_CYCLE_SIZE];
466 desc.frameDataSize = frameSize;
467 desc.presentationTime = presentationTime;
468 desc.durationInMicroseconds = durationInMicroseconds;
469
470 // Advance over the ADU descriptor, to get to the MPEG 'syncword':
471 unsigned char* ptr = desc.frameData;
472 (void)ADUdescriptor::getRemainingFrameSize(ptr);
473
474 // Read the next 11 bits into (ii,icc), and replace them with all-1s:
475 fIIlastSeen = ii = *ptr; *ptr++ = 0xFF;
476 icc = (*ptr&0xE0)>>5; *ptr |= 0xE0;
477}
478
479void DeinterleavingFrames::getReleasingFrameParams(unsigned char*& dataPtr,
480 unsigned& bytesInUse,
481 struct timeval& presentationTime,
482 unsigned& durationInMicroseconds) {
483 DeinterleavingFrameDescriptor& desc = fDescriptors[fNextIndexToRelease];
484 dataPtr = desc.frameData;
485 bytesInUse = desc.frameDataSize;
486 presentationTime = desc.presentationTime;
487 durationInMicroseconds = desc.durationInMicroseconds;
488}
489
490void DeinterleavingFrames::moveIncomingFrameIntoPlace() {
491 DeinterleavingFrameDescriptor& fromDesc = fDescriptors[MAX_CYCLE_SIZE];
492 DeinterleavingFrameDescriptor& toDesc = fDescriptors[fIIlastSeen];
493
494 toDesc.frameDataSize = fromDesc.frameDataSize;
495 toDesc.presentationTime = fromDesc.presentationTime;
496
497 // Move the data pointer into place by swapping the data pointers:
498 unsigned char* tmp = toDesc.frameData;
499 toDesc.frameData = fromDesc.frameData;
500 fromDesc.frameData = tmp;
501
502 if (fIIlastSeen < fMinIndexSeen) {
503 fMinIndexSeen = fIIlastSeen;
504 }
505 if (fIIlastSeen + 1 > fMaxIndexSeen) {
506 fMaxIndexSeen = fIIlastSeen + 1;
507 }
508}
509
510void DeinterleavingFrames::releaseNext() {
511 fDescriptors[fNextIndexToRelease].frameDataSize = 0;
512 fNextIndexToRelease = (fNextIndexToRelease+1)%MAX_CYCLE_SIZE;
513}
514
515void DeinterleavingFrames::startNewCycle() {
516 fHaveEndedCycle = True;
517}
518