| 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 |  | 
|---|