/*!
  \brief   crc interface
  \return  1: CRC OK, 0: CRC check failure
*/
int SbrCrcCheck(HANDLE_FDK_BITSTREAM hBs, /*!< handle to bit-buffer  */
                LONG NrBits)              /*!< max. CRC length       */
{
  int crcResult = 1;
  ULONG NrCrcBits;
  ULONG crcCheckResult;
  LONG NrBitsAvailable;
  ULONG crcCheckSum;

  crcCheckSum = FDKreadBits(hBs, 10);

  NrBitsAvailable = FDKgetValidBits(hBs);
  if (NrBitsAvailable <= 0) {
    return 0;
  }

  NrCrcBits = fixMin((INT)NrBits, (INT)NrBitsAvailable);

  crcCheckResult = getCrc(hBs, NrCrcBits);
  FDKpushBack(hBs, (NrBitsAvailable - FDKgetValidBits(hBs)));

  if (crcCheckResult != crcCheckSum) {
    crcResult = 0;
  }

  return (crcResult);
}
Exemple #2
0
/*---------------------------------------------------------------------------------------------
     description:   This function returns a bit from the bitstream according to
read direction. It is called very often, therefore it makes sense to inline it
(runtime).
-----------------------------------------------------------------------------------------------
        input:    - handle to FDK bitstream
                  - reference value marking start of bitfield
                  - pLeftStartOfSegment
                  - pRightStartOfSegment
                  - readDirection
-----------------------------------------------------------------------------------------------
        return:   - bit from bitstream
--------------------------------------------------------------------------------------------
*/
UINT HcrGetABitFromBitstream(HANDLE_FDK_BITSTREAM bs, const INT bsAnchor,
                             INT *pLeftStartOfSegment,
                             INT *pRightStartOfSegment, UCHAR readDirection) {
  UINT bit;
  INT readBitOffset;

  if (readDirection == FROM_LEFT_TO_RIGHT) {
    readBitOffset = (INT)FDKgetValidBits(bs) - bsAnchor + *pLeftStartOfSegment;
    if (readBitOffset) {
      FDKpushBiDirectional(bs, readBitOffset);
    }

    bit = FDKreadBits(bs, 1);

    *pLeftStartOfSegment += 1;
  } else {
    readBitOffset = (INT)FDKgetValidBits(bs) - bsAnchor + *pRightStartOfSegment;
    if (readBitOffset) {
      FDKpushBiDirectional(bs, readBitOffset);
    }

    /* to be replaced with a brother function of FDKreadBits() */
    bit = FDKreadBits(bs, 1);
    FDKpushBack(bs, 2);

    *pRightStartOfSegment -= 1;
  }

  return (bit);
}
UCHAR rvlcReadBitFromBitstream (HANDLE_FDK_BITSTREAM  bs,
                                USHORT               *pPosition,
                                UCHAR                 readDirection)
{
  UINT   bit;
  INT    readBitOffset = *pPosition-FDKgetBitCnt(bs);

  if( readBitOffset ) {
    FDKpushBiDirectional(bs, readBitOffset);
  }

  if (readDirection == FWD) {
    bit = FDKreadBits(bs, 1);

    *pPosition += 1;
  } else {
    /* to be replaced with a brother function of FDKreadBits() */
    bit = FDKreadBits(bs, 1);
    FDKpushBack(bs, 2);

    *pPosition -= 1;
  }

  return (bit);
}
Exemple #4
0
/*
 * Read the extension for height info.
 * return 0 if successfull or -1 if the CRC failed.
 */
