static TRANSPORTDEC_ERROR synchronization( HANDLE_TRANSPORTDEC hTp, INT *pHeaderBits ) { TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK, errFirstFrame = TRANSPORTDEC_OK; HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; INT syncLayerFrameBits = 0; /* Length of sync layer frame (i.e. LOAS) */ INT rawDataBlockLength = 0, rawDataBlockLengthPrevious; INT totalBits; INT headerBits = 0, headerBitsFirstFrame = 0, headerBitsPrevious; INT numFramesTraversed = 0, fTraverseMoreFrames, fConfigFound = 0, startPos, startPosFirstFrame = -1; INT numRawDataBlocksFirstFrame = 0, numRawDataBlocksPrevious, globalFramePosFirstFrame = 0, rawDataBlockLengthFirstFrame = 0; INT ignoreBufferFullness = hTp->flags & (TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK); /* Synch parameters */ INT syncLength; /* Length of sync word in bits */ UINT syncWord; /* Sync word to be found */ UINT syncMask; /* Mask for sync word (for adding one bit, so comprising one bit less) */ C_ALLOC_SCRATCH_START(contextFirstFrame, transportdec_parser_t, 1); totalBits = (INT)FDKgetValidBits(hBs); if (totalBits <= 0) { /* Return sync error, because this happens only in case of severly damaged bit streams. Returning TRANSPORTDEC_NOT_ENOUGH_BITS here is very dangerous. */ /* numberOfRawDataBlocks must be always reset in case of sync errors. */ hTp->numberOfRawDataBlocks = 0; goto bail; } fTraverseMoreFrames = (hTp->flags & (TPDEC_MINIMIZE_DELAY|TPDEC_EARLY_CONFIG)) && ! (hTp->flags & TPDEC_SYNCOK); /* Set transport specific sync parameters */ switch (hTp->transportFmt) { case TT_MP4_ADTS: syncWord = ADTS_SYNCWORD; syncLength = ADTS_SYNCLENGTH; break; case TT_MP4_LOAS: syncWord = 0x2B7; syncLength = 11; break; default: syncWord = 0; syncLength = 0; break; } syncMask = (1<<syncLength)-1; do { INT bitsAvail = 0; /* Bits available in bitstream buffer */ INT checkLengthBits; /* Helper to check remaining bits and buffer boundaries */ UINT synch; /* Current sync word read from bitstream */ headerBitsPrevious = headerBits; bitsAvail = (INT)FDKgetValidBits(hBs); if (hTp->numberOfRawDataBlocks == 0) { /* search synchword */ FDK_ASSERT( (bitsAvail % TPDEC_SYNCSKIP) == 0); if ((bitsAvail-syncLength) < TPDEC_SYNCSKIP) { err = TRANSPORTDEC_NOT_ENOUGH_BITS; headerBits = 0; } else { synch = FDKreadBits(hBs, syncLength); if ( !(hTp->flags & TPDEC_SYNCOK) ) { for (; (bitsAvail-syncLength) >= TPDEC_SYNCSKIP; bitsAvail-=TPDEC_SYNCSKIP) { if (synch == syncWord) { break; } synch = ((synch << TPDEC_SYNCSKIP) & syncMask) | FDKreadBits(hBs, TPDEC_SYNCSKIP); } } if (synch != syncWord) { /* No correct syncword found. */ err = TRANSPORTDEC_SYNC_ERROR; } else { err = TRANSPORTDEC_OK; } headerBits = syncLength; } } else { headerBits = 0; } /* Save previous raw data block data */ rawDataBlockLengthPrevious = rawDataBlockLength; numRawDataBlocksPrevious = hTp->numberOfRawDataBlocks; /* Parse transport header (raw data block granularity) */ startPos = FDKgetValidBits(hBs); if (err == TRANSPORTDEC_OK ) { switch (hTp->transportFmt) { case TT_MP4_ADTS: if (hTp->numberOfRawDataBlocks <= 0) { int errC; /* Parse ADTS header */ err = adtsRead_DecodeHeader( &hTp->parser.adts, &hTp->asc[0], hBs, ignoreBufferFullness ); if (err != TRANSPORTDEC_OK) { if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { err = TRANSPORTDEC_SYNC_ERROR; } } else { errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]); if (errC != 0) { err = TRANSPORTDEC_SYNC_ERROR; } else { hTp->numberOfRawDataBlocks = hTp->parser.adts.bs.num_raw_blocks+1; /* CAUTION: The PCE (if available) is declared to be a part of the header! */ hTp->globalFramePos = FDKgetValidBits(hBs) + hTp->parser.adts.bs.num_pce_bits; } } } else { /* Reset CRC because the next bits are the beginning of a raw_data_block() */ FDKcrcReset(&hTp->parser.adts.crcInfo); hTp->globalFramePos = FDKgetValidBits(hBs); } if (err == TRANSPORTDEC_OK) { hTp->numberOfRawDataBlocks--; rawDataBlockLength = adtsRead_GetRawDataBlockLength(&hTp->parser.adts, (hTp->parser.adts.bs.num_raw_blocks-hTp->numberOfRawDataBlocks)); syncLayerFrameBits = (hTp->parser.adts.bs.frame_length<<3) - (startPos - FDKgetValidBits(hBs)) - syncLength; if (syncLayerFrameBits <= 0) { err = TRANSPORTDEC_SYNC_ERROR; } } else { hTp->numberOfRawDataBlocks = 0; } break; case TT_MP4_LOAS: if (hTp->numberOfRawDataBlocks <= 0) { syncLayerFrameBits = FDKreadBits(hBs, 13); hTp->parser.latm.m_audioMuxLengthBytes = syncLayerFrameBits; syncLayerFrameBits <<= 3; } case TT_MP4_LATM_MCP1: case TT_MP4_LATM_MCP0: if (hTp->numberOfRawDataBlocks <= 0) { hTp->globalFramePos = FDKgetValidBits(hBs); err = CLatmDemux_Read( hBs, &hTp->parser.latm, hTp->transportFmt, &hTp->callbacks, hTp->asc, ignoreBufferFullness); if (err != TRANSPORTDEC_OK) { if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { err = TRANSPORTDEC_SYNC_ERROR; } } else { hTp->numberOfRawDataBlocks = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); syncLayerFrameBits -= startPos - FDKgetValidBits(hBs) - (13); } } else { err = CLatmDemux_ReadPayloadLengthInfo(hBs, &hTp->parser.latm); if (err != TRANSPORTDEC_OK) { err = TRANSPORTDEC_SYNC_ERROR; } } if (err == TRANSPORTDEC_OK) { rawDataBlockLength = CLatmDemux_GetFrameLengthInBits(&hTp->parser.latm); hTp->numberOfRawDataBlocks--; } else { hTp->numberOfRawDataBlocks = 0; } break; default: { syncLayerFrameBits = 0; } break; } } headerBits += startPos - (INT)FDKgetValidBits(hBs); bitsAvail -= headerBits; checkLengthBits = syncLayerFrameBits; /* Check if the whole frame would fit the bitstream buffer */ if (err == TRANSPORTDEC_OK) { if ( (checkLengthBits+headerBits) > ((TRANSPORTDEC_INBUF_SIZE<<3)-7) ) { /* We assume that the size of the transport bit buffer has been chosen to meet all system requirements, thus this condition is considered a synchronisation error. */ err = TRANSPORTDEC_SYNC_ERROR; } else { if ( bitsAvail < checkLengthBits ) { err = TRANSPORTDEC_NOT_ENOUGH_BITS; } } } if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { break; } if (err == TRANSPORTDEC_SYNC_ERROR) { int bits; /* Enforce re-sync of transport headers. */ hTp->numberOfRawDataBlocks = 0; /* Ensure that the bit amount lands and a multiple of TPDEC_SYNCSKIP */ bits = (bitsAvail + headerBits) % TPDEC_SYNCSKIP; /* Rewind - TPDEC_SYNCSKIP, in order to look for a synch one bit ahead next time. */ FDKpushBiDirectional(hBs, -(headerBits - TPDEC_SYNCSKIP) + bits); bitsAvail += headerBits - TPDEC_SYNCSKIP - bits; headerBits = 0; } /* Frame traversal */ if ( fTraverseMoreFrames ) { /* Save parser context for early config discovery "rewind all frames" */ if ( (hTp->flags & TPDEC_EARLY_CONFIG) && !(hTp->flags & TPDEC_MINIMIZE_DELAY)) { /* ignore buffer fullness if just traversing additional frames for ECD */ ignoreBufferFullness = 1; /* Save context in order to return later */ if ( err == TRANSPORTDEC_OK && startPosFirstFrame == -1 ) { startPosFirstFrame = FDKgetValidBits(hBs); numRawDataBlocksFirstFrame = hTp->numberOfRawDataBlocks; globalFramePosFirstFrame = hTp->globalFramePos; rawDataBlockLengthFirstFrame = rawDataBlockLength; headerBitsFirstFrame = headerBits; errFirstFrame = err; FDKmemcpy(contextFirstFrame, &hTp->parser, sizeof(transportdec_parser_t)); } /* Break when config was found or it is not possible anymore to find a config */ if (startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK)) { break; } } if (err == TRANSPORTDEC_OK) { FDKpushFor(hBs, rawDataBlockLength); bitsAvail -= rawDataBlockLength; numFramesTraversed++; /* Ignore error here itentionally. */ transportDec_AdjustEndOfAccessUnit(hTp); } } } while ( fTraverseMoreFrames || (err == TRANSPORTDEC_SYNC_ERROR && !(hTp->flags & TPDEC_SYNCOK))); /* Restore context in case of ECD frame traversal */ if ( startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK) ) { FDKpushBiDirectional(hBs, FDKgetValidBits(hBs) - startPosFirstFrame); FDKmemcpy(&hTp->parser, contextFirstFrame, sizeof(transportdec_parser_t)); hTp->numberOfRawDataBlocks = numRawDataBlocksFirstFrame; hTp->globalFramePos = globalFramePosFirstFrame; rawDataBlockLength = rawDataBlockLengthFirstFrame; headerBits = headerBitsFirstFrame; err = errFirstFrame; numFramesTraversed = 0; } /* Additional burst data mode buffer fullness check. */ if ( !(hTp->flags & (TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK)) && err == TRANSPORTDEC_OK) { err = additionalHoldOffNeeded(hTp, transportDec_GetBufferFullness(hTp), FDKgetValidBits(hBs) - syncLayerFrameBits); if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { hTp->holdOffFrames++; } } /* Rewind for retry because of not enough bits */ if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { FDKpushBack(hBs, headerBits); headerBits = 0; } else { /* reset hold off frame counter */ hTp->holdOffFrames = 0; } /* Return to last good frame in case of frame traversal but not ECD. */ if (numFramesTraversed > 0) { FDKpushBack(hBs, rawDataBlockLengthPrevious); if (err != TRANSPORTDEC_OK) { hTp->numberOfRawDataBlocks = numRawDataBlocksPrevious; headerBits = headerBitsPrevious; } err = TRANSPORTDEC_OK; } bail: hTp->auLength[0] = rawDataBlockLength; if (err == TRANSPORTDEC_OK) { hTp->flags |= TPDEC_SYNCOK; } if (pHeaderBits != NULL) { *pHeaderBits = headerBits; } if (err == TRANSPORTDEC_SYNC_ERROR) { hTp->flags &= ~TPDEC_SYNCOK; } C_ALLOC_SCRATCH_END(contextFirstFrame, transportdec_parser_t, 1); return err; }
static TRANSPORTDEC_ERROR transportDec_readHeader( HANDLE_TRANSPORTDEC hTp, HANDLE_FDK_BITSTREAM hBs, int syncLength, int ignoreBufferFullness, int *pRawDataBlockLength, int *pfTraverseMoreFrames, int *pSyncLayerFrameBits, int *pfConfigFound, int *pHeaderBits ) { TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; int rawDataBlockLength = *pRawDataBlockLength; int fTraverseMoreFrames = (pfTraverseMoreFrames != NULL) ? *pfTraverseMoreFrames : 0; int syncLayerFrameBits = (pSyncLayerFrameBits != NULL) ? *pSyncLayerFrameBits : 0; int fConfigFound = (pfConfigFound != NULL) ? *pfConfigFound : 0; int startPos; startPos = FDKgetValidBits(hBs); switch (hTp->transportFmt) { case TT_MP4_ADTS: if (hTp->numberOfRawDataBlocks <= 0) { int errC; hTp->globalFramePos = FDKgetValidBits(hBs); /* Parse ADTS header */ err = adtsRead_DecodeHeader( &hTp->parser.adts, &hTp->asc[0], hBs, ignoreBufferFullness ); if (err != TRANSPORTDEC_OK) { if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { err = TRANSPORTDEC_SYNC_ERROR; } } else { errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]); if (errC != 0) { if (errC == TRANSPORTDEC_NEED_TO_RESTART) { err = TRANSPORTDEC_NEED_TO_RESTART; goto bail; } else { err = TRANSPORTDEC_SYNC_ERROR; } } else { fConfigFound = 1; hTp->numberOfRawDataBlocks = hTp->parser.adts.bs.num_raw_blocks+1; } } } else { /* Reset CRC because the next bits are the beginning of a raw_data_block() */ FDKcrcReset(&hTp->parser.adts.crcInfo); hTp->parser.adts.bs.num_pce_bits = 0; } if (err == TRANSPORTDEC_OK) { hTp->numberOfRawDataBlocks--; rawDataBlockLength = adtsRead_GetRawDataBlockLength(&hTp->parser.adts, (hTp->parser.adts.bs.num_raw_blocks-hTp->numberOfRawDataBlocks)); if (rawDataBlockLength <= 0) { /* No further frame traversal possible. */ fTraverseMoreFrames = 0; } syncLayerFrameBits = (hTp->parser.adts.bs.frame_length<<3) - (startPos - FDKgetValidBits(hBs)) - syncLength; if (syncLayerFrameBits <= 0) { err = TRANSPORTDEC_SYNC_ERROR; } } else { hTp->numberOfRawDataBlocks = 0; } break; case TT_MP4_LOAS: if (hTp->numberOfRawDataBlocks <= 0) { syncLayerFrameBits = FDKreadBits(hBs, 13); hTp->parser.latm.m_audioMuxLengthBytes = syncLayerFrameBits; syncLayerFrameBits <<= 3; } case TT_MP4_LATM_MCP1: case TT_MP4_LATM_MCP0: if (hTp->numberOfRawDataBlocks <= 0) { hTp->globalFramePos = FDKgetValidBits(hBs); err = CLatmDemux_Read( hBs, &hTp->parser.latm, hTp->transportFmt, &hTp->callbacks, hTp->asc, &fConfigFound, ignoreBufferFullness); if (err != TRANSPORTDEC_OK) { if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { err = TRANSPORTDEC_SYNC_ERROR; } } else { hTp->numberOfRawDataBlocks = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); if (hTp->transportFmt == TT_MP4_LOAS) { syncLayerFrameBits -= startPos - FDKgetValidBits(hBs) - (13); } } } else { err = CLatmDemux_ReadPayloadLengthInfo(hBs, &hTp->parser.latm); if (err != TRANSPORTDEC_OK) { err = TRANSPORTDEC_SYNC_ERROR; } } if (err == TRANSPORTDEC_OK) { rawDataBlockLength = CLatmDemux_GetFrameLengthInBits(&hTp->parser.latm); hTp->numberOfRawDataBlocks--; } else { hTp->numberOfRawDataBlocks = 0; } break; default: { syncLayerFrameBits = 0; } break; } bail: *pRawDataBlockLength = rawDataBlockLength; if (pHeaderBits != NULL) { *pHeaderBits += startPos - (INT)FDKgetValidBits(hBs); } if (pfConfigFound != NULL) { *pfConfigFound = fConfigFound; } if (pfTraverseMoreFrames != NULL) { *pfTraverseMoreFrames = fTraverseMoreFrames; } if (pSyncLayerFrameBits != NULL) { *pSyncLayerFrameBits = syncLayerFrameBits; } if (pfConfigFound != NULL) { *pfConfigFound = fConfigFound; } return err; }