summaryrefslogtreecommitdiffstats
path: root/libMpegTPDec/src
diff options
context:
space:
mode:
Diffstat (limited to 'libMpegTPDec/src')
-rw-r--r--libMpegTPDec/src/Android.mk21
-rw-r--r--libMpegTPDec/src/mpegFileFormat.h52
-rw-r--r--libMpegTPDec/src/tpdec_adif.cpp93
-rw-r--r--libMpegTPDec/src/tpdec_adif.h61
-rw-r--r--libMpegTPDec/src/tpdec_adts.cpp326
-rw-r--r--libMpegTPDec/src/tpdec_adts.h174
-rw-r--r--libMpegTPDec/src/tpdec_asc.cpp867
-rw-r--r--libMpegTPDec/src/tpdec_latm.cpp364
-rw-r--r--libMpegTPDec/src/tpdec_latm.h103
-rw-r--r--libMpegTPDec/src/tpdec_lib.cpp1127
-rw-r--r--libMpegTPDec/src/version8
11 files changed, 3196 insertions, 0 deletions
diff --git a/libMpegTPDec/src/Android.mk b/libMpegTPDec/src/Android.mk
new file mode 100644
index 0000000..ae9096d
--- /dev/null
+++ b/libMpegTPDec/src/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ tpdec_adif.cpp \
+ tpdec_adts.cpp \
+ tpdec_asc.cpp \
+ tpdec_latm.cpp \
+ tpdec_lib.cpp
+
+LOCAL_CFLAGS := -DANDROID
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../../libSYS/include \
+ $(LOCAL_PATH)/../../libFDK/include
+
+LOCAL_MODULE:= libMpegTPDec
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libMpegTPDec/src/mpegFileFormat.h b/libMpegTPDec/src/mpegFileFormat.h
new file mode 100644
index 0000000..d780832
--- /dev/null
+++ b/libMpegTPDec/src/mpegFileFormat.h
@@ -0,0 +1,52 @@
+/*************************** Fraunhofer IIS FDK Tools ***********************
+
+ (C) Copyright Fraunhofer IIS (2006)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Oliver Moser
+ Description: bitstream format detection routines
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#if !defined(__BITSTREAM_FORMAT_H__)
+#define __BITSTREAM_FORMAT_H__
+
+#include "machine_type.h"
+#include "FDK_audio.h"
+
+/**
+ * \brief Try to find out the format of a file, given the few first bytes.
+ * \param fileData pointer to a buffer holding the first bytes of a file.
+ * \param pAu pointer to UCHAR*, returns the address of the first AU found or NULL.
+ * \param length pointer to the length of the buffer fileData. Return length of first AU.
+ * \return the detected file format, or FF_UNKNOWN in case of failure.
+ */
+FILE_FORMAT GetFileFormat(UCHAR *fileData, UCHAR **pAu, UINT *length);
+
+/**
+ * \brief Try to find out the transport type contained in a given file.
+ * \param filename name of the file to be analysed.
+ * \param fileFormat pointer to a variable where the detected file format is stored into.
+ * \return the detected transport type or TT_UNKNOWN in case of failure.
+ */
+TRANSPORT_TYPE GetTransportType(const char* filename, FILE_FORMAT *fileFormat);
+
+#endif
diff --git a/libMpegTPDec/src/tpdec_adif.cpp b/libMpegTPDec/src/tpdec_adif.cpp
new file mode 100644
index 0000000..7c47ea3
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_adif.cpp
@@ -0,0 +1,93 @@
+/***************************** MPEG-4 AAC Decoder **************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Josef Hoepfl
+ Description: ADIF reader
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#include "tpdec_adif.h"
+
+
+#include "FDK_bitstream.h"
+#include "genericStds.h"
+
+TRANSPORTDEC_ERROR adifRead_DecodeHeader(
+ CAdifHeader *pAdifHeader,
+ CProgramConfig *pPce,
+ HANDLE_FDK_BITSTREAM bs
+ )
+{
+ int i;
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+ UINT startAnchor = FDKgetValidBits(bs);
+
+ if ((INT)startAnchor < MIN_ADIF_HEADERLENGTH) {
+ return (TRANSPORTDEC_NOT_ENOUGH_BITS);
+ }
+
+ if (FDKreadBits(bs,8) != 'A') {
+ return (TRANSPORTDEC_SYNC_ERROR);
+ }
+ if (FDKreadBits(bs,8) != 'D') {
+ return (TRANSPORTDEC_SYNC_ERROR);
+ }
+ if (FDKreadBits(bs,8) != 'I') {
+ return (TRANSPORTDEC_SYNC_ERROR);
+ }
+ if (FDKreadBits(bs,8) != 'F') {
+ return (TRANSPORTDEC_SYNC_ERROR);
+ }
+
+ if ( (pAdifHeader->CopyrightIdPresent = FDKreadBits(bs,1)) != 0 )
+ FDKpushBiDirectional(bs,72); /* CopyrightId */
+
+
+ pAdifHeader->OriginalCopy = FDKreadBits(bs,1);
+ pAdifHeader->Home = FDKreadBits(bs,1);
+ pAdifHeader->BitstreamType = FDKreadBits(bs,1);
+
+ /* pAdifHeader->BitRate = FDKreadBits(bs, 23); */
+ pAdifHeader->BitRate = FDKreadBits(bs,16);
+ pAdifHeader->BitRate <<= 7;
+ pAdifHeader->BitRate |= FDKreadBits(bs,7);
+
+ pAdifHeader->NumProgramConfigElements = FDKreadBits(bs,4) + 1;
+
+ if (pAdifHeader->BitstreamType == 0) {
+ FDKpushBiDirectional(bs,20); /* adif_buffer_fullness */
+ }
+
+ /* Parse all PCEs but keep only one */
+ for (i=0; i < pAdifHeader->NumProgramConfigElements; i++)
+ {
+ CProgramConfig_Read(pPce, bs, startAnchor);
+ }
+
+ FDKbyteAlign(bs, startAnchor);
+
+ return (ErrorStatus);
+}
+
+
+
diff --git a/libMpegTPDec/src/tpdec_adif.h b/libMpegTPDec/src/tpdec_adif.h
new file mode 100644
index 0000000..30c2084
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_adif.h
@@ -0,0 +1,61 @@
+/***************************** MPEG-4 AAC Decoder **************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Josef Hoepfl
+ Description: ADIF reader
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#ifndef TPDEC_ADIF_H
+#define TPDEC_ADIF_H
+
+#include "tpdec_lib.h"
+
+#define MIN_ADIF_HEADERLENGTH 63 /* in bits */
+
+typedef struct
+{
+ INT NumProgramConfigElements;
+ UINT BitRate;
+ UCHAR CopyrightIdPresent;
+ UCHAR OriginalCopy;
+ UCHAR Home;
+ UCHAR BitstreamType;
+} CAdifHeader;
+
+/**
+ * \brief Parse a ADIF header at the given bitstream and store the parsed data into a given CAdifHeader
+ * and CProgramConfig struct
+ *
+ * \param pAdifHeader pointer to a CAdifHeader structure to hold the parsed ADIF header data.
+ * \param pPce pointer to a CProgramConfig structure where the last PCE will remain.
+ *
+ * \return TRANSPORTDEC_ERROR error code
+ */
+TRANSPORTDEC_ERROR adifRead_DecodeHeader(
+ CAdifHeader *pAdifHeader,
+ CProgramConfig *pPce,
+ HANDLE_FDK_BITSTREAM bs
+ );
+
+#endif /* TPDEC_ADIF_H */
diff --git a/libMpegTPDec/src/tpdec_adts.cpp b/libMpegTPDec/src/tpdec_adts.cpp
new file mode 100644
index 0000000..e64ae82
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_adts.cpp
@@ -0,0 +1,326 @@
+/***************************** MPEG-4 AAC Decoder **************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Josef Hoepfl
+ Description: ADTS interface
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#include "tpdec_adts.h"
+
+
+#include "FDK_bitstream.h"
+
+
+
+void adtsRead_CrcInit(HANDLE_ADTS pAdts) /*!< pointer to adts crc info stucture */
+{
+ FDKcrcInit(&pAdts->crcInfo, 0x8005, 0xFFFF, 16);
+}
+
+int adtsRead_CrcStartReg(
+ HANDLE_ADTS pAdts, /*!< pointer to adts stucture */
+ HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */
+ int mBits /*!< number of bits in crc region */
+ )
+{
+ if (pAdts->bs.protection_absent) {
+ return 0;
+ }
+
+ return ( FDKcrcStartReg(&pAdts->crcInfo, hBs, mBits) );
+
+}
+
+void adtsRead_CrcEndReg(
+ HANDLE_ADTS pAdts, /*!< pointer to adts crc info stucture */
+ HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */
+ int reg /*!< crc region */
+ )
+{
+ if (pAdts->bs.protection_absent == 0)
+ {
+ FDKcrcEndReg(&pAdts->crcInfo, hBs, reg);
+ }
+}
+
+TRANSPORTDEC_ERROR adtsRead_CrcCheck( HANDLE_ADTS pAdts )
+{
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+ USHORT crc;
+
+ if (pAdts->bs.protection_absent)
+ return TRANSPORTDEC_OK;
+
+ crc = FDKcrcGetCRC(&pAdts->crcInfo);
+ if (crc != pAdts->crcReadValue)
+ {
+ return (TRANSPORTDEC_CRC_ERROR);
+ }
+
+ return (ErrorStatus);
+}
+
+
+
+#define Adts_Length_SyncWord 12
+#define Adts_Length_Id 1
+#define Adts_Length_Layer 2
+#define Adts_Length_ProtectionAbsent 1
+#define Adts_Length_Profile 2
+#define Adts_Length_SamplingFrequencyIndex 4
+#define Adts_Length_PrivateBit 1
+#define Adts_Length_ChannelConfiguration 3
+#define Adts_Length_OriginalCopy 1
+#define Adts_Length_Home 1
+#define Adts_Length_CopyrightIdentificationBit 1
+#define Adts_Length_CopyrightIdentificationStart 1
+#define Adts_Length_FrameLength 13
+#define Adts_Length_BufferFullness 11
+#define Adts_Length_NumberOfRawDataBlocksInFrame 2
+#define Adts_Length_CrcCheck 16
+
+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);
+
+ /* 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;
+}
+
+int adtsRead_GetRawDataBlockLength(
+ HANDLE_ADTS pAdts,
+ INT blockNum
+ )
+{
+ int length;
+
+ if (pAdts->bs.num_raw_blocks == 0) {
+ length = (pAdts->bs.frame_length - 7) << 3; /* aac_frame_length subtracted by the header size (7 bytes). */
+ if (pAdts->bs.protection_absent == 0)
+ length -= 16; /* substract 16 bit CRC */
+ } else {
+ if (pAdts->bs.protection_absent) {
+ length = -1; /* raw data block length is unknown */
+ } else {
+ if (blockNum < 0 || blockNum > 3) {
+ return TRANSPORTDEC_INVALID_PARAMETER;
+ }
+ length = (pAdts->rawDataBlockDist[blockNum] << 3) - 16;
+ }
+ }
+ if (blockNum == 0) {
+ length -= pAdts->bs.num_pce_bits;
+ }
+ return length;
+}
+
+
diff --git a/libMpegTPDec/src/tpdec_adts.h b/libMpegTPDec/src/tpdec_adts.h
new file mode 100644
index 0000000..13c66a4
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_adts.h
@@ -0,0 +1,174 @@
+/***************************** MPEG-4 AAC Decoder **************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Josef Hoepfl
+ Description: ADTS interface
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#ifndef TPDEC_ADTS_H
+#define TPDEC_ADTS_H
+
+#include "tpdec_lib.h"
+
+
+#define ADTS_SYNCWORD ( 0xfff )
+#define ADTS_SYNCLENGTH ( 12 ) /* in bits */
+#define ADTS_HEADERLENGTH ( 56 ) /* minimum header size in bits */
+#define ADTS_FIXED_HEADERLENGTH ( 28 ) /* in bits */
+#define ADTS_VARIABLE_HEADERLENGTH ( ADTS_HEADERLENGTH - ADTS_FIXED_HEADERLENGTH )
+
+#ifdef CHECK_TWO_SYNCS
+ #define ADTS_MIN_TP_BUF_SIZE ( 8191 + 2 )
+#else
+ #define ADTS_MIN_TP_BUF_SIZE ( 8191 )
+#endif
+
+#include "FDK_crc.h"
+
+typedef struct {
+ /* ADTS header fields */
+ UCHAR mpeg_id;
+ UCHAR layer;
+ UCHAR protection_absent;
+ UCHAR profile;
+ UCHAR sample_freq_index;
+ UCHAR private_bit;
+ UCHAR channel_config;
+ UCHAR original;
+ UCHAR home;
+ UCHAR copyright_id;
+ UCHAR copyright_start;
+ USHORT frame_length;
+ USHORT adts_fullness;
+ UCHAR num_raw_blocks;
+ UCHAR num_pce_bits;
+} STRUCT_ADTS_BS;
+
+struct STRUCT_ADTS {
+
+ STRUCT_ADTS_BS bs;
+
+ UCHAR decoderCanDoMpeg4;
+ UCHAR BufferFullnesStartFlag;
+
+ FDK_CRCINFO crcInfo; /* CRC state info */
+ USHORT crcReadValue; /* CRC value read from bitstream data */
+ USHORT rawDataBlockDist[4]; /* distance between each raw data block. Not the same as found in the bitstream */
+} ;
+
+typedef struct STRUCT_ADTS *HANDLE_ADTS;
+
+/*!
+ \brief Initialize ADTS CRC
+
+ The function initialzes the crc buffer and the crc lookup table.
+
+ \return none
+*/
+void adtsRead_CrcInit( HANDLE_ADTS pAdts );
+
+/**
+ * \brief Starts CRC region with a maximum number of bits
+ * If mBits is positive zero padding will be used for CRC calculation, if there
+ * are less than mBits bits available.
+ * If mBits is negative no zero padding is done.
+ * If mBits is zero the memory for the buffer is allocated dynamically, the
+ * number of bits is not limited.
+ *
+ * \param pAdts ADTS data handle
+ * \param hBs bitstream handle, on which the CRC region referes to
+ * \param mBits max number of bits in crc region to be considered
+ *
+ * \return ID for the created region, -1 in case of an error
+ */
+int adtsRead_CrcStartReg(
+ HANDLE_ADTS pAdts,
+ HANDLE_FDK_BITSTREAM hBs,
+ int mBits
+ );
+
+/**
+ * \brief Ends CRC region identified by reg
+ *
+ * \param pAdts ADTS data handle
+ * \param hBs bitstream handle, on which the CRC region referes to
+ * \param reg CRC regions ID returned by adtsRead_CrcStartReg()
+ *
+ * \return none
+ */
+void adtsRead_CrcEndReg(
+ HANDLE_ADTS pAdts,
+ HANDLE_FDK_BITSTREAM hBs,
+ int reg
+ );
+
+/**
+ * \brief Check CRC
+ *
+ * Checks if the currently calculated CRC matches the CRC field read from the bitstream
+ * Deletes all CRC regions.
+ *
+ * \param pAdts ADTS data handle
+ *
+ * \return Returns 0 if they are identical otherwise 1
+ */
+TRANSPORTDEC_ERROR adtsRead_CrcCheck( HANDLE_ADTS pAdts );
+
+
+/**
+ * \brief Check if we have a valid ADTS frame at the current bitbuffer position
+ *
+ * This function assumes enough bits in buffer for the current frame.
+ * It reads out the header bits to prepare the bitbuffer for the decode loop.
+ * In case the header bits show an invalid bitstream/frame, the whole frame is skipped.
+ *
+ * \param pAdts ADTS data handle which is filled with parsed ADTS header data
+ * \param bs handle of bitstream from whom the ADTS header is read
+ *
+ * \return error status
+ */
+TRANSPORTDEC_ERROR adtsRead_DecodeHeader(
+ HANDLE_ADTS pAdts,
+ CSAudioSpecificConfig *pAsc,
+ HANDLE_FDK_BITSTREAM bs,
+ const INT ignoreBufferFullness
+ );
+
+/**
+ * \brief Get the raw data block length of the given block number.
+ *
+ * \param pAdts ADTS data handle
+ * \param blockNum current raw data block index
+ * \param pLength pointer to an INT where the length of the given raw data block is stored into
+ * the returned value might be -1, in which case the raw data block length is unknown.
+ *
+ * \return error status
+ */
+int adtsRead_GetRawDataBlockLength(
+ HANDLE_ADTS pAdts,
+ INT blockNum
+ );
+
+
+#endif /* TPDEC_ADTS_H */
diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
new file mode 100644
index 0000000..ee7c7cf
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_asc.cpp
@@ -0,0 +1,867 @@
+/***************************** MPEG-4 AAC Decoder **************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Daniel Homm
+ Description:
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#include "tpdec_lib.h"
+#include "tp_data.h"
+
+
+void CProgramConfig_Reset(CProgramConfig *pPce)
+{
+ pPce->elCounter = 0;
+}
+
+void CProgramConfig_Init(CProgramConfig *pPce)
+{
+ FDKmemclear(pPce, sizeof(CProgramConfig));
+#ifdef TP_PCE_ENABLE
+ pPce->SamplingFrequencyIndex = 0xf;
+#endif
+}
+
+int CProgramConfig_IsValid ( const CProgramConfig *pPce )
+{
+ return ( (pPce->isValid) ? 1 : 0);
+}
+
+#ifdef TP_PCE_ENABLE
+void CProgramConfig_Read(
+ CProgramConfig *pPce,
+ HANDLE_FDK_BITSTREAM bs,
+ UINT alignmentAnchor
+ )
+{
+ int i;
+
+ pPce->NumEffectiveChannels = 0;
+ pPce->NumChannels = 0;
+ pPce->ElementInstanceTag = (UCHAR) FDKreadBits(bs,4);
+ pPce->Profile = (UCHAR) FDKreadBits(bs,2);
+ pPce->SamplingFrequencyIndex = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumFrontChannelElements = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumSideChannelElements = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumBackChannelElements = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumLfeChannelElements = (UCHAR) FDKreadBits(bs,2);
+ pPce->NumAssocDataElements = (UCHAR) FDKreadBits(bs,3);
+ pPce->NumValidCcElements = (UCHAR) FDKreadBits(bs,4);
+
+ if ((pPce->MonoMixdownPresent = (UCHAR) FDKreadBits(bs,1)) != 0)
+ {
+ pPce->MonoMixdownElementNumber = (UCHAR) FDKreadBits(bs,4);
+ }
+
+ if ((pPce->StereoMixdownPresent = (UCHAR) FDKreadBits(bs,1)) != 0)
+ {
+ pPce->StereoMixdownElementNumber = (UCHAR) FDKreadBits(bs,4);
+ }
+
+ if ((pPce->MatrixMixdownIndexPresent = (UCHAR) FDKreadBits(bs,1)) != 0)
+ {
+ pPce->MatrixMixdownIndex = (UCHAR) FDKreadBits(bs,2);
+ pPce->PseudoSurroundEnable = (UCHAR) FDKreadBits(bs,1);
+ }
+
+ for (i=0; i < pPce->NumFrontChannelElements; i++)
+ {
+ pPce->FrontElementIsCpe[i] = (UCHAR) FDKreadBits(bs,1);
+ pPce->FrontElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1;
+ }
+
+ for (i=0; i < pPce->NumSideChannelElements; i++)
+ {
+ pPce->SideElementIsCpe[i] = (UCHAR) FDKreadBits(bs,1);
+ pPce->SideElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1;
+ }
+
+ for (i=0; i < pPce->NumBackChannelElements; i++)
+ {
+ pPce->BackElementIsCpe[i] = (UCHAR) FDKreadBits(bs,1);
+ pPce->BackElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1;
+ }
+
+ pPce->NumEffectiveChannels = pPce->NumChannels;
+
+ for (i=0; i < pPce->NumLfeChannelElements; i++)
+ {
+ pPce->LfeElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4);
+ pPce->NumChannels += 1;
+ }
+
+ for (i=0; i < pPce->NumAssocDataElements; i++)
+ {
+ pPce->AssocDataElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4);
+ }
+
+ for (i=0; i < pPce->NumValidCcElements; i++)
+ {
+ pPce->CcElementIsIndSw[i] = (UCHAR) FDKreadBits(bs,1);
+ pPce->ValidCcElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4);
+ }
+
+ FDKbyteAlign(bs, alignmentAnchor);
+
+ pPce->CommentFieldBytes = (UCHAR) FDKreadBits(bs,8);
+
+ for (i=0; i < pPce->CommentFieldBytes; i++)
+ {
+ UCHAR text;
+
+ text = (UCHAR)FDKreadBits(bs,8);
+
+ if (i < PC_COMMENTLENGTH)
+ {
+ pPce->Comment[i] = text;
+ }
+ }
+
+ pPce->isValid = 1;
+}
+#endif /* TP_PCE_ENABLE */
+
+/**
+ * \brief get implicit audio channel type for given channelConfig and MPEG ordered channel index
+ * \param channelConfig MPEG channelConfiguration from 1 upto 7
+ * \param index MPEG channel order index
+ * \return audio channel type.
+ */
+void getImplicitAudioChannelTypeAndIndex(
+ AUDIO_CHANNEL_TYPE *chType,
+ UCHAR *chIndex,
+ UINT channelConfig,
+ UINT index
+ )
+{
+ if (index < 3) {
+ *chType = ACT_FRONT;
+ *chIndex = index;
+ } else {
+ switch (channelConfig) {
+ case MODE_1_2_1:
+ case MODE_1_2_2:
+ case MODE_1_2_2_1:
+ switch (index) {
+ case 3:
+ case 4:
+ *chType = ACT_BACK;
+ *chIndex = index - 3;
+ break;
+ case 5:
+ *chType = ACT_LFE;
+ *chIndex = 0;
+ break;
+ }
+ break;
+ case MODE_1_2_2_2_1:
+ switch (index) {
+ case 3:
+ case 4:
+ *chType = ACT_SIDE;
+ *chIndex = index - 3;
+ break;
+ case 5:
+ case 6:
+ *chType = ACT_BACK;
+ *chIndex = index - 5;
+ break;
+ case 7:
+ *chType = ACT_LFE;
+ *chIndex = 0;
+ break;
+ }
+ break;
+ default:
+ *chType = ACT_NONE;
+ break;
+ }
+ }
+}
+
+int CProgramConfig_LookupElement(
+ CProgramConfig *pPce,
+ const UINT channelConfig,
+ const UINT tag,
+ const UINT channelIdx,
+ UCHAR chMapping[],
+ AUDIO_CHANNEL_TYPE chType[],
+ UCHAR chIndex[],
+ UCHAR *elMapping,
+ MP4_ELEMENT_ID elList[],
+ MP4_ELEMENT_ID elType
+ )
+{
+ if (channelConfig > 0)
+ {
+ /* Constant channel mapping must have
+ been set during initialization. */
+ if ( elType == ID_SCE
+ || elType == ID_CPE
+ || elType == ID_LFE )
+ {
+ *elMapping = pPce->elCounter;
+ if (elList[pPce->elCounter] != elType) {
+ /* Not in the list */
+ return 0;
+ }
+ /* Assume all front channels */
+ getImplicitAudioChannelTypeAndIndex(&chType[channelIdx], &chIndex[channelIdx], channelConfig, channelIdx);
+ if (elType == ID_CPE) {
+ chType[channelIdx+1] = chType[channelIdx];
+ chIndex[channelIdx+1] = chIndex[channelIdx]+1;
+ }
+ pPce->elCounter++;
+ }
+ /* Accept all non-channel elements, too. */
+ return 1;
+ }
+ else
+ {
+#ifdef TP_PCE_ENABLE
+ if (!pPce->isValid)
+#endif /* TP_PCE_ENABLE */
+ {
+ /* Implicit channel mapping. */
+ if ( elType == ID_SCE
+ || elType == ID_CPE
+ || elType == ID_LFE )
+ {
+ /* Store all channel element IDs */
+ elList[pPce->elCounter] = elType;
+ *elMapping = pPce->elCounter++;
+ }
+ }
+#ifdef TP_PCE_ENABLE
+ else {
+ /* Accept the additional channel(s), only if the tag is in the lists */
+ int isCpe = 0, i;
+ int cc = 0, fc = 0, sc = 0, bc = 0, lc = 0, ec = 0; /* Channel and element counters */
+
+ switch (elType)
+ {
+ case ID_CPE:
+ isCpe = 1;
+ case ID_SCE:
+ /* search in front channels */
+ for (i = 0; i < pPce->NumFrontChannelElements; i++) {
+ if (isCpe == pPce->FrontElementIsCpe[i] && pPce->FrontElementTagSelect[i] == tag) {
+ chMapping[cc] = channelIdx;
+ chType[cc] = ACT_FRONT;
+ chIndex[cc] = fc;
+ if (isCpe) {
+ chMapping[cc+1] = channelIdx+1;
+ chType[cc+1] = ACT_FRONT;
+ chIndex[cc+1] = fc+1;
+ }
+ *elMapping = ec;
+ return 1;
+ }
+ ec++;
+ if (pPce->FrontElementIsCpe[i]) {
+ cc+=2; fc+=2;
+ } else {
+ cc++; fc++;
+ }
+ }
+ /* search in side channels */
+ for (i = 0; i < pPce->NumSideChannelElements; i++) {
+ if (isCpe == pPce->SideElementIsCpe[i] && pPce->SideElementTagSelect[i] == tag) {
+ chMapping[cc] = channelIdx;
+ chType[cc] = ACT_SIDE;
+ chIndex[cc] = sc;
+ if (isCpe) {
+ chMapping[cc+1] = channelIdx+1;
+ chType[cc+1] = ACT_SIDE;
+ chIndex[cc+1] = sc+1;
+ }
+ *elMapping = ec;
+ return 1;
+ }
+ ec++;
+ if (pPce->SideElementIsCpe[i]) {
+ cc+=2; sc+=2;
+ } else {
+ cc++; sc++;
+ }
+ }
+ /* search in back channels */
+ for (i = 0; i < pPce->NumBackChannelElements; i++) {
+ if (isCpe == pPce->BackElementIsCpe[i] && pPce->BackElementTagSelect[i] == tag) {
+ chMapping[cc] = channelIdx;
+ chType[cc] = ACT_BACK;
+ chIndex[cc] = bc;
+ if (isCpe) {
+ chMapping[cc+1] = channelIdx+1;
+ chType[cc+1] = ACT_BACK;
+ chIndex[cc+1] = bc+1;
+ }
+ *elMapping = ec;
+ return 1;
+ }
+ ec++;
+ if (pPce->BackElementIsCpe[i]) {
+ cc+=2; bc+=2;
+ } else {
+ cc++; bc++;
+ }
+ }
+ break;
+
+ case ID_LFE:
+ /* Initialize channel counter and element counter */
+ cc = pPce->NumEffectiveChannels;
+ ec = pPce->NumFrontChannelElements+ pPce->NumSideChannelElements + pPce->NumBackChannelElements;
+ /* search in lfe channels */
+ for (i = 0; i < pPce->NumLfeChannelElements; i++) {
+ if ( pPce->LfeElementTagSelect[i] == tag ) {
+ chMapping[cc] = channelIdx;
+ *elMapping = ec;
+ chType[cc] = ACT_LFE;
+ chIndex[cc] = lc;
+ return 1;
+ }
+ ec++;
+ cc++;
+ lc++;
+ }
+ break;
+
+ /* Non audio elements */
+ case ID_CCE:
+ /* search in cce channels */
+ for (i = 0; i < pPce->NumValidCcElements; i++) {
+ if (pPce->ValidCcElementTagSelect[i] == tag) {
+ return 1;
+ }
+ }
+ break;
+ case ID_DSE:
+ /* search associated data elements */
+ for (i = 0; i < pPce->NumAssocDataElements; i++) {
+ if (pPce->AssocDataElementTagSelect[i] == tag) {
+ return 1;
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 0; /* not found in any list */
+ }
+#endif /* TP_PCE_ENABLE */
+ }
+
+ return 1;
+}
+
+#ifdef TP_PCE_ENABLE
+int CProgramConfig_GetElementTable(
+ const CProgramConfig *pPce,
+ MP4_ELEMENT_ID elList[]
+ )
+{
+ int i, el = 0;
+
+ for (i=0; i < pPce->NumFrontChannelElements; i++)
+ {
+ elList[el++] = (pPce->FrontElementIsCpe[i]) ? ID_CPE : ID_SCE;
+ }
+
+ for (i=0; i < pPce->NumSideChannelElements; i++)
+ {
+ elList[el++] = (pPce->SideElementIsCpe[i]) ? ID_CPE : ID_SCE;
+ }
+
+ for (i=0; i < pPce->NumBackChannelElements; i++)
+ {
+ elList[el++] = (pPce->BackElementIsCpe[i]) ? ID_CPE : ID_SCE;
+ }
+
+ for (i=0; i < pPce->NumLfeChannelElements; i++)
+ {
+ elList[el++] = ID_LFE;
+ }
+
+
+ return el;
+}
+#endif
+
+static AUDIO_OBJECT_TYPE getAOT(HANDLE_FDK_BITSTREAM bs)
+{
+ int tmp = 0;
+
+ tmp = FDKreadBits(bs,5);
+ if (tmp == AOT_ESCAPE) {
+ int tmp2 = FDKreadBits(bs,6);
+ tmp = 32 + tmp2;
+ }
+
+ return (AUDIO_OBJECT_TYPE)tmp;
+}
+
+static INT getSampleRate(HANDLE_FDK_BITSTREAM bs, UCHAR *index, int nBits)
+{
+ INT sampleRate;
+ int idx;
+
+ idx = FDKreadBits(bs, nBits);
+ if( idx == (1<<nBits)-1 ) {
+ if(FDKgetValidBits(bs) < 24) {
+ return 0;
+ }
+ sampleRate = FDKreadBits(bs,24);
+ } else {
+ sampleRate = SamplingRateTable[idx];
+ }
+
+ *index = idx;
+
+ return sampleRate;
+}
+
+#ifdef TP_GA_ENABLE
+static
+TRANSPORTDEC_ERROR GaSpecificConfig_Parse( CSGaSpecificConfig *self,
+ CSAudioSpecificConfig *asc,
+ HANDLE_FDK_BITSTREAM bs,
+ UINT ascStartAnchor )
+{
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+
+ self->m_frameLengthFlag = FDKreadBits(bs,1);
+
+ self->m_dependsOnCoreCoder = FDKreadBits(bs,1);
+
+ if( self->m_dependsOnCoreCoder )
+ self->m_coreCoderDelay = FDKreadBits(bs,14);
+
+ self->m_extensionFlag = FDKreadBits(bs,1);
+
+ if( asc->m_channelConfiguration == 0 ) {
+ CProgramConfig_Read(&asc->m_progrConfigElement, bs, ascStartAnchor);
+ }
+
+ if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) {
+ self->m_layer = FDKreadBits(bs,3);
+ }
+
+ if (self->m_extensionFlag) {
+ if (asc->m_aot == AOT_ER_BSAC) {
+ self->m_numOfSubFrame = FDKreadBits(bs,5);
+ self->m_layerLength = FDKreadBits(bs,11);
+ }
+
+ if ((asc->m_aot == AOT_ER_AAC_LC) || (asc->m_aot == AOT_ER_AAC_LTP) ||
+ (asc->m_aot == AOT_ER_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_LD))
+ {
+ asc->m_vcb11Flag = FDKreadBits(bs,1); /* aacSectionDataResilienceFlag */
+ asc->m_rvlcFlag = FDKreadBits(bs,1); /* aacScalefactorDataResilienceFlag */
+ asc->m_hcrFlag = FDKreadBits(bs,1); /* aacSpectralDataResilienceFlag */
+ }
+
+ self->m_extensionFlag3 = FDKreadBits(bs,1);
+
+ }
+ return (ErrorStatus);
+}
+#endif /* TP_GA_ENABLE */
+
+
+
+
+
+#ifdef TP_ELD_ENABLE
+
+static INT ld_sbr_header( const CSAudioSpecificConfig *asc,
+ HANDLE_FDK_BITSTREAM hBs,
+ CSTpCallBacks *cb )
+{
+ const int channelConfiguration = asc->m_channelConfiguration;
+ int i = 0;
+ INT error = 0;
+
+ if (channelConfiguration == 2) {
+ error = cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
+ } else {
+ error = cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++);
+ }
+
+ switch ( channelConfiguration ) {
+ 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++);
+ break;
+ }
+
+ return error;
+}
+
+static
+TRANSPORTDEC_ERROR EldSpecificConfig_Parse(
+ CSAudioSpecificConfig *asc,
+ HANDLE_FDK_BITSTREAM hBs,
+ CSTpCallBacks *cb
+ )
+{
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+ CSEldSpecificConfig *esc = &asc->m_sc.m_eldSpecificConfig;
+ ASC_ELD_EXT_TYPE eldExtType;
+ int eldExtLen, len, cnt;
+
+ FDKmemclear(esc, sizeof(CSEldSpecificConfig));
+
+ esc->m_frameLengthFlag = FDKreadBits(hBs, 1 );
+ if (esc->m_frameLengthFlag) {
+ asc->m_samplesPerFrame = 480;
+ } else {
+ asc->m_samplesPerFrame = 512;
+ }
+
+ asc->m_vcb11Flag = FDKreadBits(hBs, 1 );
+ asc->m_rvlcFlag = FDKreadBits(hBs, 1 );
+ asc->m_hcrFlag = FDKreadBits(hBs, 1 );
+
+ esc->m_sbrPresentFlag = FDKreadBits(hBs, 1 );
+
+ if (esc->m_sbrPresentFlag == 1) {
+ esc->m_sbrSamplingRate = FDKreadBits(hBs, 1 ); /* 0: single rate, 1: dual rate */
+ esc->m_sbrCrcFlag = FDKreadBits(hBs, 1 );
+
+ asc->m_extensionSamplingFrequency = asc->m_samplingFrequency << esc->m_sbrSamplingRate;
+
+ if (cb->cbSbr != NULL){
+ if ( 0 != ld_sbr_header(asc, hBs, cb) ) {
+ return TRANSPORTDEC_PARSE_ERROR;
+ }
+ }
+ }
+ esc->m_useLdQmfTimeAlign = 0;
+
+ /* new ELD syntax */
+ /* parse ExtTypeConfigData */
+ while ((eldExtType = (ASC_ELD_EXT_TYPE)FDKreadBits(hBs, 4 )) != ELDEXT_TERM) {
+ eldExtLen = len = FDKreadBits(hBs, 4 );
+ if ( len == 0xf ) {
+ len = FDKreadBits(hBs, 8 );
+ eldExtLen += len;
+
+ if ( len == 0xff ) {
+ len = FDKreadBits(hBs, 16 );
+ eldExtLen += len;
+ }
+ }
+
+ switch (eldExtType) {
+ case ELDEXT_LDSAC:
+ esc->m_useLdQmfTimeAlign = 1;
+ if (cb->cbSsc != NULL) {
+ ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc(
+ cb->cbSscData,
+ hBs,
+ asc->m_aot,
+ asc->m_samplingFrequency,
+ 1, /* muxMode */
+ len
+ );
+ } else {
+ ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+ if (ErrorStatus != TRANSPORTDEC_OK) {
+ goto bail;
+ }
+ break;
+ default:
+ for(cnt=0; cnt<len; cnt++) {
+ FDKreadBits(hBs, 8 );
+ }
+ break;
+ /* add future eld extension configs here */
+ }
+ }
+bail:
+ return (ErrorStatus);
+}
+#endif /* TP_ELD_ENABLE */
+
+
+static
+TRANSPORTDEC_ERROR AudioSpecificConfig_ExtensionParse(CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, CSTpCallBacks *cb)
+{
+ TP_ASC_EXTENSION_ID lastAscExt, ascExtId = ASCEXT_UNKOWN;
+ INT bitsAvailable = (INT)FDKgetValidBits(bs);
+
+ while (bitsAvailable >= 11)
+ {
+ lastAscExt = ascExtId;
+ ascExtId = (TP_ASC_EXTENSION_ID)FDKreadBits(bs, 11);
+ bitsAvailable -= 11;
+
+ switch (ascExtId) {
+ case ASCEXT_SBR: /* 0x2b7 */
+ if ( (self->m_extensionAudioObjectType != AOT_SBR) && (bitsAvailable >= 5) ) {
+ self->m_extensionAudioObjectType = getAOT(bs);
+
+ if ( (self->m_extensionAudioObjectType == AOT_SBR)
+ || (self->m_extensionAudioObjectType == AOT_ER_BSAC) )
+ { /* Get SBR extension configuration */
+ self->m_sbrPresentFlag = FDKreadBits(bs, 1);
+ bitsAvailable -= 1;
+
+ if ( self->m_sbrPresentFlag == 1 ) {
+ self->m_extensionSamplingFrequency = getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4);
+
+ if ((INT)self->m_extensionSamplingFrequency <= 0) {
+ return TRANSPORTDEC_PARSE_ERROR;
+ }
+ }
+ if ( self->m_extensionAudioObjectType == AOT_ER_BSAC ) {
+ self->m_extensionChannelConfiguration = FDKreadBits(bs, 4);
+ bitsAvailable -= 4;
+ }
+ }
+ /* Update counter because of variable length fields (AOT and sampling rate) */
+ bitsAvailable = (INT)FDKgetValidBits(bs);
+ }
+ break;
+ case ASCEXT_PS: /* 0x548 */
+ if ( (lastAscExt == ASCEXT_SBR)
+ && (self->m_extensionAudioObjectType == AOT_SBR)
+ && (bitsAvailable > 0) )
+ { /* Get PS extension configuration */
+ self->m_psPresentFlag = FDKreadBits(bs, 1);
+ bitsAvailable -= 1;
+ }
+ break;
+ case ASCEXT_MPS: /* 0x76a */
+ if ( self->m_extensionAudioObjectType == AOT_MPEGS )
+ break;
+ case ASCEXT_LDMPS: /* 0x7cc */
+ if ( (ascExtId == ASCEXT_LDMPS)
+ && (self->m_extensionAudioObjectType == AOT_LD_MPEGS) )
+ break;
+ if (bitsAvailable >= 1)
+ {
+ bitsAvailable -= 1;
+ if ( FDKreadBits(bs, 1) ) { /* self->m_mpsPresentFlag */
+ int sscLen = FDKreadBits(bs, 8);
+ bitsAvailable -= 8;
+ if (sscLen == 0xFF) {
+ sscLen += FDKreadBits(bs, 16);
+ bitsAvailable -= 16;
+ }
+ if (cb->cbSsc != NULL) {
+ cb->cbSsc(
+ cb->cbSscData,
+ bs,
+ self->m_aot,
+ self->m_samplingFrequency,
+ 1,
+ sscLen
+ );
+ } else
+ FDKpushFor(bs, sscLen); /* Skip SSC to be able to read the next extension if there is one. */
+
+ bitsAvailable -= sscLen*8;
+ }
+ }
+ break;
+ default:
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+ }
+
+ return TRANSPORTDEC_OK;
+}
+
+/*
+ * API Functions
+ */
+
+void AudioSpecificConfig_Init(CSAudioSpecificConfig *asc)
+{
+ FDKmemclear(asc, sizeof(CSAudioSpecificConfig));
+
+ /* Init all values that should not be zero. */
+ asc->m_aot = AOT_NONE;
+ asc->m_samplingFrequencyIndex = 0xf;
+ asc->m_epConfig = -1;
+ asc->m_extensionAudioObjectType = AOT_NULL_OBJECT;
+#ifdef TP_PCE_ENABLE
+ CProgramConfig_Init(&asc->m_progrConfigElement);
+#endif
+}
+
+TRANSPORTDEC_ERROR AudioSpecificConfig_Parse(
+ CSAudioSpecificConfig *self,
+ HANDLE_FDK_BITSTREAM bs,
+ int fExplicitBackwardCompatible,
+ CSTpCallBacks *cb
+ )
+{
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+ UINT ascStartAnchor = FDKgetValidBits(bs);
+ int frameLengthFlag = -1;
+
+ AudioSpecificConfig_Init(self);
+
+ self->m_aot = getAOT(bs);
+ self->m_samplingFrequency = getSampleRate(bs, &self->m_samplingFrequencyIndex, 4);
+ if (self->m_samplingFrequency <= 0) {
+ return TRANSPORTDEC_PARSE_ERROR;
+ }
+
+ self->m_channelConfiguration = FDKreadBits(bs,4);
+
+ /* SBR extension ( explicit non-backwards compatible mode ) */
+ self->m_sbrPresentFlag = 0;
+ self->m_psPresentFlag = 0;
+
+ if ( self->m_aot == AOT_SBR || self->m_aot == AOT_PS ) {
+ self->m_extensionAudioObjectType = AOT_SBR;
+
+ self->m_sbrPresentFlag = 1;
+ if ( self->m_aot == AOT_PS ) {
+ self->m_psPresentFlag = 1;
+ }
+
+ self->m_extensionSamplingFrequency = getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4);
+ self->m_aot = getAOT(bs);
+
+ } else {
+ self->m_extensionAudioObjectType = AOT_NULL_OBJECT;
+ }
+
+ /* Parse whatever specific configs */
+ switch (self->m_aot)
+ {
+#ifdef TP_GA_ENABLE
+ case AOT_AAC_LC:
+ case AOT_ER_AAC_LC:
+ case AOT_ER_AAC_LD:
+ case AOT_ER_AAC_SCAL:
+ case AOT_ER_BSAC:
+ if ((ErrorStatus = GaSpecificConfig_Parse(&self->m_sc.m_gaSpecificConfig, self, bs, ascStartAnchor)) != TRANSPORTDEC_OK ) {
+ return (ErrorStatus);
+ }
+ frameLengthFlag = self->m_sc.m_gaSpecificConfig.m_frameLengthFlag;
+ break;
+#endif /* TP_GA_ENABLE */
+ case AOT_MPEGS:
+ if (cb->cbSsc != NULL) {
+ cb->cbSsc(
+ cb->cbSscData,
+ bs,
+ self->m_aot,
+ self->m_samplingFrequency,
+ 1,
+ 0 /* don't know the length */
+ );
+ } else {
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+ break;
+#ifdef TP_ELD_ENABLE
+ case AOT_ER_AAC_ELD:
+ if ((ErrorStatus = EldSpecificConfig_Parse(self, bs, cb)) != TRANSPORTDEC_OK ) {
+ return (ErrorStatus);
+ }
+ frameLengthFlag = self->m_sc.m_eldSpecificConfig.m_frameLengthFlag;
+ self->m_sbrPresentFlag = self->m_sc.m_eldSpecificConfig.m_sbrPresentFlag;
+ self->m_extensionSamplingFrequency = (self->m_sc.m_eldSpecificConfig.m_sbrSamplingRate+1) * self->m_samplingFrequency;
+ break;
+#endif /* TP_ELD_ENABLE */
+
+ default:
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ break;
+ }
+
+ /* Frame length */
+ switch (self->m_aot)
+ {
+#if defined(TP_GA_ENABLE) || defined(TP_USAC_ENABLE)
+ case AOT_AAC_LC:
+ case AOT_ER_AAC_LC:
+ case AOT_ER_AAC_SCAL:
+ case AOT_ER_BSAC:
+ /*case AOT_USAC:*/
+ if (!frameLengthFlag)
+ self->m_samplesPerFrame = 1024;
+ else
+ self->m_samplesPerFrame = 960;
+ break;
+#endif /* TP_GA_ENABLE */
+#if defined(TP_GA_ENABLE)
+ case AOT_ER_AAC_LD:
+ if (!frameLengthFlag)
+ self->m_samplesPerFrame = 512;
+ else
+ self->m_samplesPerFrame = 480;
+ break;
+#endif /* defined(TP_GA_ENABLE) */
+ default:
+ break;
+ }
+
+ switch (self->m_aot)
+ {
+ case AOT_ER_AAC_LC:
+ case AOT_ER_AAC_LD:
+ case AOT_ER_AAC_ELD:
+ case AOT_ER_AAC_SCAL:
+ case AOT_ER_CELP:
+ case AOT_ER_HVXC:
+ case AOT_ER_BSAC:
+ self->m_epConfig = FDKreadBits(bs,2);
+
+ if (self->m_epConfig > 1) {
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT; // EPCONFIG;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (fExplicitBackwardCompatible) {
+ ErrorStatus = AudioSpecificConfig_ExtensionParse(self, bs, cb);
+ }
+
+ return (ErrorStatus);
+}
+
+
diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp
new file mode 100644
index 0000000..28daebc
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_latm.cpp
@@ -0,0 +1,364 @@
+/***************************** MPEG-4 AAC Decoder **************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Daniel Homm
+ Description:
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#include "tpdec_latm.h"
+
+
+#include "FDK_bitstream.h"
+
+
+#define TPDEC_TRACKINDEX(p,l) (2*(p) + (l))
+
+static
+UINT CLatmDemux_GetValue(HANDLE_FDK_BITSTREAM bs)
+{
+ UCHAR bytesForValue = 0, tmp = 0;
+ int value = 0;
+
+ bytesForValue = (UCHAR) FDKreadBits(bs,2);
+
+ for (UINT i=0; i<=bytesForValue; i++) {
+ value <<= 8;
+ tmp = (UCHAR) FDKreadBits(bs,8);
+ value += tmp;
+ }
+
+ return value;
+}
+
+
+static
+TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement(
+ HANDLE_FDK_BITSTREAM bs,
+ CLatmDemux *pLatmDemux,
+ int m_muxConfigPresent,
+ CSTpCallBacks *pTpDecCallbacks,
+ CSAudioSpecificConfig *pAsc
+ )
+{
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+
+ if (m_muxConfigPresent) {
+ pLatmDemux->m_useSameStreamMux = FDKreadBits(bs,1);
+
+ if (!pLatmDemux->m_useSameStreamMux) {
+ if ((ErrorStatus = CLatmDemux_ReadStreamMuxConfig(bs, pLatmDemux, pTpDecCallbacks, pAsc))) {
+ return (ErrorStatus);
+ }
+ }
+ }
+
+ if (pLatmDemux->m_AudioMuxVersionA == 0) {
+ /* Do only once per call, because parsing and decoding is done in-line. */
+ if ((ErrorStatus = CLatmDemux_ReadPayloadLengthInfo(bs,pLatmDemux))) {
+ return (ErrorStatus);
+ }
+ } else {
+ /* audioMuxVersionA > 0 is reserved for future extensions */
+ ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+
+ return (ErrorStatus);
+}
+
+TRANSPORTDEC_ERROR CLatmDemux_Read(
+ HANDLE_FDK_BITSTREAM bs,
+ CLatmDemux *pLatmDemux,
+ TRANSPORT_TYPE tt,
+ CSTpCallBacks *pTpDecCallbacks,
+ CSAudioSpecificConfig *pAsc,
+ const INT ignoreBufferFullness
+ )
+{
+ UINT cntBits;
+ UINT cmpBufferFullness;
+ UINT audioMuxLengthBytesLast = 0;
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+
+ cntBits = FDKgetValidBits(bs);
+
+ if ((INT)cntBits < MIN_LATM_HEADERLENGTH) {
+ return TRANSPORTDEC_NOT_ENOUGH_BITS;
+ }
+
+ if ((ErrorStatus = CLatmDemux_ReadAudioMuxElement(bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0), pTpDecCallbacks, pAsc)))
+ return (ErrorStatus);
+
+ if (!ignoreBufferFullness)
+ {
+ cmpBufferFullness = 24+audioMuxLengthBytesLast*8
+ + pLatmDemux->m_linfo[0][0].m_bufferFullness* pAsc[TPDEC_TRACKINDEX(0,0)].m_channelConfiguration*32;
+
+ /* evaluate buffer fullness */
+
+ if (pLatmDemux->m_linfo[0][0].m_bufferFullness != 0xFF)
+ {
+ if (!pLatmDemux->BufferFullnessAchieved)
+ {
+ if (cntBits < cmpBufferFullness)
+ {
+ /* condition for start of decoding is not fulfilled */
+
+ /* the current frame will not be decoded */
+ return TRANSPORTDEC_NOT_ENOUGH_BITS;
+ }
+ else
+ {
+ pLatmDemux->BufferFullnessAchieved = 1;
+ }
+ }
+ }
+ }
+
+ return (ErrorStatus);
+}
+
+
+TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig(
+ HANDLE_FDK_BITSTREAM bs,
+ CLatmDemux *pLatmDemux,
+ CSTpCallBacks *pTpDecCallbacks,
+ CSAudioSpecificConfig *pAsc
+ )
+{
+ LATM_LAYER_INFO *p_linfo = NULL;
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+
+ pLatmDemux->m_AudioMuxVersion = FDKreadBits(bs,1);
+
+ if (pLatmDemux->m_AudioMuxVersion == 0) {
+ pLatmDemux->m_AudioMuxVersionA = 0;
+ } else {
+ pLatmDemux->m_AudioMuxVersionA = FDKreadBits(bs,1);
+ }
+
+ if (pLatmDemux->m_AudioMuxVersionA == 0) {
+ if (pLatmDemux->m_AudioMuxVersion == 1) {
+ pLatmDemux->m_taraBufferFullness = CLatmDemux_GetValue(bs);
+ }
+ pLatmDemux->m_allStreamsSameTimeFraming = FDKreadBits(bs,1);
+ pLatmDemux->m_noSubFrames = FDKreadBits(bs,6) + 1;
+ pLatmDemux->m_numProgram = FDKreadBits(bs,4) + 1;
+
+ if (pLatmDemux->m_numProgram > 1) {
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+
+ int idCnt = 0;
+ for (UINT prog = 0; prog < pLatmDemux->m_numProgram; prog++) {
+ pLatmDemux->m_numLayer = FDKreadBits(bs,3) + 1;
+ if (pLatmDemux->m_numLayer > 2) {
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+
+ for (UINT lay = 0; lay < pLatmDemux->m_numLayer; lay++) {
+ p_linfo = &pLatmDemux->m_linfo[prog][lay];
+
+ p_linfo->m_streamID = idCnt++;
+ p_linfo->m_frameLengthInBits = 0;
+
+ if( (prog == 0) && (lay == 0) ) {
+ pLatmDemux->m_useSameConfig = 0;
+ } else {
+ pLatmDemux->m_useSameConfig = FDKreadBits(bs,1);
+ }
+
+ if (pLatmDemux->m_useSameConfig) {
+ if (lay > 1) {
+ FDKmemcpy(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &pAsc[TPDEC_TRACKINDEX(prog,lay-1)], sizeof(CSAudioSpecificConfig));
+ } else {
+ return TRANSPORTDEC_PARSE_ERROR;
+ }
+ } else {
+ if (pLatmDemux->m_AudioMuxVersion == 1)
+ {
+ FDK_BITSTREAM tmpBs;
+ UINT ascStartPos, ascLen=0;
+
+ ascLen = CLatmDemux_GetValue(bs);
+ ascStartPos = FDKgetValidBits(bs);
+ tmpBs = *bs;
+ FDKsyncCache(&tmpBs);
+ tmpBs.hBitBuf.ValidBits = ascLen;
+
+ /* Read ASC */
+ if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &tmpBs, 1, pTpDecCallbacks))) {
+ return (ErrorStatus);
+ }
+
+ /* The field p_linfo->m_ascLen could be wrong, so check if */
+ if ( 0 > (INT)FDKgetValidBits(&tmpBs)) {
+ return TRANSPORTDEC_PARSE_ERROR;
+ }
+ FDKpushFor(bs, ascLen); /* position bitstream after ASC */
+ }
+ else {
+ /* Read ASC */
+ if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], bs, 0, pTpDecCallbacks))) {
+ return (ErrorStatus);
+ }
+ }
+ {
+ int cbError;
+
+ cbError = pTpDecCallbacks->cbUpdateConfig(pTpDecCallbacks->cbUpdateConfigData, &pAsc[TPDEC_TRACKINDEX(prog,lay)]);
+ if (cbError != 0) {
+ return TRANSPORTDEC_UNKOWN_ERROR;
+ }
+ }
+ }
+
+ p_linfo->m_frameLengthType = FDKreadBits(bs,3);
+ switch( p_linfo->m_frameLengthType ) {
+ case 0:
+ p_linfo->m_bufferFullness = FDKreadBits(bs,8);
+
+ if (!pLatmDemux->m_allStreamsSameTimeFraming) {
+ if ((lay > 0) && (pAsc[TPDEC_TRACKINDEX(prog,lay)].m_aot == AOT_AAC_SCAL || pAsc[TPDEC_TRACKINDEX(prog,lay)].m_aot == AOT_ER_AAC_SCAL)) {
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+ }
+ break;
+ case 1:
+ /* frameLength = FDKreadBits(bs,9); */
+ case 3:
+ case 4:
+ case 5:
+ /* CELP */
+ case 6:
+ case 7:
+ /* HVXC */
+ default:
+ return TRANSPORTDEC_PARSE_ERROR; //_LATM_INVALIDFRAMELENGTHTYPE;
+
+ } /* switch framelengthtype*/
+
+ } /* layer loop */
+ } /* prog loop */
+
+ pLatmDemux->m_otherDataPresent = FDKreadBits(bs,1);
+ pLatmDemux->m_otherDataLength = 0;
+
+ if (pLatmDemux->m_otherDataPresent) {
+ int otherDataLenEsc = 0;
+ do {
+ pLatmDemux->m_otherDataLength <<= 8; // *= 256
+ otherDataLenEsc = FDKreadBits(bs,1);
+ pLatmDemux->m_otherDataLength += FDKreadBits(bs,8);
+ } while (otherDataLenEsc);
+ }
+
+ pLatmDemux->m_crcCheckPresent = FDKreadBits(bs,1);
+ pLatmDemux->m_crcCheckSum = 0;
+
+ if (pLatmDemux->m_crcCheckPresent) {
+ pLatmDemux->m_crcCheckSum = FDKreadBits(bs,8);
+ }
+
+ }
+ else {
+ /* audioMuxVersionA > 0 is reserved for future extensions */
+ ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+ return (ErrorStatus);
+}
+
+TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux)
+{
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+ int totalPayloadBits = 0;
+
+ if( pLatmDemux->m_allStreamsSameTimeFraming == 1 ) {
+ for (UINT prog=0; prog<pLatmDemux->m_numProgram; prog++ ) {
+ for (UINT lay=0; lay<pLatmDemux->m_numLayer; lay++ ) {
+ LATM_LAYER_INFO *p_linfo = &pLatmDemux->m_linfo[prog][lay];
+
+ switch (p_linfo->m_frameLengthType ) {
+ case 0:
+ p_linfo->m_frameLengthInBits = CLatmDemux_ReadAuChunkLengthInfo(bs);
+ totalPayloadBits += p_linfo->m_frameLengthInBits;
+ break;
+ case 3:
+ case 5:
+ case 7:
+ default:
+ return TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_INVALIDFRAMELENGTHTYPE;
+ }
+ }
+ }
+ }
+ else {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_TIMEFRAMING;
+ }
+ if ((INT)FDKgetValidBits(bs) < totalPayloadBits) {
+ return TRANSPORTDEC_NOT_ENOUGH_BITS;
+ }
+ if (pLatmDemux->m_audioMuxLengthBytes > 0 && totalPayloadBits > pLatmDemux->m_audioMuxLengthBytes*8) {
+ return TRANSPORTDEC_PARSE_ERROR;
+ }
+ return (ErrorStatus);
+}
+
+int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs)
+{
+ UCHAR endFlag;
+ int len = 0;
+
+ do {
+ UCHAR tmp = (UCHAR) FDKreadBits(bs,8);
+ endFlag = (tmp < 255);
+
+ len += tmp;
+
+ } while( endFlag == 0 );
+
+ len <<= 3; /* convert from bytes to bits */
+
+ return len;
+}
+
+int CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux)
+{
+ return pLatmDemux->m_linfo[0][0].m_frameLengthInBits;
+}
+
+int CLatmDemux_GetOtherDataPresentFlag(CLatmDemux *pLatmDemux)
+{
+ return pLatmDemux->m_otherDataPresent ? 1 : 0;
+}
+
+int CLatmDemux_GetOtherDataLength(CLatmDemux *pLatmDemux)
+{
+ return pLatmDemux->m_otherDataLength;
+}
+
+UINT CLatmDemux_GetNrOfSubFrames(CLatmDemux *pLatmDemux)
+{
+ return pLatmDemux->m_noSubFrames;
+}
+
diff --git a/libMpegTPDec/src/tpdec_latm.h b/libMpegTPDec/src/tpdec_latm.h
new file mode 100644
index 0000000..54854b3
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_latm.h
@@ -0,0 +1,103 @@
+/***************************** MPEG-4 AAC Decoder **************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Daniel Homm
+ Description:
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#ifndef LATM_DEMUX_H
+#define LATM_DEMUX_H
+
+#include "tpdec_lib.h"
+
+
+#include "FDK_bitstream.h"
+
+#define MIN_LATM_HEADERLENGTH 9
+#define MIN_LOAS_HEADERLENGTH MIN_LATM_HEADERLENGTH + 24 /* both in bits */
+ #define MIN_TP_BUF_SIZE_LOAS ( 8194 )
+
+enum {
+ LATM_MAX_PROG = 1,
+ LATM_MAX_LAYER = 2,
+ LATM_MAX_VAR_CHUNKS=16,
+ LATM_MAX_ID=16
+};
+
+typedef struct {
+ UINT m_frameLengthType;
+ UINT m_bufferFullness;
+ UINT m_streamID;
+ UINT m_frameLengthInBits;
+} LATM_LAYER_INFO;
+
+typedef struct {
+ LATM_LAYER_INFO m_linfo[LATM_MAX_PROG][LATM_MAX_LAYER];
+ UINT m_taraBufferFullness;
+ UINT m_otherDataLength;
+ UINT m_audioMuxLengthBytes; /* Length of LOAS payload */
+
+ UCHAR m_useSameStreamMux;
+ UCHAR m_AudioMuxVersion;
+ UCHAR m_AudioMuxVersionA;
+ UCHAR m_allStreamsSameTimeFraming;
+ UCHAR m_noSubFrames;
+ UCHAR m_numProgram;
+ UCHAR m_numLayer;
+ UCHAR m_useSameConfig;
+
+ UCHAR m_otherDataPresent;
+ UCHAR m_crcCheckPresent;
+ UCHAR m_crcCheckSum;
+
+ SCHAR BufferFullnessAchieved;
+} CLatmDemux;
+
+int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs);
+
+TRANSPORTDEC_ERROR CLatmDemux_Read(
+ HANDLE_FDK_BITSTREAM bs,
+ CLatmDemux *pLatmDemux,
+ TRANSPORT_TYPE tt,
+ CSTpCallBacks *pTpDecCallbacks,
+ CSAudioSpecificConfig *pAsc,
+ const INT ignoreBufferFullness
+ );
+
+TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig(
+ HANDLE_FDK_BITSTREAM bs,
+ CLatmDemux *pLatmDemux,
+ CSTpCallBacks *pTpDecCallbacks,
+ CSAudioSpecificConfig *pAsc
+ );
+
+TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux);
+
+int CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux);
+int CLatmDemux_GetOtherDataPresentFlag(CLatmDemux *pLatmDemux);
+int CLatmDemux_GetOtherDataLength(CLatmDemux *pLatmDemux);
+UINT CLatmDemux_GetNrOfSubFrames(CLatmDemux *pLatmDemux);
+
+
+#endif /* LATM_DEMUX_H */
diff --git a/libMpegTPDec/src/tpdec_lib.cpp b/libMpegTPDec/src/tpdec_lib.cpp
new file mode 100644
index 0000000..4387847
--- /dev/null
+++ b/libMpegTPDec/src/tpdec_lib.cpp
@@ -0,0 +1,1127 @@
+/************************** MPEG-4 Transport Decoder ************************
+
+ (C) Copyright Fraunhofer IIS (2006)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ $Id$
+ Author(s): Manuel Jander
+ Description: MPEG Transport decoder
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+******************************************************************************/
+
+#include "tpdec_lib.h"
+
+/* library version */
+#include "version"
+
+
+#include "tp_data.h"
+
+#include "tpdec_adts.h"
+
+#include "tpdec_adif.h"
+
+#include "tpdec_latm.h"
+
+
+
+#define MODULE_NAME "transportDec"
+
+typedef union {
+ STRUCT_ADTS adts;
+
+ CAdifHeader adif;
+
+ CLatmDemux latm;
+
+
+} transportdec_parser_t;
+
+struct TRANSPORTDEC
+{
+ TRANSPORT_TYPE transportFmt; /*!< MPEG4 transportDec type. */
+
+ CSTpCallBacks callbacks; /*!< Struct holding callback and its data */
+
+ FDK_BITSTREAM bitStream[2]; /* Bitstream reader */
+ UCHAR *bsBuffer; /* Internal bitstreamd data buffer (unallocated in case of TT_MP4_RAWPACKETS) */
+
+ transportdec_parser_t parser; /* Format specific parser structs. */
+
+ CSAudioSpecificConfig asc[(1*2)]; /* Audio specific config from the last config found. */
+ UINT globalFramePos; /* Global transport frame reference bit position. */
+ UINT accessUnitAnchor[2]; /* Current access unit start bit position. */
+ INT auLength[2]; /* Length of current access unit. */
+ INT numberOfRawDataBlocks; /* Current number of raw data blocks contained remaining from the current transport frame. */
+ UINT avgBitRate; /* Average bit rate used for frame loss estimation. */
+ UINT lastValidBufferFullness; /* Last valid buffer fullness value for frame loss estimation */
+ INT remainder; /* Reminder in division during lost access unit estimation. */
+ INT missingAccessUnits; /* Estimated missing access units. */
+ UINT burstPeriod; /* Data burst period in mili seconds. */
+ UINT holdOffFrames; /* Amount of frames that were already hold off due to buffer fullness condition not being met. */
+ UINT flags; /* Flags. */
+};
+
+/* Flag bitmasks for "flags" member of struct TRANSPORTDEC */
+#define TPDEC_SYNCOK 1
+#define TPDEC_MINIMIZE_DELAY 2
+#define TPDEC_IGNORE_BUFFERFULLNESS 4
+#define TPDEC_EARLY_CONFIG 8
+#define TPDEC_LOST_FRAMES_PENDING 16
+
+C_ALLOC_MEM(Ram_TransportDecoder, TRANSPORTDEC, 1)
+C_ALLOC_MEM(Ram_TransportDecoderBuffer, UCHAR, TRANSPORTDEC_INBUF_SIZE)
+
+
+
+
+HANDLE_TRANSPORTDEC transportDec_Open( const TRANSPORT_TYPE transportFmt, const UINT flags)
+{
+ HANDLE_TRANSPORTDEC hInput;
+
+ hInput = GetRam_TransportDecoder(0);
+ if ( hInput == NULL ) {
+ return NULL;
+ }
+
+ /* Init transportDec struct. */
+ hInput->transportFmt = transportFmt;
+
+ switch (transportFmt) {
+
+ case TT_MP4_ADIF:
+ break;
+
+ case TT_MP4_ADTS:
+ if (flags & TP_FLAG_MPEG4)
+ hInput->parser.adts.decoderCanDoMpeg4 = 1;
+ else
+ hInput->parser.adts.decoderCanDoMpeg4 = 0;
+ adtsRead_CrcInit(&hInput->parser.adts);
+ hInput->parser.adts.BufferFullnesStartFlag = 1;
+ hInput->numberOfRawDataBlocks = 0;
+ break;
+
+
+ case TT_MP4_LATM_MCP0:
+ case TT_MP4_LATM_MCP1:
+ case TT_MP4_LOAS:
+ case TT_MP4_RAW:
+ break;
+
+ default:
+ FreeRam_TransportDecoder(&hInput);
+ hInput = NULL;
+ break;
+ }
+
+ if (hInput != NULL) {
+ /* Create bitstream */
+ if ( (transportFmt == TT_MP4_RAW)
+ || (transportFmt == TT_DRM) ){
+ hInput->bsBuffer = NULL;
+ } else {
+ hInput->bsBuffer = GetRam_TransportDecoderBuffer(0);
+ if (hInput->bsBuffer == NULL) {
+ transportDec_Close( &hInput );
+ return NULL;
+ }
+ FDKinitBitStream(&hInput->bitStream[0], hInput->bsBuffer, TRANSPORTDEC_INBUF_SIZE, 0, BS_READER);
+ }
+
+ hInput->burstPeriod = 0;
+ }
+
+ return hInput;
+}
+
+TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR *conf, const UINT length, UINT layer )
+{
+ TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK;
+
+ FDK_BITSTREAM bs;
+ HANDLE_FDK_BITSTREAM hBs = &bs;
+
+ FDKinitBitStream(hBs, conf, 0x80000000, length<<3, BS_READER);
+
+ /* config transport decoder */
+ switch (hTp->transportFmt) {
+ case TT_MP4_LATM_MCP0:
+ case TT_MP4_LATM_MCP1:
+ case TT_MP4_LOAS:
+ {
+ if (layer != 0) {
+ return TRANSPORTDEC_INVALID_PARAMETER;
+ }
+ CLatmDemux *pLatmDemux = &hTp->parser.latm;
+ err = CLatmDemux_ReadStreamMuxConfig(hBs, pLatmDemux, &hTp->callbacks, hTp->asc);
+ if (err != TRANSPORTDEC_OK) {
+ return err;
+ }
+ }
+ break;
+ case TT_MP4_RAW:
+ err = AudioSpecificConfig_Parse(&hTp->asc[layer], hBs, 1, &hTp->callbacks);
+ break;
+ default:
+ return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+ if (err == TRANSPORTDEC_OK) {
+ int errC;
+
+ errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer]);
+ if (errC != 0) {
+ err = TRANSPORTDEC_PARSE_ERROR;
+ }
+ }
+
+ return err;
+}
+
+int transportDec_RegisterAscCallback( HANDLE_TRANSPORTDEC hTpDec, const cbUpdateConfig_t cbUpdateConfig, void* user_data)
+{
+ if (hTpDec == NULL) {
+ return -1;
+ }
+ hTpDec->callbacks.cbUpdateConfig = cbUpdateConfig;
+ hTpDec->callbacks.cbUpdateConfigData = user_data;
+ return 0;
+}
+
+int transportDec_RegisterSscCallback( HANDLE_TRANSPORTDEC hTpDec, const cbSsc_t cbSsc, void* user_data)
+{
+ if (hTpDec == NULL) {
+ return -1;
+ }
+ hTpDec->callbacks.cbSsc = cbSsc;
+ hTpDec->callbacks.cbSscData = user_data;
+ return 0;
+}
+
+int transportDec_RegisterSbrCallback( HANDLE_TRANSPORTDEC hTpDec, const cbSbr_t cbSbr, void* user_data)
+{
+ if (hTpDec == NULL) {
+ return -1;
+ }
+ hTpDec->callbacks.cbSbr = cbSbr;
+ hTpDec->callbacks.cbSbrData = user_data;
+ return 0;
+}
+
+TRANSPORTDEC_ERROR transportDec_FillData(
+ const HANDLE_TRANSPORTDEC hTp,
+ UCHAR *pBuffer,
+ const UINT bufferSize,
+ UINT *pBytesValid,
+ const INT layer )
+{
+ HANDLE_FDK_BITSTREAM hBs;
+
+ if ( (hTp == NULL)
+ || (layer >= 2) ) {
+ return TRANSPORTDEC_INVALID_PARAMETER;
+ }
+
+ if (*pBytesValid == 0) {
+ /* nothing to do */
+ return TRANSPORTDEC_OK;
+ }
+
+ /* set bitbuffer shortcut */
+ hBs = &hTp->bitStream[layer];
+
+ switch (hTp->transportFmt) {
+ case TT_MP4_RAW:
+ case TT_DRM:
+ /* 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 feed bitbuffer with new stream data (append). */
+ if (hTp->numberOfRawDataBlocks <= 0) {
+ FDKfeedBuffer (hBs, pBuffer, bufferSize, pBytesValid) ;
+ }
+ }
+
+ return TRANSPORTDEC_OK;
+}
+
+HANDLE_FDK_BITSTREAM transportDec_GetBitstream( const HANDLE_TRANSPORTDEC hTp, const UINT layer )
+{
+ return &hTp->bitStream[layer];
+}
+
+TRANSPORT_TYPE transportDec_GetFormat( const HANDLE_TRANSPORTDEC hTp )
+{
+ return hTp->transportFmt;
+}
+
+INT transportDec_GetBufferFullness( const HANDLE_TRANSPORTDEC hTp )
+{
+ INT bufferFullness = -1;
+
+ switch (hTp->transportFmt) {
+ case TT_MP4_ADTS:
+ if (hTp->parser.adts.bs.adts_fullness != 0x7ff) {
+ bufferFullness = hTp->parser.adts.bs.frame_length*8 + hTp->parser.adts.bs.adts_fullness * 32 * getNumberOfEffectiveChannels(hTp->parser.adts.bs.channel_config);
+ }
+ break;
+ case TT_MP4_LOAS:
+ case TT_MP4_LATM_MCP0:
+ case TT_MP4_LATM_MCP1:
+ if (hTp->parser.latm.m_linfo[0][0].m_bufferFullness != 0xff) {
+ bufferFullness = hTp->parser.latm.m_linfo[0][0].m_bufferFullness;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return bufferFullness;
+}
+
+/**
+ * \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.
+ * \param bufferFullness the buffer fullness value of the first frame to be decoded.
+ * \param bitsAvail the amount of available bits at the end of the first frame to be decoded.
+ * \return error code
+ */
+static
+TRANSPORTDEC_ERROR additionalHoldOffNeeded(
+ HANDLE_TRANSPORTDEC hTp,
+ INT bufferFullness,
+ INT bitsAvail
+ )
+{
+ INT checkLengthBits, avgBitsPerFrame;
+ INT maxAU; /* maximum number of frames per Master Frame */
+ INT samplesPerFrame = hTp->asc->m_samplesPerFrame;
+ INT samplingFrequency = (INT)hTp->asc->m_samplingFrequency;
+
+ if ( (hTp->avgBitRate == 0) || (hTp->burstPeriod == 0) ) {
+ return TRANSPORTDEC_OK;
+ }
+ if ( (samplesPerFrame == 0 ) || (samplingFrequency == 0) ) {
+ return TRANSPORTDEC_NOT_ENOUGH_BITS;
+ }
+
+ /* One Master Frame is sent every hTp->burstPeriod ms */
+ maxAU = hTp->burstPeriod * samplingFrequency + (samplesPerFrame*1000 - 1);
+ maxAU = maxAU / (samplesPerFrame*1000);
+ /* Subtract number of frames which were already held off. */
+ maxAU -= hTp->holdOffFrames;
+
+ avgBitsPerFrame = hTp->avgBitRate * samplesPerFrame + (samplingFrequency-1);
+ avgBitsPerFrame = avgBitsPerFrame / samplingFrequency;
+
+ /* Consider worst case of bufferFullness quantization. */
+ switch (hTp->transportFmt) {
+ case TT_MP4_ADIF:
+ case TT_MP4_ADTS:
+ case TT_MP4_LOAS:
+ case TT_MP4_LATM_MCP0:
+ case TT_MP4_LATM_MCP1:
+ bufferFullness += 31;
+ break;
+ default:
+ break;
+ }
+
+ checkLengthBits = bufferFullness + (maxAU-1)*avgBitsPerFrame;
+
+ /* Check if buffer is big enough to fullfill buffer fullness condition */
+ if ( (checkLengthBits /*+headerBits*/) > ((TRANSPORTDEC_INBUF_SIZE<<3)-7) ) {
+ return TRANSPORTDEC_SYNC_ERROR;
+ }
+
+ if ( bitsAvail < checkLengthBits ) {
+ return TRANSPORTDEC_NOT_ENOUGH_BITS;
+ }
+ else {
+ return TRANSPORTDEC_OK;
+ }
+}
+
+/**
+ * \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 )
+ {
+ /* 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;
+ }
+ }
+ }
+
+ /* Do global LOAS/LATM audioMuxElement byte alignment */
+ FDKbyteAlign(hBs, hTp->globalFramePos);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return err;
+}
+
+
+/* How many bits to advance for synchronization search. */
+#define TPDEC_SYNCSKIP 8
+
+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);
+
+ 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;
+
+ FDK_ASSERT(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;
+ }
+
+ 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;
+}
+
+/**
+ * \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;
+}
+
+/* returns error code */
+TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, const UINT layer )
+{
+ TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK;
+ HANDLE_FDK_BITSTREAM hBs;
+
+ if (!hTp) {
+ return TRANSPORTDEC_INVALID_PARAMETER;
+ }
+
+ hBs = &hTp->bitStream[layer];
+
+ switch (hTp->transportFmt) {
+
+ case TT_MP4_ADIF:
+ /* Read header if not already done */
+ if (!(hTp->flags & TPDEC_SYNCOK))
+ {
+ CProgramConfig *pce;
+
+ AudioSpecificConfig_Init(&hTp->asc[0]);
+ pce = &hTp->asc[0].m_progrConfigElement;
+ err = adifRead_DecodeHeader(&hTp->parser.adif, pce, hBs);
+ if (err)
+ goto bail;
+
+ /* Map adif header to ASC */
+ hTp->asc[0].m_aot = (AUDIO_OBJECT_TYPE)(pce->Profile + 1);
+ hTp->asc[0].m_samplingFrequencyIndex = pce->SamplingFrequencyIndex;
+ hTp->asc[0].m_samplingFrequency = SamplingRateTable[pce->SamplingFrequencyIndex];
+ hTp->asc[0].m_channelConfiguration = 0;
+ hTp->asc[0].m_samplesPerFrame = 1024;
+ hTp->avgBitRate = hTp->parser.adif.BitRate;
+
+ /* Call callback to decoder. */
+ {
+ int errC;
+
+ errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]);
+ if (errC == 0) {
+ /* Misuse sync flag to parse header only once. */
+ hTp->flags |= TPDEC_SYNCOK;
+ } else {
+ err = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ }
+ }
+ hTp->auLength[layer] = -1; /* Access Unit data length is unknown. */
+ 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_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;
+
+ default:
+ err = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ break;
+ }
+
+ if (err == TRANSPORTDEC_OK) {
+ hTp->accessUnitAnchor[layer] = FDKgetValidBits(hBs);
+ } else {
+ hTp->accessUnitAnchor[layer] = 0;
+ }
+
+bail:
+ return err;
+}
+
+INT transportDec_GetAuBitsRemaining( const HANDLE_TRANSPORTDEC hTp, const UINT layer )
+{
+ INT bits;
+
+ if (hTp->accessUnitAnchor[layer] > 0 && hTp->auLength[layer] > 0) {
+ bits = hTp->auLength[layer] - (hTp->accessUnitAnchor[layer] - FDKgetValidBits(&hTp->bitStream[layer]));
+ } else {
+ bits = FDKgetValidBits(&hTp->bitStream[layer]);
+ }
+
+ return bits;
+}
+
+INT transportDec_GetAuBitsTotal( const HANDLE_TRANSPORTDEC hTp, const UINT layer )
+{
+ return hTp->auLength[layer];
+}
+
+TRANSPORTDEC_ERROR transportDec_GetMissingAccessUnitCount ( INT *pNAccessUnits, HANDLE_TRANSPORTDEC hTp )
+{
+ *pNAccessUnits = hTp->missingAccessUnits;
+
+ return TRANSPORTDEC_OK;
+}
+
+/* Inform the transportDec layer that reading of access unit has finished. */
+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;
+ }
+
+ return err;
+}
+
+TRANSPORTDEC_ERROR transportDec_SetParam ( const HANDLE_TRANSPORTDEC hTp,
+ const TPDEC_PARAM param,
+ const INT value)
+{
+ TRANSPORTDEC_ERROR error = TRANSPORTDEC_OK;
+
+ switch (param) {
+ case TPDEC_PARAM_MINIMIZE_DELAY:
+ if (value) {
+ hTp->flags |= TPDEC_MINIMIZE_DELAY;
+ } else {
+ hTp->flags &= ~TPDEC_MINIMIZE_DELAY;
+ }
+ break;
+ case TPDEC_PARAM_EARLY_CONFIG:
+ if (value) {
+ hTp->flags |= TPDEC_EARLY_CONFIG;
+ } else {
+ hTp->flags &= ~TPDEC_EARLY_CONFIG;
+ }
+ break;
+ case TPDEC_PARAM_IGNORE_BUFFERFULLNESS:
+ if (value) {
+ hTp->flags |= TPDEC_IGNORE_BUFFERFULLNESS;
+ } else {
+ hTp->flags &= ~TPDEC_IGNORE_BUFFERFULLNESS;
+ }
+ break;
+ case TPDEC_PARAM_SET_BITRATE:
+ hTp->avgBitRate = value;
+ break;
+ case TPDEC_PARAM_BURST_PERIOD:
+ hTp->burstPeriod = value;
+ break;
+ case TPDEC_PARAM_RESET:
+ {
+ int i;
+
+ for (i=0; i<(1*2); i++) {
+ FDKresetBitbuffer(&hTp->bitStream[i]);
+ hTp->auLength[i] = 0;
+ hTp->accessUnitAnchor[i] = 0;
+ }
+ hTp->flags &= ~(TPDEC_SYNCOK|TPDEC_LOST_FRAMES_PENDING);
+ hTp->remainder = 0;
+ hTp->avgBitRate = 0;
+ hTp->missingAccessUnits = 0;
+ hTp->numberOfRawDataBlocks = 0;
+ hTp->globalFramePos = 0;
+ hTp->holdOffFrames = 0;
+ }
+ break;
+ }
+
+ return error;
+}
+
+UINT transportDec_GetNrOfSubFrames(HANDLE_TRANSPORTDEC hTp)
+{
+ UINT nSubFrames = 0;
+
+ if (hTp == NULL)
+ return 0;
+
+ if (hTp->transportFmt==TT_MP4_LATM_MCP1 || hTp->transportFmt==TT_MP4_LATM_MCP0 || hTp->transportFmt==TT_MP4_LOAS)
+ nSubFrames = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm);
+ else if (hTp->transportFmt==TT_MP4_ADTS)
+ nSubFrames = hTp->parser.adts.bs.num_raw_blocks;
+
+ return nSubFrames;
+}
+
+void transportDec_Close(HANDLE_TRANSPORTDEC *phTp)
+{
+ if (phTp != NULL)
+ {
+ if (*phTp != NULL) {
+ if ((*phTp)->transportFmt != TT_MP4_RAW && (*phTp)->transportFmt != TT_DRM) {
+ FreeRam_TransportDecoderBuffer(&(*phTp)->bsBuffer);
+ }
+ if (*phTp != NULL) {
+ FreeRam_TransportDecoder(phTp);
+ }
+ }
+ }
+}
+
+TRANSPORTDEC_ERROR transportDec_GetLibInfo( LIB_INFO *info )
+{
+ int i;
+
+ if (info == NULL) {
+ return TRANSPORTDEC_UNKOWN_ERROR;
+ }
+
+ /* search for next free tab */
+ for (i = 0; i < FDK_MODULE_LAST; i++) {
+ if (info[i].module_id == FDK_NONE) break;
+ }
+ if (i == FDK_MODULE_LAST) return TRANSPORTDEC_UNKOWN_ERROR;
+ info += i;
+
+ info->module_id = FDK_TPDEC;
+ info->build_date = __DATE__;
+ info->build_time = __TIME__;
+ info->title = TP_LIB_TITLE;
+ info->version = LIB_VERSION(TP_LIB_VL0, TP_LIB_VL1, TP_LIB_VL2);
+ LIB_VERSION_STRING(info);
+ info->flags = 0
+ | CAPF_ADIF
+ | CAPF_ADTS
+ | CAPF_LATM
+ | CAPF_LOAS
+ | CAPF_RAWPACKETS
+ ;
+
+ return TRANSPORTDEC_OK; /* FDKERR_NOERROR; */
+}
+
+
+int transportDec_CrcStartReg(HANDLE_TRANSPORTDEC pTp, INT mBits)
+{
+ switch (pTp->transportFmt) {
+ case TT_MP4_ADTS:
+ return adtsRead_CrcStartReg(&pTp->parser.adts, &pTp->bitStream[0], mBits);
+ default:
+ return 0;
+ }
+}
+
+void transportDec_CrcEndReg(HANDLE_TRANSPORTDEC pTp, INT reg)
+{
+ switch (pTp->transportFmt) {
+ case TT_MP4_ADTS:
+ adtsRead_CrcEndReg(&pTp->parser.adts, &pTp->bitStream[0], reg);
+ break;
+ default:
+ break;
+ }
+}
+
+TRANSPORTDEC_ERROR transportDec_CrcCheck(HANDLE_TRANSPORTDEC pTp)
+{
+ switch (pTp->transportFmt) {
+ case TT_MP4_ADTS:
+ 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);
+ }
+ return adtsRead_CrcCheck(&pTp->parser.adts);
+ default:
+ return TRANSPORTDEC_OK;
+ }
+}
diff --git a/libMpegTPDec/src/version b/libMpegTPDec/src/version
new file mode 100644
index 0000000..6aa18cf
--- /dev/null
+++ b/libMpegTPDec/src/version
@@ -0,0 +1,8 @@
+
+/* library info */
+#define TP_LIB_VL0 2
+#define TP_LIB_VL1 2
+#define TP_LIB_VL2 0
+#define TP_LIB_TITLE "MPEG Transport"
+#define TP_LIB_BUILD_DATE __DATE__
+#define TP_LIB_BUILD_TIME __TIME__