static
int CProgramConfig_ReadHeightExt(
                                  CProgramConfig *pPce,
                                  HANDLE_FDK_BITSTREAM bs,
                                  int * const bytesAvailable,
                                  const UINT alignmentAnchor
                                )
{
  int err = 0;
  FDK_CRCINFO crcInfo;    /* CRC state info */
  INT crcReg;
  FDKcrcInit(&crcInfo, 0x07, 0xFF, 8);
  crcReg = FDKcrcStartReg(&crcInfo, bs, 0);
  UINT startAnchor = FDKgetValidBits(bs);

  FDK_ASSERT(pPce != NULL);
  FDK_ASSERT(bs != NULL);
  FDK_ASSERT(bytesAvailable != NULL);

  if ( (startAnchor >= 24) && (*bytesAvailable >= 3)
    && (FDKreadBits(bs,8) == PCE_HEIGHT_EXT_SYNC) )
  {
    int i;

    for (i=0; i < pPce->NumFrontChannelElements; i++)
    {
      pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    }
    for (i=0; i < pPce->NumSideChannelElements; i++)
    {
      pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    }
    for (i=0; i < pPce->NumBackChannelElements; i++)
    {
      pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    }
    FDKbyteAlign(bs, alignmentAnchor);

    FDKcrcEndReg(&crcInfo, bs, crcReg);
    if ((USHORT)FDKreadBits(bs,8) != FDKcrcGetCRC(&crcInfo)) {
      /* CRC failed */
      err = -1;
    }
  }
  else {
    /* No valid extension data found -> restore the initial bitbuffer state */
    FDKpushBack(bs, startAnchor - FDKgetValidBits(bs));
  }

  /* Always report the bytes read. */
  *bytesAvailable -= (startAnchor - FDKgetValidBits(bs)) >> 3;

  return (err);
}
INT FDKsbrEnc_CountSbrChannelPairElement(
    HANDLE_SBR_HEADER_DATA sbrHeaderData,
    HANDLE_PARAMETRIC_STEREO hParametricStereo,
    HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData,
    HANDLE_SBR_ENV_DATA sbrEnvDataLeft, HANDLE_SBR_ENV_DATA sbrEnvDataRight,
    HANDLE_COMMON_DATA cmonData, UINT sbrSyntaxFlags) {
  INT payloadBits;
  INT bitPos = FDKgetValidBits(&cmonData->sbrBitbuf);

  payloadBits = FDKsbrEnc_WriteEnvChannelPairElement(
      sbrHeaderData, hParametricStereo, sbrBitstreamData, sbrEnvDataLeft,
      sbrEnvDataRight, cmonData, sbrSyntaxFlags);

  FDKpushBack(&cmonData->sbrBitbuf,
              (FDKgetValidBits(&cmonData->sbrBitbuf) - bitPos));

  return payloadBits;
}
Exemple #6
0
/**
 * \brief Synchronize to stream and estimate the amount of missing access units due
 *        to a current synchronization error in case of constant average bit rate.
 */
