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 | // 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 | |
32 | Interleaving::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 | |
40 | Interleaving::~Interleaving() { |
41 | } |
42 | |
43 | ////////// MP3ADUinterleaverBase ////////// |
44 | |
45 | MP3ADUinterleaverBase::MP3ADUinterleaverBase(UsageEnvironment& env, |
46 | FramedSource* inputSource) |
47 | : FramedFilter(env, inputSource) { |
48 | } |
49 | MP3ADUinterleaverBase::~MP3ADUinterleaverBase() { |
50 | } |
51 | |
52 | FramedSource* 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 | |
66 | void 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 | |
83 | class InterleavingFrames { |
84 | public: |
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 | |
104 | private: |
105 | unsigned fMaxCycleSize; |
106 | unsigned fNextIndexToRelease; |
107 | class InterleavingFrameDescriptor* fDescriptors; |
108 | }; |
109 | |
110 | ////////// MP3ADUinterleaver ////////// |
111 | |
112 | |
113 | MP3ADUinterleaver::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 | |
122 | MP3ADUinterleaver::~MP3ADUinterleaver() { |
123 | delete fFrames; |
124 | } |
125 | |
126 | MP3ADUinterleaver* MP3ADUinterleaver::createNew(UsageEnvironment& env, |
127 | Interleaving const& interleaving, |
128 | FramedSource* inputSource) { |
129 | return new MP3ADUinterleaver(env, interleaving, inputSource); |
130 | } |
131 | |
132 | void 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 | |
155 | void 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 | |
170 | void 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 | |
187 | class DeinterleavingFrames { |
188 | public: |
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 | |
207 | private: |
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 | |
217 | MP3ADUdeinterleaver::MP3ADUdeinterleaver(UsageEnvironment& env, |
218 | FramedSource* inputSource) |
219 | : MP3ADUinterleaverBase(env, inputSource), |
220 | fFrames(new DeinterleavingFrames), |
221 | fIIlastSeen(~0), fICClastSeen(~0) { |
222 | } |
223 | |
224 | MP3ADUdeinterleaver::~MP3ADUdeinterleaver() { |
225 | delete fFrames; |
226 | } |
227 | |
228 | MP3ADUdeinterleaver* MP3ADUdeinterleaver::createNew(UsageEnvironment& env, |
229 | FramedSource* inputSource) { |
230 | return new MP3ADUdeinterleaver(env, inputSource); |
231 | } |
232 | |
233 | void 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 | |
280 | void 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 | |
305 | void 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 | |
323 | class InterleavingFrameDescriptor { |
324 | public: |
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 | |
333 | InterleavingFrames::InterleavingFrames(unsigned maxCycleSize) |
334 | : fMaxCycleSize(maxCycleSize), fNextIndexToRelease(0), |
335 | fDescriptors(new InterleavingFrameDescriptor[maxCycleSize]) { |
336 | } |
337 | InterleavingFrames::~InterleavingFrames() { |
338 | delete[] fDescriptors; |
339 | } |
340 | |
341 | Boolean InterleavingFrames::haveReleaseableFrame() { |
342 | return fDescriptors[fNextIndexToRelease].frameDataSize > 0; |
343 | } |
344 | |
345 | void 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 | |
353 | void 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 | |
365 | void 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 | |
386 | void InterleavingFrames::releaseNext() { |
387 | fDescriptors[fNextIndexToRelease].frameDataSize = 0; |
388 | fNextIndexToRelease = (fNextIndexToRelease+1)%fMaxCycleSize; |
389 | } |
390 | |
391 | ////////// DeinterleavingFrames (implementation) ////////// |
392 | |
393 | class DeinterleavingFrameDescriptor { |
394 | public: |
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 | |
404 | DeinterleavingFrames::DeinterleavingFrames() |
405 | : fNextIndexToRelease(0), fHaveEndedCycle(False), |
406 | fMinIndexSeen(MAX_CYCLE_SIZE), fMaxIndexSeen(0), |
407 | fDescriptors(new DeinterleavingFrameDescriptor[MAX_CYCLE_SIZE+1]) { |
408 | } |
409 | DeinterleavingFrames::~DeinterleavingFrames() { |
410 | delete[] fDescriptors; |
411 | } |
412 | |
413 | Boolean 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 | |
447 | void 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 | |
460 | void 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 | |
479 | void 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 | |
490 | void 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 | |
510 | void DeinterleavingFrames::releaseNext() { |
511 | fDescriptors[fNextIndexToRelease].frameDataSize = 0; |
512 | fNextIndexToRelease = (fNextIndexToRelease+1)%MAX_CYCLE_SIZE; |
513 | } |
514 | |
515 | void DeinterleavingFrames::startNewCycle() { |
516 | fHaveEndedCycle = True; |
517 | } |
518 | |