aboutsummaryrefslogtreecommitdiffstats
path: root/libMpegTPDec
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2013-08-27 16:28:09 -0700
committerJean-Michel Trivi <jmtrivi@google.com>2013-08-27 16:28:09 -0700
commit5016eb7f6582fbb2d72d79be782325a12df08864 (patch)
treebc2325ebc6840a20d25f35a0c5a6a13454d2e402 /libMpegTPDec
parentb9774f90651be61065ae40171fc321f6ced60e49 (diff)
downloadfdk-aac-5016eb7f6582fbb2d72d79be782325a12df08864.tar.gz
fdk-aac-5016eb7f6582fbb2d72d79be782325a12df08864.tar.bz2
fdk-aac-5016eb7f6582fbb2d72d79be782325a12df08864.zip
Decoder stability, sanity checks improvements
* AAC-Decoder - Improved PCE handling for saver (re-)configuration and metadata processing. Modified file(s): libAACdec/src/aacdecoder.cpp libAACdec/src/aacdecoder_lib.cpp - Transport layer changes (config found) -> to be evaluated. Modified file(s): libMpegTPDec/include/tpdec_lib.h libMpegTPDec/src/tpdec_latm.h libMpegTPDec/src/version libMpegTPDec/src/tpdec_asc.cpp libMpegTPDec/src/tpdec_lib.cpp libMpegTPDec/src/tpdec_adts.cpp libMpegTPDec/src/tpdec_latm.cpp libSYS/include/FDK_audio.h libSYS/src/genericStds.cpp - Enable concealment state machine to skip states if the corresponding parameter is set to zero. Modified file(s): libAACdec/src/conceal.cpp - Add some more sanity checks to avoid segmentation faults especially when setting dynamic API params. Modified file(s): libAACdec/src/aacdecoder_lib.cpp - Fix to do a fail-safe initialization of IMDCT for all channels even with corrupt streams. Modified file(s): libAACdec/src/aacdecoder.cpp - HCR decoder fix (remove warnings). Modified file(s): libAACdec/src/block.cpp - Fix border calculation in SBR decoder's LPP transposer patch determination. Modified file(s): libSBRdec/src/env_dec.cpp libSBRdec/src/sbrdecoder.cpp libSBRdec/src/lpp_tran.cpp Bug 9428126 Change-Id: Ib415b702b88a7ec8e9a55789d79cafb39296d26b
Diffstat (limited to 'libMpegTPDec')
-rw-r--r--libMpegTPDec/include/tpdec_lib.h21
-rw-r--r--libMpegTPDec/src/tpdec_adts.cpp4
-rw-r--r--libMpegTPDec/src/tpdec_asc.cpp147
-rw-r--r--libMpegTPDec/src/tpdec_latm.cpp20
-rw-r--r--libMpegTPDec/src/tpdec_latm.h13
-rw-r--r--libMpegTPDec/src/tpdec_lib.cpp444
-rw-r--r--libMpegTPDec/src/version2
7 files changed, 476 insertions, 175 deletions
diff --git a/libMpegTPDec/include/tpdec_lib.h b/libMpegTPDec/include/tpdec_lib.h
index 5cec91d..fb4c41d 100644
--- a/libMpegTPDec/include/tpdec_lib.h
+++ b/libMpegTPDec/include/tpdec_lib.h
@@ -186,6 +186,27 @@ int CProgramConfig_IsValid ( const CProgramConfig *pPce );
void CProgramConfig_Read ( CProgramConfig *pPce,
HANDLE_FDK_BITSTREAM bs,
UINT alignAnchor );
+
+/*!
+ \brief Compare two Program Config Elements.
+ \param pPce1 Pointer to first Program Config Element structure.
+ \param pPce2 Pointer to second Program Config Element structure.
+ \return -1 if PCEs are completely different,
+ 0 if PCEs are completely equal,
+ 1 if PCEs are different but have the same channel config,
+ 2 if PCEs have different channel config but same number of channels.
+*/
+int CProgramConfig_Compare ( const CProgramConfig * const pPce1,
+ const CProgramConfig * const pPce2 );
+
+/*!
+ \brief Get a Program Config Element that matches the predefined MPEG-4 channel configurations 1-14.
+ \param pPce Program Config Element structure.
+ \param channelConfig MPEG-4 channel configuration.
+ \return void
+*/
+void CProgramConfig_GetDefault ( CProgramConfig *pPce,
+ const UINT channelConfig );
#endif /* TP_PCE_ENABLE */
/**
diff --git a/libMpegTPDec/src/tpdec_adts.cpp b/libMpegTPDec/src/tpdec_adts.cpp
index b5c67c2..c455681 100644
--- a/libMpegTPDec/src/tpdec_adts.cpp
+++ b/libMpegTPDec/src/tpdec_adts.cpp
@@ -374,12 +374,12 @@ int adtsRead_GetRawDataBlockLength(
length = -1; /* raw data block length is unknown */
} else {
if (blockNum < 0 || blockNum > 3) {
- return TRANSPORTDEC_INVALID_PARAMETER;
+ length = -1;
}
length = (pAdts->rawDataBlockDist[blockNum] << 3) - 16;
}
}
- if (blockNum == 0) {
+ if (blockNum == 0 && length > 0) {
length -= pAdts->bs.num_pce_bits;
}
return length;
diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
index e6278d6..59ad58b 100644
--- a/libMpegTPDec/src/tpdec_asc.cpp
+++ b/libMpegTPDec/src/tpdec_asc.cpp
@@ -205,6 +205,145 @@ void CProgramConfig_Read(
pPce->isValid = 1;
}
+
+/*
+ * Compare two program configurations.
+ * Returns the result of the comparison:
+ * -1 - completely different
+ * 0 - completely equal
+ * 1 - different but same channel configuration
+ * 2 - different channel configuration but same number of channels
+ */
+int CProgramConfig_Compare ( const CProgramConfig * const pPce1,
+ const CProgramConfig * const pPce2 )
+{
+ int result = 0; /* Innocent until proven false. */
+
+ if (FDKmemcmp(pPce1, pPce2, sizeof(CProgramConfig)) != 0)
+ { /* Configurations are not completely different.
+ So look into details and analyse the channel configurations: */
+ result = -1;
+
+ if (pPce1->NumChannels == pPce2->NumChannels)
+ { /* Now the logic changes. We first assume to have the same channel configuration
+ and then prove if this assumption is true. */
+ result = 1;
+
+ /* Front channels */
+ if (pPce1->NumFrontChannelElements != pPce2->NumFrontChannelElements) {
+ result = 2; /* different number of front channel elements */
+ } else {
+ int el, numCh1 = 0, numCh2 = 0;
+ for (el = 0; el < pPce1->NumFrontChannelElements; el += 1) {
+ numCh1 += pPce1->FrontElementIsCpe[el] ? 2 : 1;
+ numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1;
+ }
+ if (numCh1 != numCh2) {
+ result = 2; /* different number of front channels */
+ }
+ }
+ /* Side channels */
+ if (pPce1->NumSideChannelElements != pPce2->NumSideChannelElements) {
+ result = 2; /* different number of side channel elements */
+ } else {
+ int el, numCh1 = 0, numCh2 = 0;
+ for (el = 0; el < pPce1->NumSideChannelElements; el += 1) {
+ numCh1 += pPce1->SideElementIsCpe[el] ? 2 : 1;
+ numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1;
+ }
+ if (numCh1 != numCh2) {
+ result = 2; /* different number of side channels */
+ }
+ }
+ /* Back channels */
+ if (pPce1->NumBackChannelElements != pPce2->NumBackChannelElements) {
+ result = 2; /* different number of back channel elements */
+ } else {
+ int el, numCh1 = 0, numCh2 = 0;
+ for (el = 0; el < pPce1->NumBackChannelElements; el += 1) {
+ numCh1 += pPce1->BackElementIsCpe[el] ? 2 : 1;
+ numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1;
+ }
+ if (numCh1 != numCh2) {
+ result = 2; /* different number of back channels */
+ }
+ }
+ /* LFE channels */
+ if (pPce1->NumLfeChannelElements != pPce2->NumLfeChannelElements) {
+ result = 2; /* different number of lfe channels */
+ }
+ /* LFEs are always SCEs so we don't need to count the channels. */
+ }
+ }
+
+ return result;
+}
+
+void CProgramConfig_GetDefault( CProgramConfig *pPce,
+ const UINT channelConfig )
+{
+ FDK_ASSERT(pPce != NULL);
+
+ /* Init PCE */
+ CProgramConfig_Init(pPce);
+ pPce->Profile = 1; /* Set AAC LC because it is the only supported object type. */
+
+ switch (channelConfig) {
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ case 6: /* 3/0/2.1ch */
+ pPce->NumLfeChannelElements += 1;
+ pPce->NumChannels += 1;
+ case 5: /* 3/0/2.0ch */
+ case 4: /* 3/0/1.0ch */
+ pPce->NumBackChannelElements += 1;
+ pPce->BackElementIsCpe[0] = (channelConfig>4) ? 1 : 0;
+ pPce->NumChannels += (channelConfig>4) ? 2 : 1;
+ pPce->NumEffectiveChannels += (channelConfig>4) ? 2 : 1;
+ case 3: /* 3/0/0.0ch */
+ pPce->NumFrontChannelElements += 1;
+ pPce->FrontElementIsCpe[1] = 1;
+ pPce->NumChannels += 2;
+ pPce->NumEffectiveChannels += 2;
+ case 1: /* 1/0/0.0ch */
+ pPce->NumFrontChannelElements += 1;
+ pPce->FrontElementIsCpe[0] = 0;
+ pPce->NumChannels += 1;
+ pPce->NumEffectiveChannels += 1;
+ pPce->isValid = 1;
+ break;
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ case 2: /* 2/0/0.ch */
+ pPce->NumFrontChannelElements = 1;
+ pPce->FrontElementIsCpe[0] = 1;
+ pPce->NumChannels += 2;
+ pPce->NumEffectiveChannels += 2;
+ pPce->isValid = 1;
+ break;
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ default:
+ pPce->isValid = 0; /* To be explicit! */
+ break;
+ }
+
+ if (pPce->isValid) {
+ /* Create valid element instance tags */
+ int el, elTagSce = 0, elTagCpe = 0;
+
+ for (el = 0; el < pPce->NumFrontChannelElements; el += 1) {
+ pPce->FrontElementTagSelect[el] = (pPce->FrontElementIsCpe) ? elTagCpe++ : elTagSce++;
+ }
+ for (el = 0; el < pPce->NumSideChannelElements; el += 1) {
+ pPce->SideElementTagSelect[el] = (pPce->SideElementIsCpe) ? elTagCpe++ : elTagSce++;
+ }
+ for (el = 0; el < pPce->NumBackChannelElements; el += 1) {
+ pPce->BackElementTagSelect[el] = (pPce->BackElementIsCpe) ? elTagCpe++ : elTagSce++;
+ }
+ elTagSce = 0;
+ for (el = 0; el < pPce->NumLfeChannelElements; el += 1) {
+ pPce->LfeElementTagSelect[el] = elTagSce++;
+ }
+ }
+}
#endif /* TP_PCE_ENABLE */
/**
@@ -589,18 +728,18 @@ static INT ld_sbr_header( const CSAudioSpecificConfig *asc,
}
switch ( channelConfiguration ) {
+ case 7:
+ error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
+ case 6:
case 5:
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
case 3:
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
break;
- case 7:
- error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++);
- case 6:
- error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
case 4:
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
+ error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++);
break;
}
diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp
index 7595c5e..5710d77 100644
--- a/libMpegTPDec/src/tpdec_latm.cpp
+++ b/libMpegTPDec/src/tpdec_latm.cpp
@@ -120,7 +120,8 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement(
CLatmDemux *pLatmDemux,
int m_muxConfigPresent,
CSTpCallBacks *pTpDecCallbacks,
- CSAudioSpecificConfig *pAsc
+ CSAudioSpecificConfig *pAsc,
+ int *pfConfigFound
)
{
TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
@@ -129,12 +130,17 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement(
pLatmDemux->m_useSameStreamMux = FDKreadBits(bs,1);
if (!pLatmDemux->m_useSameStreamMux) {
- if ((ErrorStatus = CLatmDemux_ReadStreamMuxConfig(bs, pLatmDemux, pTpDecCallbacks, pAsc))) {
+ if ((ErrorStatus = CLatmDemux_ReadStreamMuxConfig(bs, pLatmDemux, pTpDecCallbacks, pAsc, pfConfigFound))) {
return (ErrorStatus);
}
}
}
+ /* If there was no configuration read, its not possible to parse PayloadLengthInfo below. */
+ if (! *pfConfigFound) {
+ return TRANSPORTDEC_SYNC_ERROR;
+ }
+
if (pLatmDemux->m_AudioMuxVersionA == 0) {
/* Do only once per call, because parsing and decoding is done in-line. */
if ((ErrorStatus = CLatmDemux_ReadPayloadLengthInfo(bs,pLatmDemux))) {
@@ -154,6 +160,7 @@ TRANSPORTDEC_ERROR CLatmDemux_Read(
TRANSPORT_TYPE tt,
CSTpCallBacks *pTpDecCallbacks,
CSAudioSpecificConfig *pAsc,
+ int *pfConfigFound,
const INT ignoreBufferFullness
)
{
@@ -168,7 +175,7 @@ TRANSPORTDEC_ERROR CLatmDemux_Read(
return TRANSPORTDEC_NOT_ENOUGH_BITS;
}
- if ((ErrorStatus = CLatmDemux_ReadAudioMuxElement(bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0), pTpDecCallbacks, pAsc)))
+ if ((ErrorStatus = CLatmDemux_ReadAudioMuxElement(bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0), pTpDecCallbacks, pAsc, pfConfigFound)))
return (ErrorStatus);
if (!ignoreBufferFullness)
@@ -205,7 +212,8 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig(
HANDLE_FDK_BITSTREAM bs,
CLatmDemux *pLatmDemux,
CSTpCallBacks *pTpDecCallbacks,
- CSAudioSpecificConfig *pAsc
+ CSAudioSpecificConfig *pAsc,
+ int * pfConfigFound
)
{
LATM_LAYER_INFO *p_linfo = NULL;
@@ -272,6 +280,7 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig(
if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &tmpBs, 1, pTpDecCallbacks))) {
return (ErrorStatus);
}
+ *pfConfigFound = 1;
/* The field p_linfo->m_ascLen could be wrong, so check if */
if ( 0 > (INT)FDKgetValidBits(&tmpBs)) {
@@ -292,6 +301,7 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig(
if (cbError != 0) {
return TRANSPORTDEC_UNKOWN_ERROR;
}
+ *pfConfigFound = 1;
}
}
@@ -377,7 +387,7 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLa
else {
ErrorStatus = TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_TIMEFRAMING;
}
- if (pLatmDemux->m_audioMuxLengthBytes > 0 && totalPayloadBits > pLatmDemux->m_audioMuxLengthBytes*8) {
+ if (pLatmDemux->m_audioMuxLengthBytes > (UINT)0 && totalPayloadBits > (int)pLatmDemux->m_audioMuxLengthBytes*8) {
return TRANSPORTDEC_PARSE_ERROR;
}
return (ErrorStatus);
diff --git a/libMpegTPDec/src/tpdec_latm.h b/libMpegTPDec/src/tpdec_latm.h
index e8dd37a..6dc13e8 100644
--- a/libMpegTPDec/src/tpdec_latm.h
+++ b/libMpegTPDec/src/tpdec_latm.h
@@ -144,14 +144,25 @@ TRANSPORTDEC_ERROR CLatmDemux_Read(
TRANSPORT_TYPE tt,
CSTpCallBacks *pTpDecCallbacks,
CSAudioSpecificConfig *pAsc,
+ int *pfConfigFound,
const INT ignoreBufferFullness
);
+/**
+ * \brief Read StreamMuxConfig
+ * \param bs bit stream handle as data source
+ * \param pLatmDemux pointer to CLatmDemux struct of current LATM context
+ * \param pTpDecCallbacks Call back structure for configuration callbacks
+ * \param pAsc pointer to a ASC for configuration storage
+ * \param pfConfigFound pointer to a flag which is set to 1 if a configuration was found and processed successfully
+ * \return error code
+ */
TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig(
HANDLE_FDK_BITSTREAM bs,
CLatmDemux *pLatmDemux,
CSTpCallBacks *pTpDecCallbacks,
- CSAudioSpecificConfig *pAsc
+ CSAudioSpecificConfig *pAsc,
+ int * pfConfigFound
);
TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux);
diff --git a/libMpegTPDec/src/tpdec_lib.cpp b/libMpegTPDec/src/tpdec_lib.cpp
index 8de20eb..1f9f29b 100644
--- a/libMpegTPDec/src/tpdec_lib.cpp
+++ b/libMpegTPDec/src/tpdec_lib.cpp
@@ -197,8 +197,7 @@ HANDLE_TRANSPORTDEC transportDec_Open( const TRANSPORT_TYPE transportFmt, const
if (hInput != NULL) {
/* Create bitstream */
- if ( (transportFmt == TT_MP4_RAW)
- || (transportFmt == TT_DRM) ){
+ if ( TT_IS_PACKET(transportFmt) ) {
hInput->bsBuffer = NULL;
} else {
hInput->bsBuffer = GetRam_TransportDecoderBuffer(0);
@@ -222,7 +221,9 @@ TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR *
FDK_BITSTREAM bs;
HANDLE_FDK_BITSTREAM hBs = &bs;
- FDKinitBitStream(hBs, conf, 0x80000000, length<<3, BS_READER);
+ FDKinitBitStream(hBs, conf, 0x10000000, length<<3, BS_READER);
+
+ int fConfigFound = 0;
/* config transport decoder */
switch (hTp->transportFmt) {
@@ -234,27 +235,27 @@ TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR *
return TRANSPORTDEC_INVALID_PARAMETER;
}
CLatmDemux *pLatmDemux = &hTp->parser.latm;
- err = CLatmDemux_ReadStreamMuxConfig(hBs, pLatmDemux, &hTp->callbacks, hTp->asc);
+ err = CLatmDemux_ReadStreamMuxConfig(hBs, pLatmDemux, &hTp->callbacks, hTp->asc, &fConfigFound);
if (err != TRANSPORTDEC_OK) {
return err;
}
}
break;
default:
- case TT_MP4_RAW:
+ fConfigFound = 1;
err = AudioSpecificConfig_Parse(&hTp->asc[layer], hBs, 1, &hTp->callbacks);
- break;
- }
- if (err == TRANSPORTDEC_OK) {
- int errC;
+ if (err == TRANSPORTDEC_OK) {
+ int errC;
- errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer]);
- if (errC != 0) {
- err = TRANSPORTDEC_PARSE_ERROR;
- }
+ errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer]);
+ if (errC != 0) {
+ err = TRANSPORTDEC_PARSE_ERROR;
+ }
+ }
+ break;
}
- if (err == TRANSPORTDEC_OK) {
+ if (err == TRANSPORTDEC_OK && fConfigFound) {
hTp->flags |= TPDEC_CONFIG_FOUND;
}
@@ -313,18 +314,16 @@ TRANSPORTDEC_ERROR transportDec_FillData(
/* set bitbuffer shortcut */
hBs = &hTp->bitStream[layer];
- switch (hTp->transportFmt) {
- case TT_MP4_RAW:
- case TT_DRM:
+ if ( TT_IS_PACKET(hTp->transportFmt) ) {
+ if (hTp->numberOfRawDataBlocks == 0) {
/* For packet based transport, pass input buffer to bitbuffer without copying the data.
Unfortunately we do not know the actual buffer size. And the FDK bit buffer implementation
needs a number 2^x. So we assume the maximum of 48 channels with 6144 bits per channel
and round it up to the next power of 2 => 65536 bytes */
FDKinitBitStream(hBs, pBuffer, 0x10000, (*pBytesValid)<<3, BS_READER);
*pBytesValid = 0;
- break;
-
- default:
+ }
+ } else {
/* ... else feed bitbuffer with new stream data (append). */
if (hTp->numberOfRawDataBlocks <= 0) {
FDKfeedBuffer (hBs, pBuffer, bufferSize, pBytesValid) ;
@@ -369,6 +368,82 @@ INT transportDec_GetBufferFullness( const HANDLE_TRANSPORTDEC hTp )
}
/**
+ * \brief adjust bit stream position and the end of an access unit.
+ * \param hTp transport decoder handle.
+ * \return error code.
+ */
+static
+TRANSPORTDEC_ERROR transportDec_AdjustEndOfAccessUnit(HANDLE_TRANSPORTDEC hTp)
+{
+ HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0];
+ TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK;
+
+ switch (hTp->transportFmt) {
+ case TT_MP4_LOAS:
+ case TT_MP4_LATM_MCP0:
+ case TT_MP4_LATM_MCP1:
+ if ( hTp->numberOfRawDataBlocks == 0 )
+ {
+ /* Do byte align at the end of AudioMuxElement. */
+ FDKbyteAlign(hBs, hTp->globalFramePos);
+
+ /* Check global frame length */
+ if (hTp->transportFmt == TT_MP4_LOAS && hTp->parser.latm.m_audioMuxLengthBytes > 0)
+ {
+ int loasOffset;
+
+ loasOffset = (hTp->parser.latm.m_audioMuxLengthBytes*8 + FDKgetValidBits(hBs)) - hTp->globalFramePos;
+ if (loasOffset != 0) {
+ FDKpushBiDirectional(hBs, loasOffset);
+ /* For ELD and other payloads there is an unknown amount of padding, so ignore unread bits, but
+ throw an error only if too many bits where read. */
+ if (loasOffset < 0) {
+ err = TRANSPORTDEC_PARSE_ERROR;
+ }
+ }
+ }
+ }
+ break;
+
+ case TT_MP4_ADTS:
+ if (hTp->parser.adts.bs.protection_absent == 0)
+ {
+ int offset;
+
+ /* Calculate offset to end of AU */
+ offset = hTp->parser.adts.rawDataBlockDist[hTp->parser.adts.bs.num_raw_blocks-hTp->numberOfRawDataBlocks]<<3;
+ /* CAUTION: The PCE (if available) is declared to be a part of the header! */
+ offset -= hTp->accessUnitAnchor[0] - FDKgetValidBits(hBs) + 16 + hTp->parser.adts.bs.num_pce_bits;
+ FDKpushBiDirectional(hBs, offset);
+ }
+ if (hTp->parser.adts.bs.num_raw_blocks > 0 && hTp->parser.adts.bs.protection_absent == 0) {
+ /* Note this CRC read currently happens twice because of transportDec_CrcCheck() */
+ hTp->parser.adts.crcReadValue = FDKreadBits(hBs, 16);
+ }
+ if ( hTp->numberOfRawDataBlocks == 0 )
+ {
+ /* Check global frame length */
+ if (hTp->parser.adts.bs.protection_absent == 0)
+ {
+ int offset;
+
+ offset = (hTp->parser.adts.bs.frame_length*8 - ADTS_SYNCLENGTH + FDKgetValidBits(hBs)) - hTp->globalFramePos;
+ if (offset != 0) {
+ FDKpushBiDirectional(hBs, offset);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return err;
+}
+
+
+/**
* \brief Determine additional buffer fullness contraint due to burst data reception.
* The parameter TPDEC_PARAM_BURSTPERIOD must have been set as a precondition.
* \param hTp transport decoder handle.
@@ -432,51 +507,152 @@ TRANSPORTDEC_ERROR additionalHoldOffNeeded(
}
}
-/**
- * \brief adjust bit stream position and the end of an access unit.
- * \param hTp transport decoder handle.
- * \return error code.
- */
-static
-TRANSPORTDEC_ERROR transportDec_AdjustEndOfAccessUnit(HANDLE_TRANSPORTDEC hTp)
+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
+ )
{
- HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0];
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_LOAS:
- case TT_MP4_LATM_MCP0:
- case TT_MP4_LATM_MCP1:
- if ( hTp->numberOfRawDataBlocks == 0 )
+ case TT_MP4_ADTS:
+ if (hTp->numberOfRawDataBlocks <= 0)
{
- /* Check global frame length */
- if (hTp->transportFmt == TT_MP4_LOAS && hTp->parser.latm.m_audioMuxLengthBytes > 0)
- {
- int loasOffset;
+ int errC;
- loasOffset = (hTp->parser.latm.m_audioMuxLengthBytes*8 + FDKgetValidBits(hBs)) - hTp->globalFramePos;
- if (loasOffset != 0) {
- FDKpushBiDirectional(hBs, loasOffset);
- /* For ELD and other payloads there is an unknown amount of padding, so ignore unread bits, but
- throw an error only if too many bits where read. */
- if (loasOffset < 0) {
- err = TRANSPORTDEC_PARSE_ERROR;
+ 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);
- /* Do global LOAS/LATM audioMuxElement byte alignment */
- FDKbyteAlign(hBs, hTp->globalFramePos);
+ 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;
}
-
/* How many bits to advance for synchronization search. */
#define TPDEC_SYNCSKIP 8
@@ -493,9 +669,9 @@ TRANSPORTDEC_ERROR synchronization(
INT rawDataBlockLength = 0, rawDataBlockLengthPrevious;
INT totalBits;
INT headerBits = 0, headerBitsFirstFrame = 0, headerBitsPrevious;
- INT numFramesTraversed = 0, fTraverseMoreFrames, fConfigFound = 0, startPos, startPosFirstFrame = -1;
+ 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_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK);
+ INT ignoreBufferFullness = hTp->flags & (TPDEC_LOST_FRAMES_PENDING|TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK);
/* Synch parameters */
INT syncLength; /* Length of sync word in bits */
@@ -506,10 +682,7 @@ TRANSPORTDEC_ERROR synchronization(
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;
+ err = TRANSPORTDEC_NOT_ENOUGH_BITS;
goto bail;
}
@@ -579,100 +752,22 @@ TRANSPORTDEC_ERROR synchronization(
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;
- }
+ err = transportDec_readHeader(
+ hTp,
+ hBs,
+ syncLength,
+ ignoreBufferFullness,
+ &rawDataBlockLength,
+ &fTraverseMoreFrames,
+ &syncLayerFrameBits,
+ &fConfigFound,
+ &headerBits
+ );
}
- headerBits += startPos - (INT)FDKgetValidBits(hBs);
bitsAvail -= headerBits;
checkLengthBits = syncLayerFrameBits;
@@ -702,12 +797,12 @@ TRANSPORTDEC_ERROR synchronization(
/* Enforce re-sync of transport headers. */
hTp->numberOfRawDataBlocks = 0;
- /* Ensure that the bit amount lands and a multiple of TPDEC_SYNCSKIP */
+ /* 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;
+ headerBits = 0;
}
/* Frame traversal */
@@ -731,7 +826,15 @@ TRANSPORTDEC_ERROR synchronization(
}
/* Break when config was found or it is not possible anymore to find a config */
- if (startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK)) {
+ 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;
}
}
@@ -759,7 +862,7 @@ TRANSPORTDEC_ERROR synchronization(
}
/* Additional burst data mode buffer fullness check. */
- if ( !(hTp->flags & (TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK)) && err == TRANSPORTDEC_OK) {
+ 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++;
@@ -789,10 +892,22 @@ TRANSPORTDEC_ERROR synchronization(
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;
}
@@ -925,6 +1040,10 @@ TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, c
hBs = &hTp->bitStream[layer];
+ if ((INT)FDKgetValidBits(hBs) <= 0) {
+ err = TRANSPORTDEC_NOT_ENOUGH_BITS;
+ }
+
switch (hTp->transportFmt) {
case TT_MP4_ADIF:
@@ -964,20 +1083,26 @@ TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, c
break;
case TT_MP4_RAW:
- if ((INT)FDKgetValidBits(hBs) <= 0 && layer == 0) {
- err = TRANSPORTDEC_NOT_ENOUGH_BITS;
- }
/* One Access Unit was filled into buffer.
So get the length out of the buffer. */
hTp->auLength[layer] = FDKgetValidBits(hBs);
hTp->flags |= TPDEC_SYNCOK;
break;
+ case TT_MP4_LATM_MCP0:
+ case TT_MP4_LATM_MCP1:
+ {
+ int fConfigFound = hTp->flags & TPDEC_CONFIG_FOUND;
+ err = transportDec_readHeader(hTp, hBs, 0, 1, &hTp->auLength[layer], NULL, NULL, &fConfigFound, NULL);
+ if (fConfigFound) {
+ hTp->flags |= TPDEC_CONFIG_FOUND;
+ }
+ }
+ break;
+
case TT_RSVD50:
case TT_MP4_ADTS:
case TT_MP4_LOAS:
- case TT_MP4_LATM_MCP0:
- case TT_MP4_LATM_MCP1:
err = transportDec_readStream(hTp, layer);
break;
@@ -1026,13 +1151,10 @@ TRANSPORTDEC_ERROR transportDec_EndAccessUnit(HANDLE_TRANSPORTDEC hTp)
{
TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK;
+
err = transportDec_AdjustEndOfAccessUnit(hTp);
switch (hTp->transportFmt) {
- case TT_MP4_LOAS:
- case TT_MP4_LATM_MCP0:
- case TT_MP4_LATM_MCP1:
- break;
default:
break;
}
@@ -1082,8 +1204,11 @@ TRANSPORTDEC_ERROR transportDec_SetParam ( const HANDLE_TRANSPORTDEC hTp,
FDKresetBitbuffer(&hTp->bitStream[i]);
hTp->auLength[i] = 0;
hTp->accessUnitAnchor[i] = 0;
- }
+ }
hTp->flags &= ~(TPDEC_SYNCOK|TPDEC_LOST_FRAMES_PENDING);
+ if (hTp->transportFmt != TT_MP4_ADIF) {
+ hTp->flags &= ~TPDEC_CONFIG_FOUND;
+ }
hTp->remainder = 0;
hTp->avgBitRate = 0;
hTp->missingAccessUnits = 0;
@@ -1117,7 +1242,7 @@ void transportDec_Close(HANDLE_TRANSPORTDEC *phTp)
if (phTp != NULL)
{
if (*phTp != NULL) {
- if ((*phTp)->transportFmt != TT_MP4_RAW && (*phTp)->transportFmt != TT_DRM) {
+ if ( ! TT_IS_PACKET((*phTp)->transportFmt) ) {
FreeRam_TransportDecoderBuffer(&(*phTp)->bsBuffer);
}
if (*phTp != NULL) {
@@ -1188,13 +1313,8 @@ TRANSPORTDEC_ERROR transportDec_CrcCheck(HANDLE_TRANSPORTDEC pTp)
if ( (pTp->parser.adts.bs.num_raw_blocks > 0) && (pTp->parser.adts.bs.protection_absent == 0) )
{
HANDLE_FDK_BITSTREAM hBs = &pTp->bitStream[0];
- int bitDiff;
- /* Calculate possible offset to CRC value. */
- bitDiff = pTp->parser.adts.rawDataBlockDist[pTp->parser.adts.bs.num_raw_blocks-pTp->numberOfRawDataBlocks]<<3;
- bitDiff -= pTp->globalFramePos - FDKgetValidBits(hBs) + 16;
- FDKpushBiDirectional(hBs, bitDiff);
- pTp->parser.adts.crcReadValue = FDKreadBits(hBs, 16);
+ transportDec_AdjustEndOfAccessUnit(pTp);
}
return adtsRead_CrcCheck(&pTp->parser.adts);
default:
diff --git a/libMpegTPDec/src/version b/libMpegTPDec/src/version
index d998903..91c4c67 100644
--- a/libMpegTPDec/src/version
+++ b/libMpegTPDec/src/version
@@ -2,7 +2,7 @@
/* library info */
#define TP_LIB_VL0 2
#define TP_LIB_VL1 3
-#define TP_LIB_VL2 1
+#define TP_LIB_VL2 2
#define TP_LIB_TITLE "MPEG Transport"
#define TP_LIB_BUILD_DATE __DATE__
#define TP_LIB_BUILD_TIME __TIME__