static
TRANSPORTDEC_ERROR transportDec_readStream ( HANDLE_TRANSPORTDEC hTp, const UINT layer )
{

  TRANSPORTDEC_ERROR error = TRANSPORTDEC_OK;
  HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[layer];
  INT nAU = -1;
  INT headerBits;
  INT bitDistance, bfDelta;

  /* Obtain distance to next synch word */
  bitDistance = FDKgetValidBits(hBs);
  error = synchronization(hTp, &headerBits);
  bitDistance -= FDKgetValidBits(hBs);


  FDK_ASSERT(bitDistance >= 0);

  if (error == TRANSPORTDEC_SYNC_ERROR || (hTp->flags & TPDEC_LOST_FRAMES_PENDING))
  {
    /* Check if estimating lost access units is feasible. */
    if (hTp->avgBitRate > 0 && hTp->asc[0].m_samplesPerFrame > 0 && hTp->asc[0].m_samplingFrequency > 0)
    {
      if (error == TRANSPORTDEC_OK)
      {
        int aj;

        aj = transportDec_GetBufferFullness(hTp);
        if (aj > 0) {
          bfDelta = aj;
        } else {
          bfDelta = 0;
        }
        /* sync was ok: last of a series of bad access units. */
        hTp->flags &= ~TPDEC_LOST_FRAMES_PENDING;
        /* Add up bitDistance until end of the current frame. Later we substract
           this frame from the grand total, since this current successfully synchronized
           frame should not be skipped of course; but it must be accounted into the
           bufferfulness math. */
        bitDistance += hTp->auLength[0];
      } else {
        if ( !(hTp->flags & TPDEC_LOST_FRAMES_PENDING) ) {
          /* sync not ok: one of many bad access units. */
          hTp->flags |= TPDEC_LOST_FRAMES_PENDING;
          bfDelta = - (INT)hTp->lastValidBufferFullness;
        } else {
          bfDelta = 0;
        }
      }

      {
        int num, denom;

        /* Obtain estimate of number of lost frames */
        num = hTp->asc[0].m_samplingFrequency * (bfDelta + bitDistance) + hTp->remainder;
        denom = hTp->avgBitRate * hTp->asc[0].m_samplesPerFrame;
        if (num > 0) {
          nAU = num / denom;
          hTp->remainder = num % denom;
        } else {
          hTp->remainder = num;
        }

        if (error == TRANSPORTDEC_OK)
        {
          /* Final adjustment of remainder, taken -1 into account because current
             frame should not be skipped, thus substract -1 or do nothing instead
             of +1-1 accordingly. */
          if ( (denom - hTp->remainder) >= hTp->remainder ) {
            nAU--;
          }
            
          if (nAU < 0) {
            /* There was one frame too much concealed, so unfortunately we will have to skip one good frame. */
            transportDec_EndAccessUnit(hTp);
            error = synchronization(hTp, &headerBits);             
            nAU = -1;
#ifdef DEBUG
            FDKprintf("ERROR: Bufferfullness accounting failed. remainder=%d, nAU=%d\n", hTp->remainder, nAU);
#endif
          }
          hTp->remainder = 0;
          /* Enforce last missed frames to be concealed. */
          if (nAU > 0) {
            FDKpushBack(hBs, headerBits);
          }
        }
      }
    }
  }

  /* Be sure that lost frames are handled correctly. This is necessary due to some
     sync error sequences where later it turns out that there is not enough data, but
     the bits upto the sync word are discarded, thus causing a value of nAU > 0 */
  if (nAU > 0) {
    error = TRANSPORTDEC_SYNC_ERROR;
  }

  hTp->missingAccessUnits = nAU;

  return error;
}
Exemple #7
0
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;
}
Exemple #8
0
SBR_ERROR sbrDecoder_Parse(
        HANDLE_SBRDECODER self,
        HANDLE_FDK_BITSTREAM  hBs,
        int *count,
        int  bsPayLen,
        int  crcFlag,
        MP4_ELEMENT_ID prevElement,
        int elementIndex,
        int fGlobalIndependencyFlag
        )
{
  SBR_DECODER_ELEMENT   *hSbrElement;
  HANDLE_SBR_HEADER_DATA hSbrHeader;
  HANDLE_SBR_CHANNEL    *pSbrChannel;

  SBR_FRAME_DATA *hFrameDataLeft;
  SBR_FRAME_DATA *hFrameDataRight;

  SBR_ERROR errorStatus = SBRDEC_OK;
  SBR_SYNC_STATE initialSyncState;
  SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT;

  INT  startPos;
  INT  CRCLen = 0;

  int  stereo;
  int  fDoDecodeSbrData = 1;

  int lastSlot, lastHdrSlot = 0, thisHdrSlot;

  /* Remember start position of  SBR element */
  startPos = FDKgetValidBits(hBs);

  /* SBR sanity checks */
  if ( self == NULL || self->pSbrElement[elementIndex] == NULL ) {
    errorStatus = SBRDEC_NOT_INITIALIZED;
    goto bail;
  } 

  hSbrElement = self->pSbrElement[elementIndex];

  lastSlot    = (hSbrElement->useFrameSlot > 0) ? hSbrElement->useFrameSlot-1 : self->numDelayFrames;
  lastHdrSlot =  hSbrElement->useHeaderSlot[lastSlot];
  thisHdrSlot =  getHeaderSlot( hSbrElement->useFrameSlot, hSbrElement->useHeaderSlot );  /* Get a free header slot not used by frames not processed yet. */

  /* Assign the free slot to store a new header if there is one. */
  hSbrHeader = &self->sbrHeader[elementIndex][thisHdrSlot];

  pSbrChannel = hSbrElement->pSbrChannel;
  stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0;

  hFrameDataLeft  = &self->pSbrElement[elementIndex]->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot];
  hFrameDataRight = &self->pSbrElement[elementIndex]->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot];

  initialSyncState = hSbrHeader->syncState;

  /* reset PS flag; will be set after PS was found */
  self->flags &= ~SBRDEC_PS_DECODED;

  if (hSbrHeader->status & SBRDEC_HDR_STAT_UPDATE) {
    /* Got a new header from extern (e.g. from an ASC) */
    headerStatus = HEADER_OK;
    hSbrHeader->status &= ~SBRDEC_HDR_STAT_UPDATE;
  }
  else if (thisHdrSlot != lastHdrSlot) {
    /* Copy the last header into this slot otherwise the
       header compare will trigger more HEADER_RESETs than needed. */
    copySbrHeader( hSbrHeader, &self->sbrHeader[elementIndex][lastHdrSlot] );
  }

  /*
     Check if bit stream data is valid and matches the element context
  */
  if ( ((prevElement != ID_SCE) && (prevElement != ID_CPE)) || prevElement != hSbrElement->elementID) {
    /* In case of LFE we also land here, since there is no LFE SBR element (do upsampling only) */
    fDoDecodeSbrData = 0;
  }

  if (fDoDecodeSbrData)
  {
    if ((INT)FDKgetValidBits(hBs) <= 0) {
      fDoDecodeSbrData = 0;
    }
  }

  /*
     SBR CRC-check
  */
  if (fDoDecodeSbrData)
  {
    if (crcFlag == 1) {
      switch (self->coreCodec) {
      case AOT_ER_AAC_ELD:
        FDKpushFor (hBs, 10);
        /* check sbrcrc later: we don't know the payload length now */
        break;
      default:
        CRCLen = bsPayLen - 10;                     /* change: 0 => i */
        if (CRCLen < 0) {
          fDoDecodeSbrData = 0;
        } else {
          fDoDecodeSbrData = SbrCrcCheck (hBs, CRCLen);
        }
        break;
      }
    }
  } /* if (fDoDecodeSbrData) */

  /*
     Read in the header data and issue a reset if change occured
  */
  if (fDoDecodeSbrData)
  {
    int sbrHeaderPresent;

    {
      sbrHeaderPresent = FDKreadBit(hBs);
    }

    if ( sbrHeaderPresent ) {
      headerStatus = sbrGetHeaderData (hSbrHeader,
                                       hBs,
                                       self->flags,
                                       1);
    }

    if (headerStatus == HEADER_RESET)
    {
      errorStatus = sbrDecoder_HeaderUpdate(
            self,
            hSbrHeader,
            headerStatus,
            pSbrChannel,
            hSbrElement->nChannels 
            );

      if (errorStatus == SBRDEC_OK) {
        hSbrHeader->syncState = SBR_HEADER;
      } else {
        hSbrHeader->syncState = SBR_NOT_INITIALIZED;
      }
    }

    if (errorStatus != SBRDEC_OK) {
      fDoDecodeSbrData = 0;
    }
  } /* if (fDoDecodeSbrData) */

  /*
    Print debugging output only if state has changed
  */

  /* read frame data */
  if ((hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) {
    int sbrFrameOk;
    /* read the SBR element data */
    if (stereo) {
      sbrFrameOk = sbrGetChannelPairElement(hSbrHeader,
                                            hFrameDataLeft,
                                            hFrameDataRight,
                                            hBs,
                                            self->flags,
                                            self->pSbrElement[elementIndex]->transposerSettings.overlap);
    }
    else {
      if (self->hParametricStereoDec != NULL) {
        /* update slot index for PS bitstream parsing */
        self->hParametricStereoDec->bsLastSlot = self->hParametricStereoDec->bsReadSlot;
        self->hParametricStereoDec->bsReadSlot = hSbrElement->useFrameSlot;
      }
      sbrFrameOk = sbrGetSingleChannelElement(hSbrHeader,
                                              hFrameDataLeft,
                                              hBs,
                                              self->hParametricStereoDec,
                                              self->flags,
                                              self->pSbrElement[elementIndex]->transposerSettings.overlap);
    }
    if (!sbrFrameOk) {
      fDoDecodeSbrData = 0;
    }
    else {
      INT valBits;

      if (bsPayLen > 0) {
        valBits = bsPayLen - ((INT)startPos - (INT)FDKgetValidBits(hBs));
      } else {
        valBits = (INT)FDKgetValidBits(hBs);
      }

      if ( crcFlag == 1 ) {
        switch (self->coreCodec) {
        case AOT_ER_AAC_ELD:
          {
            /* late crc check for eld */
            INT payloadbits = (INT)startPos - (INT)FDKgetValidBits(hBs) - startPos;
            INT crcLen      = payloadbits - 10;
            FDKpushBack(hBs, payloadbits);
            fDoDecodeSbrData      = SbrCrcCheck (hBs, crcLen);
            FDKpushFor(hBs, crcLen);
          }
          break;
        default:
          break;
        }
      }

      /* sanity check of remaining bits */
      if (valBits < 0) {
        fDoDecodeSbrData = 0;
      } else {
        switch (self->coreCodec) {
        case AOT_SBR:
        case AOT_PS:
        case AOT_AAC_LC:
          {
            /* This sanity check is only meaningful with General Audio bitstreams */
            int alignBits = valBits & 0x7;

            if (valBits > alignBits) {
              fDoDecodeSbrData = 0;
            }
          }
          break;
        default:
          /* No sanity check available */
          break;
        }
      }
    }
  } else {
    /* The returned bit count will not be the actual payload size since we did not
       parse the frame data. Return an error so that the caller can react respectively. */
    errorStatus = SBRDEC_PARSE_ERROR;
  }

  if (!fDoDecodeSbrData) {
    /* Set error flag for this slot to trigger concealment */
    self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 1;
    errorStatus = SBRDEC_PARSE_ERROR;
  } else {
    /* Everything seems to be ok so clear the error flag */
    self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 0;
  }

  if (!stereo) {
    /* Turn coupling off explicitely to avoid access to absent right frame data
       that might occur with corrupt bitstreams. */
    hFrameDataLeft->coupling = COUPLING_OFF;
  }

bail:
  if (errorStatus == SBRDEC_OK) {
    if (headerStatus == HEADER_NOT_PRESENT) {
      /* Use the old header for this frame */
      hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = lastHdrSlot;
    } else {
      /* Use the new header for this frame */
      hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = thisHdrSlot;
    }

    /* Move frame pointer to the next slot which is up to be decoded/applied next */
    hSbrElement->useFrameSlot = (hSbrElement->useFrameSlot+1) % (self->numDelayFrames+1);
  }

  *count -= startPos - FDKgetValidBits(hBs);

  return errorStatus;
}
Exemple #9
0
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 = (hTp->flags & TPDEC_CONFIG_FOUND), startPosFirstFrame = -1;
  INT numRawDataBlocksFirstFrame = 0, numRawDataBlocksPrevious, globalFramePosFirstFrame = 0, rawDataBlockLengthFirstFrame = 0;
  INT ignoreBufferFullness = hTp->flags & (TPDEC_LOST_FRAMES_PENDING|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) {
    err = TRANSPORTDEC_NOT_ENOUGH_BITS;
    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) */

    if (err == TRANSPORTDEC_OK )
    {
      err = transportDec_readHeader(
              hTp,
              hBs,
              syncLength,
              ignoreBufferFullness,
             &rawDataBlockLength,
             &fTraverseMoreFrames,
             &syncLayerFrameBits,
             &fConfigFound,
             &headerBits
              );
    }

    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 at 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))
        {
          /* In case of ECD and sync error, do not rewind anywhere. */
          if (err == TRANSPORTDEC_SYNC_ERROR)
          {
            startPosFirstFrame = -1;
            fConfigFound = 0;
            numFramesTraversed = 0;
          }
          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_LOST_FRAMES_PENDING|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;

  /* Detect pointless TRANSPORTDEC_NOT_ENOUGH_BITS error case, were the bit buffer is already full,
     or no new burst packet fits. Recover by advancing the bit buffer. */
  if ( (TRANSPORTDEC_NOT_ENOUGH_BITS == err) &&  (FDKgetValidBits(hBs) >= ((TRANSPORTDEC_INBUF_SIZE*8 - ((hTp->avgBitRate*hTp->burstPeriod)/1000)) - 7)) )
  {
    FDKpushFor(hBs, TPDEC_SYNCSKIP);
    err = TRANSPORTDEC_SYNC_ERROR;
  }

  if (err == TRANSPORTDEC_OK) {
    hTp->flags |= TPDEC_SYNCOK;
  }

  if (fConfigFound) {
    hTp->flags |= TPDEC_CONFIG_FOUND;
  }

  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;
}
TRANSPORTDEC_ERROR adtsRead_DecodeHeader(
        HANDLE_ADTS           pAdts,
        CSAudioSpecificConfig *pAsc,
        HANDLE_FDK_BITSTREAM  hBs,
        const INT             ignoreBufferFullness
        )
{
  INT crcReg;

  INT valBits;
  INT cmp_buffer_fullness;
  int i, adtsHeaderLength;

  STRUCT_ADTS_BS bs;

#ifdef TP_PCE_ENABLE
  CProgramConfig oldPce;
  /* Store the old PCE temporarily. Maybe we'll need it later if we
     have channelConfig=0 and no PCE in this frame. */
  FDKmemcpy(&oldPce, &pAsc->m_progrConfigElement, sizeof(CProgramConfig));
#endif

  valBits = FDKgetValidBits(hBs);

#ifndef ANDROID_DEFAULT_CODE
  if (valBits <= ADTS_HEADERLENGTH) return TRANSPORTDEC_NOT_ENOUGH_BITS;
#endif

  /* adts_fixed_header */
  bs.mpeg_id           = FDKreadBits(hBs, Adts_Length_Id);
  bs.layer             = FDKreadBits(hBs, Adts_Length_Layer);
  bs.protection_absent = FDKreadBits(hBs, Adts_Length_ProtectionAbsent);
  bs.profile           = FDKreadBits(hBs, Adts_Length_Profile);
  bs.sample_freq_index = FDKreadBits(hBs, Adts_Length_SamplingFrequencyIndex);
  bs.private_bit       = FDKreadBits(hBs, Adts_Length_PrivateBit);
  bs.channel_config    = FDKreadBits(hBs, Adts_Length_ChannelConfiguration);
  bs.original          = FDKreadBits(hBs, Adts_Length_OriginalCopy);
  bs.home              = FDKreadBits(hBs, Adts_Length_Home);

  /* adts_variable_header */
  bs.copyright_id    = FDKreadBits(hBs, Adts_Length_CopyrightIdentificationBit);
  bs.copyright_start = FDKreadBits(hBs, Adts_Length_CopyrightIdentificationStart);
  bs.frame_length    = FDKreadBits(hBs, Adts_Length_FrameLength);
  bs.adts_fullness   = FDKreadBits(hBs, Adts_Length_BufferFullness);
  bs.num_raw_blocks  = FDKreadBits(hBs, Adts_Length_NumberOfRawDataBlocksInFrame);
  bs.num_pce_bits    = 0;

  adtsHeaderLength = ADTS_HEADERLENGTH;

  if (!bs.protection_absent) {
    FDKcrcReset(&pAdts->crcInfo);
    FDKpushBack(hBs, 56);   /* complete fixed and variable header! */
    crcReg = FDKcrcStartReg(&pAdts->crcInfo, hBs, 0);
    FDKpushFor(hBs, 56);
  }

  if (! bs.protection_absent && bs.num_raw_blocks>0) {
    for (i=0; i<bs.num_raw_blocks; i++) {
      pAdts->rawDataBlockDist[i] = (USHORT)FDKreadBits(hBs, 16);
      adtsHeaderLength += 16;
    }
    /* Change raw data blocks to delta values */
    pAdts->rawDataBlockDist[bs.num_raw_blocks] = bs.frame_length - 7 - bs.num_raw_blocks*2 - 2 ;
    for (i=bs.num_raw_blocks; i>0; i--) {
      pAdts->rawDataBlockDist[i] -= pAdts->rawDataBlockDist[i-1];
    }
  }

  /* adts_error_check */
  if (!bs.protection_absent)
  {
    USHORT crc_check;

    FDKcrcEndReg(&pAdts->crcInfo, hBs, crcReg);
    crc_check = FDKreadBits(hBs, Adts_Length_CrcCheck);
    adtsHeaderLength += Adts_Length_CrcCheck;

    pAdts->crcReadValue = crc_check;
    /* Check header CRC in case of multiple raw data blocks */
    if (bs.num_raw_blocks > 0) {
      if (pAdts->crcReadValue != FDKcrcGetCRC(&pAdts->crcInfo)) {
        return TRANSPORTDEC_CRC_ERROR;
      }
      /* Reset CRC for the upcoming raw_data_block() */
      FDKcrcReset(&pAdts->crcInfo);
    }
  }


  /* check if valid header */
  if (
      (bs.layer != 0) ||                          // we only support MPEG ADTS
      (bs.sample_freq_index >= 13)                // we only support 96kHz - 7350kHz
      ) {
    FDKpushFor(hBs, bs.frame_length * 8);   // try again one frame later
    return TRANSPORTDEC_UNSUPPORTED_FORMAT;
  }

  /* special treatment of id-bit */
  if ( (bs.mpeg_id == 0) && (pAdts->decoderCanDoMpeg4 == 0) )
  {
    /* MPEG-2 decoder cannot play MPEG-4 bitstreams */


    FDKpushFor(hBs, bs.frame_length * 8);  // try again one frame later
    return TRANSPORTDEC_UNSUPPORTED_FORMAT;
  }

  if (!ignoreBufferFullness)
  {
    cmp_buffer_fullness = bs.frame_length*8 + bs.adts_fullness*32*getNumberOfEffectiveChannels(bs.channel_config);


    /* Evaluate buffer fullness */
    if (bs.adts_fullness != 0x7FF)
    {
      if (pAdts->BufferFullnesStartFlag)
      {
        if ( valBits < cmp_buffer_fullness )
        {
          /* Condition for start of decoding is not fulfilled */

          /* The current frame will not be decoded */
          FDKpushBack(hBs, adtsHeaderLength);

          if ( (cmp_buffer_fullness+adtsHeaderLength) > ((TRANSPORTDEC_INBUF_SIZE<<3)-7) ) {
            return TRANSPORTDEC_SYNC_ERROR;
          } else {
            return TRANSPORTDEC_NOT_ENOUGH_BITS;
          }
        }
        else
        {
          pAdts->BufferFullnesStartFlag = 0;
        }
      }
    }
  }


  /* Get info from ADTS header */
  AudioSpecificConfig_Init(pAsc);
  pAsc->m_aot                    = (AUDIO_OBJECT_TYPE)(bs.profile + 1);
  pAsc->m_samplingFrequencyIndex = bs.sample_freq_index;
  pAsc->m_samplingFrequency      = SamplingRateTable[bs.sample_freq_index];
  pAsc->m_channelConfiguration   = bs.channel_config;
  pAsc->m_samplesPerFrame        = 1024;

#ifdef TP_PCE_ENABLE
  if (bs.channel_config == 0)
  {
    int pceBits = 0;
    UINT alignAnchor = FDKgetValidBits(hBs);
    
    if (FDKreadBits(hBs,3) == ID_PCE) {
      /* Got luck! Parse the PCE */
      int crcReg;
      crcReg = adtsRead_CrcStartReg(pAdts, hBs, 0);

      CProgramConfig_Read(&pAsc->m_progrConfigElement, hBs, alignAnchor);

      adtsRead_CrcEndReg(pAdts, hBs, crcReg);
      pceBits = alignAnchor - FDKgetValidBits(hBs);
      /* store the number of PCE bits */
      bs.num_pce_bits = pceBits;
    }
    else {
      /* No PCE in this frame! Push back the ID tag bits. */
      FDKpushBack(hBs,3);

      /* Encoders do not have to write a PCE in each frame.
         So if we already have a valid PCE we have to use it. */
      if (  oldPce.isValid
        && (bs.sample_freq_index == pAdts->bs.sample_freq_index)  /* we could compare the complete fixed header (bytes) here! */
        && (bs.channel_config    == pAdts->bs.channel_config) /* == 0 */
        && (bs.mpeg_id           == pAdts->bs.mpeg_id) )
      { /* Restore previous PCE which is still valid */
        FDKmemcpy(&pAsc->m_progrConfigElement, &oldPce, sizeof(CProgramConfig));
      }
      else if (bs.mpeg_id == 0) {
        /* If not it seems that we have a implicit channel configuration.
           This mode is not allowed in the context of ISO/IEC 14496-3.
           Skip this frame and try the next one. */
        FDKpushFor(hBs, (bs.frame_length<<3) - adtsHeaderLength - 3);
        return TRANSPORTDEC_UNSUPPORTED_FORMAT;
      }
      /* else {
         ISO/IEC 13818-7 implicit channel mapping is allowed.
         So just open the box of chocolates to see what we got.
      } */
    }
  }
#endif /* TP_PCE_ENABLE */

  /* Copy bit stream data struct to persistent memory now, once we passed all sanity checks above. */
  FDKmemcpy(&pAdts->bs, &bs, sizeof(STRUCT_ADTS_BS));

  return TRANSPORTDEC_OK;
}