From 9bf37cc9712506b2483650c82d3c41152337ef7e Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Tue, 17 Apr 2012 09:51:45 -0700 Subject: Fraunhofer AAC codec. License boilerplate update to follow. Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5 --- libMpegTPDec/Android.mk | 1 + libMpegTPDec/include/mpegFileRead.h | 132 ++++ libMpegTPDec/include/tp_data.h | 277 +++++++++ libMpegTPDec/include/tpdec_lib.h | 430 +++++++++++++ libMpegTPDec/src/Android.mk | 21 + libMpegTPDec/src/mpegFileFormat.h | 52 ++ libMpegTPDec/src/tpdec_adif.cpp | 93 +++ libMpegTPDec/src/tpdec_adif.h | 61 ++ libMpegTPDec/src/tpdec_adts.cpp | 326 ++++++++++ libMpegTPDec/src/tpdec_adts.h | 174 ++++++ libMpegTPDec/src/tpdec_asc.cpp | 867 +++++++++++++++++++++++++++ libMpegTPDec/src/tpdec_latm.cpp | 364 +++++++++++ libMpegTPDec/src/tpdec_latm.h | 103 ++++ libMpegTPDec/src/tpdec_lib.cpp | 1127 +++++++++++++++++++++++++++++++++++ libMpegTPDec/src/version | 8 + 15 files changed, 4036 insertions(+) create mode 100644 libMpegTPDec/Android.mk create mode 100644 libMpegTPDec/include/mpegFileRead.h create mode 100644 libMpegTPDec/include/tp_data.h create mode 100644 libMpegTPDec/include/tpdec_lib.h create mode 100644 libMpegTPDec/src/Android.mk create mode 100644 libMpegTPDec/src/mpegFileFormat.h create mode 100644 libMpegTPDec/src/tpdec_adif.cpp create mode 100644 libMpegTPDec/src/tpdec_adif.h create mode 100644 libMpegTPDec/src/tpdec_adts.cpp create mode 100644 libMpegTPDec/src/tpdec_adts.h create mode 100644 libMpegTPDec/src/tpdec_asc.cpp create mode 100644 libMpegTPDec/src/tpdec_latm.cpp create mode 100644 libMpegTPDec/src/tpdec_latm.h create mode 100644 libMpegTPDec/src/tpdec_lib.cpp create mode 100644 libMpegTPDec/src/version (limited to 'libMpegTPDec') diff --git a/libMpegTPDec/Android.mk b/libMpegTPDec/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libMpegTPDec/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libMpegTPDec/include/mpegFileRead.h b/libMpegTPDec/include/mpegFileRead.h new file mode 100644 index 0000000..c86b5f9 --- /dev/null +++ b/libMpegTPDec/include/mpegFileRead.h @@ -0,0 +1,132 @@ +/***************************** MPEG-4 AAC 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: Bitstream data provider for MP4 decoders + + 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 "machine_type.h" +#include "FDK_audio.h" + +#define MPFREAD_MP4FF_DISABLE + +#ifndef MPFREAD_MP4FF_DISABLE + /*!< If MPFREAD_MP4FF_ENABLE is set, include support for MPEG ISO fileformat. + If not set, no .mp4, .m4a and .3gp files can be used for input. */ + #define MPFREAD_MP4FF_ENABLE +#endif + +/* maximum number of layers which can be read */ +/* shall equal max number of layers read by iisisoff */ +#define FILEREAD_MAX_LAYERS (2) + +typedef struct STRUCT_FILEREAD *HANDLE_FILEREAD; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Open an MPEG audio file and try to detect its format. + * \param filename String of the filename to be opened. + * \param fileFormat Skip file format detection and use given format if fileFormat != FF_UNKNOWN. + Else store detected format into *fileFmt. + * \param transportType Skip transport type detection and use given format if transportType != TT_UNKNOWN. + Else store detected format into *fileFmt. + * \param conf Pointer to unsigned char to hold the AudioSpecificConfig of the input file, if + any (MPEG 4 file format). In case of RAW LATM it holds the StreamMuxConfig. + * \param confSize Pointer to an integer, where the length of the ASC or SMC (in case of RAW LATM) + is stored to. + * \return MPEG file read handle. + */ +HANDLE_FILEREAD mpegFileRead_Open( const char *filename, + FILE_FORMAT fileFormat, + TRANSPORT_TYPE transportType, + UCHAR *conf[], + UINT confSize[], + INT *noOfLayers + ); + +/** + * \brief Get the file format of the input file. + * \param hDataSrc MPEG file read handle. + * \return File format of the input file. + */ +FILE_FORMAT mpegFileRead_GetFileFormat(HANDLE_FILEREAD hDataSrc); + +/** + * \brief Get the transport type of the input file. + * \param hDataSrc MPEG file read handle. + * \return Transport type of the input file. + */ +TRANSPORT_TYPE mpegFileRead_GetTransportType(HANDLE_FILEREAD hDataSrc); + +/** + * \brief Read data from MPEG file. In case of packet file, read one packet, in case + * of streaming file with embedded synchronisation layer (LOAS/ADTS...), just + * fill the buffer. + * + * \param hMpegFile MPEG file read handle. + * \param inBuffer Pointer to input buffer. + * \param bufferSize Size of input buffer. + * \param bytesValid Number of bytes that were read. + * \return 0 on success, -1 if unsupported file format or file read error. + */ +int mpegFileRead_Read( HANDLE_FILEREAD hMpegFile, + UCHAR *inBuffer[], + UINT bufferSize, + UINT *bytesValid + ); + +/** + * \brief Seek in file from origin by given offset in frames. + * \param hMpegFile MPEG file read handle. + * \param origin If 0, the origin is the file beginning (absolute seek). + * If 1, the origin is the current position (relative seek). + * \param offset The amount of frames to seek from the given origin. + * \return 0 on sucess, -1 if offset < 0 or file read error. + */ +int mpegFileRead_seek( HANDLE_FILEREAD hMpegFile, + INT origin, + INT offset + ); + +/** + * \brief Get file position in percent. + * \param hMpegFile MPEG file read handle. + * \return File position in percent. + */ +int mpegFileRead_getPercent(HANDLE_FILEREAD hMpegFile); + + +/** + * \brief Close MPEG audio file. + * \param hMpegFile Mpeg file read handle. + * \return 0 on sucess. + */ +int mpegFileRead_Close(HANDLE_FILEREAD *hMpegFile); + +#ifdef __cplusplus +} +#endif diff --git a/libMpegTPDec/include/tp_data.h b/libMpegTPDec/include/tp_data.h new file mode 100644 index 0000000..6149608 --- /dev/null +++ b/libMpegTPDec/include/tp_data.h @@ -0,0 +1,277 @@ +/***************************** 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): Manuel Jander + Description: MPEG Transport data tables + + 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 __TP_DATA_H__ +#define __TP_DATA_H__ + +#include "machine_type.h" +#include "FDK_audio.h" +#include "FDK_bitstream.h" + +/* + * Configuration + */ +#define TP_GA_ENABLE +/* #define TP_CELP_ENABLE */ +/* #define TP_HVXC_ENABLE */ +/* #define TP_SLS_ENABLE */ +#define TP_ELD_ENABLE +/* #define TP_USAC_ENABLE */ +/* #define TP_RSVD50_ENABLE */ + +#if defined(TP_GA_ENABLE) || defined(TP_SLS_ENABLE) +#define TP_PCE_ENABLE /**< Enable full PCE support */ +#endif + +/** + * ProgramConfig struct. + */ +/* ISO/IEC 14496-3 4.4.1.1 Table 4.2 Program config element */ +#define PC_FSB_CHANNELS_MAX 16 /* Front/Side/Back channels */ +#define PC_LFE_CHANNELS_MAX 4 +#define PC_ASSOCDATA_MAX 8 +#define PC_CCEL_MAX 16 /* CC elements */ +#define PC_COMMENTLENGTH 256 + +typedef struct +{ +#ifdef TP_PCE_ENABLE + /* PCE bitstream elements: */ + UCHAR ElementInstanceTag; + UCHAR Profile; + UCHAR SamplingFrequencyIndex; + UCHAR NumFrontChannelElements; + UCHAR NumSideChannelElements; + UCHAR NumBackChannelElements; + UCHAR NumLfeChannelElements; + UCHAR NumAssocDataElements; + UCHAR NumValidCcElements; + + UCHAR MonoMixdownPresent; + UCHAR MonoMixdownElementNumber; + + UCHAR StereoMixdownPresent; + UCHAR StereoMixdownElementNumber; + + UCHAR MatrixMixdownIndexPresent; + UCHAR MatrixMixdownIndex; + UCHAR PseudoSurroundEnable; + + UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX]; + + UCHAR AssocDataElementTagSelect[PC_ASSOCDATA_MAX]; + + UCHAR CcElementIsIndSw[PC_CCEL_MAX]; + UCHAR ValidCcElementTagSelect[PC_CCEL_MAX]; + + UCHAR CommentFieldBytes; + UCHAR Comment[PC_COMMENTLENGTH]; +#endif /* TP_PCE_ENABLE */ + + /* Helper variables for administration: */ + UCHAR isValid; /*!< Flag showing if PCE has been read successfully. */ + UCHAR NumChannels; /*!< Amount of audio channels summing all channel elements including LFEs */ + UCHAR NumEffectiveChannels; /*!< Amount of audio channels summing only SCEs and CPEs */ + UCHAR elCounter; + +} CProgramConfig; + +typedef enum { + ASCEXT_UNKOWN = -1, + ASCEXT_SBR = 0x2b7, + ASCEXT_PS = 0x548, + ASCEXT_MPS = 0x76a, + ASCEXT_SAOC = 0x7cb, + ASCEXT_LDMPS = 0x7cc + +} TP_ASC_EXTENSION_ID; + +#ifdef TP_GA_ENABLE +/** + * GaSpecificConfig struct + */ +typedef struct { + UINT m_frameLengthFlag ; + UINT m_dependsOnCoreCoder ; + UINT m_coreCoderDelay ; + + UINT m_extensionFlag ; + UINT m_extensionFlag3 ; + + UINT m_layer; + UINT m_numOfSubFrame; + UINT m_layerLength; + +} CSGaSpecificConfig; +#endif /* TP_GA_ENABLE */ + + + + +#ifdef TP_ELD_ENABLE + +typedef enum { + ELDEXT_TERM = 0x0, /* Termination tag */ + ELDEXT_SAOC = 0x1, /* SAOC config */ + ELDEXT_LDSAC = 0x2 /* LD MPEG Surround config */ + /* reserved */ +} ASC_ELD_EXT_TYPE; + +typedef struct { + UCHAR m_frameLengthFlag; + + UCHAR m_sbrPresentFlag; + UCHAR m_useLdQmfTimeAlign; /* Use LD-MPS QMF in SBR to achive time alignment */ + UCHAR m_sbrSamplingRate; + UCHAR m_sbrCrcFlag; + +} CSEldSpecificConfig; +#endif /* TP_ELD_ENABLE */ + + + + +/** + * Audio configuration struct, suitable for encoder and decoder configuration. + */ +typedef struct { + + /* XYZ Specific Data */ + union { +#ifdef TP_GA_ENABLE + CSGaSpecificConfig m_gaSpecificConfig; /**< General audio specific configuration. */ +#endif /* TP_GA_ENABLE */ +#ifdef TP_ELD_ENABLE + CSEldSpecificConfig m_eldSpecificConfig; /**< ELD specific configuration. */ +#endif /* TP_ELD_ENABLE */ + } m_sc; + + /* Common ASC parameters */ +#ifdef TP_PCE_ENABLE + CProgramConfig m_progrConfigElement; /**< Program configuration. */ +#endif /* TP_PCE_ENABLE */ + + AUDIO_OBJECT_TYPE m_aot; /**< Audio Object Type. */ + UINT m_samplingFrequency; /**< Samplerate. */ + UINT m_samplesPerFrame; /**< Amount of samples per frame. */ + UINT m_directMapping; /**< Document this please !! */ + + AUDIO_OBJECT_TYPE m_extensionAudioObjectType; /**< Audio object type */ + UINT m_extensionSamplingFrequency; /**< Samplerate */ + + SCHAR m_channelConfiguration; /**< Channel configuration index */ + + SCHAR m_epConfig; /**< Error protection index */ + SCHAR m_vcb11Flag; /**< aacSectionDataResilienceFlag */ + SCHAR m_rvlcFlag; /**< aacScalefactorDataResilienceFlag */ + SCHAR m_hcrFlag; /**< aacSpectralDataResilienceFlag */ + + SCHAR m_sbrPresentFlag; /**< Flag indicating the presence of SBR data in the bitstream */ + SCHAR m_psPresentFlag; /**< Flag indicating the presence of parametric stereo data in the bitstream */ + UCHAR m_samplingFrequencyIndex; /**< Samplerate index */ + UCHAR m_extensionSamplingFrequencyIndex; /**< Samplerate index */ + SCHAR m_extensionChannelConfiguration; /**< Channel configuration index */ + +} CSAudioSpecificConfig; + +typedef INT (*cbUpdateConfig_t)(void*, const CSAudioSpecificConfig*); +typedef INT (*cbSsc_t)( + void*, HANDLE_FDK_BITSTREAM, + const AUDIO_OBJECT_TYPE coreCodec, + const INT samplingFrequency, + const INT muxMode, + const INT configBytes + ); +typedef INT (*cbSbr_t)( + void * self, + HANDLE_FDK_BITSTREAM hBs, + const INT sampleRateIn, + const INT sampleRateOut, + const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const INT elementIndex + ); + +typedef struct { + cbUpdateConfig_t cbUpdateConfig; /*!< Function pointer for Config change notify callback. */ + void *cbUpdateConfigData; /*!< User data pointer for Config change notify callback. */ + cbSsc_t cbSsc; /*!< Function pointer for SSC parser callback. */ + void *cbSscData; /*!< User data pointer for SSC parser callback. */ + cbSbr_t cbSbr; /*!< Function pointer for SBR header parser callback. */ + void *cbSbrData; /*!< User data pointer for SBR header parser callback. */ +} CSTpCallBacks; + +static const UINT SamplingRateTable[] = +{ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, + 0 +}; + +static inline +int getSamplingRateIndex( UINT samplingRate ) +{ + UINT sf_index, tableSize=sizeof(SamplingRateTable)/sizeof(UINT); + + for (sf_index=0; sf_indextableSize-1) { + return tableSize-1; + } + + return sf_index; +} + +/* + * Get Channel count from channel configuration + */ +static inline int getNumberOfTotalChannels(int channelConfig) +{ + if (channelConfig > 0 && channelConfig < 8) + return (channelConfig == 7)?8:channelConfig; + else + return 0; +} + +static inline +int getNumberOfEffectiveChannels(const int channelConfig) +{ + const int n[] = {0,1,2,3,4,5,5,7}; + return n[channelConfig]; +} + +#endif /* __TP_DATA_H__ */ diff --git a/libMpegTPDec/include/tpdec_lib.h b/libMpegTPDec/include/tpdec_lib.h new file mode 100644 index 0000000..f32f6d8 --- /dev/null +++ b/libMpegTPDec/include/tpdec_lib.h @@ -0,0 +1,430 @@ +/************************** 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. + +******************************************************************************/ + +#ifndef __TPDEC_LIB_H__ +#define __TPDEC_LIB_H__ + +#include "tp_data.h" + +#include "FDK_bitstream.h" + +#define TRANSPORTDEC_INBUF_SIZE ( 8192 ) /*!< Size is in bytes. + Set the transport input buffer size carefully and + assure that it fulfills the requirements of the + supported transport format(s). */ + +typedef enum { + TRANSPORTDEC_OK = 0, /*!< All fine. */ + + /* Synchronization errors. Wait for new input data and try again. */ + tpdec_sync_error_start = 0x100, + TRANSPORTDEC_NOT_ENOUGH_BITS, /*!< Out of bits. Provide more bits and try again. */ + TRANSPORTDEC_SYNC_ERROR, /*!< No sync was found or sync got lost. Keep trying. */ + tpdec_sync_error_end, + + /* Decode errors. Mostly caused due to bit errors. */ + tpdec_decode_error_start = 0x400, + TRANSPORTDEC_PARSE_ERROR, /*!< Bitstream data showed inconsistencies (wrong syntax). */ + TRANSPORTDEC_UNSUPPORTED_FORMAT, /*!< Unsupported format or feature found in the bitstream data. */ + TRANSPORTDEC_CRC_ERROR, /*!< CRC error encountered in bitstream data. */ + tpdec_decode_error_end, + + /* Fatal errors. Stop immediately on one of these errors! */ + tpdec_fatal_error_start = 0x200, + TRANSPORTDEC_UNKOWN_ERROR, /*!< An unknown error occured. */ + TRANSPORTDEC_INVALID_PARAMETER, /*!< An invalid parameter was passed to a function. */ + TRANSPORTDEC_NEED_TO_RESTART, /*!< The decoder needs to be restarted, since the requiered + configuration change cannot be performed. */ + tpdec_fatal_error_end + +} TRANSPORTDEC_ERROR; + + +/** Macro to identify decode errors. */ +#define TPDEC_IS_DECODE_ERROR(err) ( ((err>=tpdec_decode_error_start) && (err<=tpdec_decode_error_end)) ? 1 : 0) +/** Macro to identify fatal errors. */ +#define TPDEC_IS_FATAL_ERROR(err) ( ((err>=tpdec_fatal_error_start) && (err<=tpdec_fatal_error_end)) ? 1 : 0) + + +/** + * \brief Parameter identifiers for transportDec_SetParam() + */ +typedef enum { + TPDEC_PARAM_MINIMIZE_DELAY = 1, /** Delay minimization strategy. 0: none, 1: discard as many frames as possible. */ + TPDEC_PARAM_EARLY_CONFIG, /** Enable early config discovery. */ + TPDEC_PARAM_IGNORE_BUFFERFULLNESS, /** Ignore buffer fullness. */ + TPDEC_PARAM_SET_BITRATE, /** Set average bit rate for bit stream interruption frame misses estimation. */ + TPDEC_PARAM_RESET, /** Reset transport decoder instance status. */ + TPDEC_PARAM_BURST_PERIOD /** Set data reception burst period in mili seconds. */ +} TPDEC_PARAM; + +/* ISO/IEC 14496-3 4.4.1.1 Table 4.2 Program config element */ +#define PC_FSB_CHANNELS_MAX 16 /* Front/Side/Back channels */ +#define PC_LFE_CHANNELS_MAX 4 +#define PC_ASSOCDATA_MAX 8 +#define PC_CCEL_MAX 16 /* CC elements */ +#define PC_COMMENTLENGTH 256 + + +/*! + \brief Reset Program Config Element. + \param pPce Program Config Element structure. + \return void +*/ +void CProgramConfig_Reset ( CProgramConfig *pPce ); + +/*! + \brief Initialize Program Config Element. + \param pPce Program Config Element structure. + \return void +*/ +void CProgramConfig_Init ( CProgramConfig *pPce ); + +/*! + \brief Inquire state of present Program Config Element structure. + \param pPce Program Config Element structure. + \return 1 if the PCE structure is filled correct, + 0 if no valid PCE present. +*/ +int CProgramConfig_IsValid ( const CProgramConfig *pPce ); + +#ifdef TP_PCE_ENABLE +/*! + \brief Read Program Config Element. + \param pPce Program Config Element structure. + \param bs Bitstream buffer to read from. + \param alignAnchor Align bitstream to alignAnchor bits after all read operations. + \return void +*/ +void CProgramConfig_Read ( CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs, + UINT alignAnchor ); +#endif /* TP_PCE_ENABLE */ + +/** + * \brief Lookup and verify a given element. The decoder calls this + * method with every new element ID found in the bitstream. + * + * \param pPce A valid Program config structure. + * \param tag Tag of the current element to be looked up. + * \param channelIdx The current channel count of the decoder parser. + * \param chMapping Array to store the canonical channel mapping indexes. + * \param chType Array to store the audio channel type. + * \param chIndex Array to store the individual audio channel type index. + * \param elMapping Pointer where the canonical element index is stored. + * \param elType The element id of the current element to be looked up. + * + * \return Non-zero if the element belongs to the current program, zero + * if it does not. + */ +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 + ); + +/** + * \brief Get table of elements in canonical order. + * \param pPce A valid program config structure. + * \param table An array where the element IDs are stored. + * \return Total element count including all SCE, CPE and LFE. + */ +int CProgramConfig_GetElementTable( const CProgramConfig *pPce, + MP4_ELEMENT_ID table[] ); + +/** + * \brief Initialize a given AudioSpecificConfig structure. + * \param pAsc A pointer to an allocated CSAudioSpecificConfig struct. + * \return void + */ +void AudioSpecificConfig_Init(CSAudioSpecificConfig *pAsc); + +/** + * \brief Parse a AudioSpecificConfig from a given bitstream handle. + * + * \param pAsc A pointer to an allocated CSAudioSpecificConfig struct. + * \param hBs Bitstream handle. + * \param fExplicitBackwardCompatible Do explicit backward compatibility parsing if set (flag). + * \param cb pointer to structure holding callback information + * + * \return Total element count including all SCE, CPE and LFE. + */ +TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( + CSAudioSpecificConfig *pAsc, + HANDLE_FDK_BITSTREAM hBs, + int fExplicitBackwardCompatible, + CSTpCallBacks *cb + ); + +/* CELP stuff */ +enum { + MPE = 0, + RPE = 1, + fs8KHz = 0, + fs16KHz = 1 +}; + +/* Defintion of flags that can be passed to transportDecOpen() */ +#define TP_FLAG_MPEG4 1 + +/* Capability flags */ +#define CAPF_TPDEC_ADIF 0x00001000 /**< Flag indicating support for ADIF transport format. */ +#define CAPF_TPDEC_ADTS 0x00002000 /**< Flag indicating support for ADTS transport format. */ +#define CAPF_TPDEC_LOAS 0x00004000 /**< Flag indicating support for LOAS transport format. */ +#define CAPF_TPDEC_LATM 0x00008000 /**< Flag indicating support for LATM transport format. */ +#define CAPF_TPDEC_RAWPACKETS 0x00010000 /**< Flag indicating support for raw packets transport format. */ + +typedef struct TRANSPORTDEC *HANDLE_TRANSPORTDEC; + + +/** + * \brief Configure Transport Decoder via a binary coded AudioSpecificConfig or StreamMuxConfig. + * The previously requested configuration callback will be called as well. The buffer conf + * must containt a SMC in case of LOAS/LATM transport format, and an ASC elseways. + * + * \param hTp Handle of a transport decoder. + * \param conf UCHAR buffer of the binary coded config (ASC or SMC). + * \param length The length in bytes of the conf buffer. + * + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_OutOfBandConfig( const HANDLE_TRANSPORTDEC hTp, + UCHAR *conf, + const UINT length, + const UINT layer ); + +/** + * \brief Open Transport medium for reading. + * + * \param transportDecFmt Format of the transport decoder medium to be accessed. + * \param flags Transport decoder flags. Currently only TP_FLAG_MPEG4, which signals a + * MPEG4 capable decoder (relevant for ADTS only). + * + * \return A pointer to a valid and allocated HANDLE_TRANSPORTDEC or a null pointer on failure. + */ +HANDLE_TRANSPORTDEC transportDec_Open( TRANSPORT_TYPE transportDecFmt, + const UINT flags ); + +/** + * \brief Register configuration change callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle audio config changes. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportDec_RegisterAscCallback ( + HANDLE_TRANSPORTDEC hTp, + const cbUpdateConfig_t cbUpdateConfig, + void* user_data ); + +/** + * \brief Register SSC parser callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle SSC parsing. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportDec_RegisterSscCallback ( + HANDLE_TRANSPORTDEC hTp, + const cbSsc_t cbSscParse, + void* user_data ); + +/** + * \brief Register SBR header parser callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle SBR header parsing. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportDec_RegisterSbrCallback( HANDLE_TRANSPORTDEC hTpDec, const cbSbr_t cbSbr, void* user_data); + +/** + * \brief Fill internal input buffer with bitstream data from the external input buffer. + * The function only copies such data as long as the decoder-internal input buffer is not full. + * So it grabs whatever it can from pBuffer and returns information (bytesValid) so that at a + * subsequent call of %transportDec_FillData(), the right position in pBuffer can be determined to + * grab the next data. + * + * \param hTp Handle of transportDec. + * \param pBuffer Pointer to external input buffer. + * \param bufferSize Size of external input buffer. This argument is required because decoder-internally + * we need the information to calculate the offset to pBuffer, where the next + * available data is, which is then fed into the decoder-internal buffer (as much + * as possible). Our example framework implementation fills the buffer at pBuffer + * again, once it contains no available valid bytes anymore (meaning bytesValid equal 0). + * \param bytesValid Number of bitstream bytes in the external bitstream buffer that have not yet been + * copied into the decoder's internal bitstream buffer by calling this function. + * The value is updated according to the amount of newly copied bytes. + * \param layer The layer the bitstream belongs to. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_FillData( + const HANDLE_TRANSPORTDEC hTp, + UCHAR *pBuffer, + const UINT bufferSize, + UINT *pBytesValid, + const INT layer ); + +/** + * \brief Get transportDec bitstream handle. + * \param hTp Pointer to a transport decoder handle. + * \return HANDLE_FDK_BITSTREAM bitstream handle. + */ +HANDLE_FDK_BITSTREAM transportDec_GetBitstream ( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief Get transport format. + * \param hTp Pointer to a transport decoder handle. + * \return The transport format. + */ +TRANSPORT_TYPE transportDec_GetFormat ( const HANDLE_TRANSPORTDEC hTp ); + +/** + * \brief Get the current buffer fullness value. + * + * \param hTp Handle of a transport decoder. + * + * \return Buffer fullness + */ +INT transportDec_GetBufferFullness( const HANDLE_TRANSPORTDEC hTp ); + +/** + * \brief Close and deallocate transportDec. + * \param phTp Pointer to a previously allocated transport decoder handle. + * \return void + */ +void transportDec_Close ( HANDLE_TRANSPORTDEC *phTp ); + +/** + * \brief Read one access unit from the transportDec medium. + * \param hTp Handle of transportDec. + * \param length On return, this value is overwritten with the actual access unit length in bits. + * Set to -1 if length is unknown. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_ReadAccessUnit ( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief Get the remaining amount of bits of the current access unit. The result + * can be below zero, meaning that too many bits have been read. + * \param hTp Handle of transportDec. + * \return amount of remaining bits. + */ +INT transportDec_GetAuBitsRemaining( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief Get the total amount of bits of the current access unit. + * \param hTp Handle of transportDec. + * \return amount of total bits. + */ +INT transportDec_GetAuBitsTotal( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief This function is required to be called when the decoder has finished parsing + * one Access Unit for bitstream housekeeping. + * \param hTp Transport Handle. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_EndAccessUnit ( const HANDLE_TRANSPORTDEC hTp ); + +/** + * \brief Obtain the amount of missing access units if applicable in case of + * a bit stream synchronization error. Each time transportDec_ReadAccessUnit() + * returns TRANSPORTDEC_SYNC_ERROR this function can be called to retrieve an estimate + * of the amount of missing access units. This works only in case of constant average + * bit rate (has to be known) and if the parameter TPDEC_PARAM_SET_BITRATE has been set + * accordingly. + * \param hTp Transport Handle. + * \param pNAccessUnits pointer to a memory location where the estimated lost frame count will be stored into. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_GetMissingAccessUnitCount ( INT *pNAccessUnits, HANDLE_TRANSPORTDEC hTp ); + + +/** + * \brief Set a given setting. + * \param hTp Transport Handle. + * \param param Identifier of the parameter to be changed. + * \param value Value for the parameter to be changed. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_SetParam ( const HANDLE_TRANSPORTDEC hTp, + const TPDEC_PARAM param, + const INT value ); + +/** + * \brief Get number of subframes (for LATM or ADTS) + * \param hTp Transport Handle. + * \return Number of ADTS/LATM subframes (return 1 for all other transport types). + */ +UINT transportDec_GetNrOfSubFrames(HANDLE_TRANSPORTDEC hTp); + + +/** + * \brief Get info structure of transport decoder library. + * \param info A pointer to an allocated LIB_INFO struct. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_GetLibInfo( LIB_INFO *info ); + +/* ADTS CRC support */ + +/** + * \brief Set current bitstream position as start of a new data region. + * \param hTp Transport handle. + * \param mBits Size in bits of the data region. Set to 0 if it should not be of a fixed size. + * \return Data region ID, which should be used when calling transportDec_CrcEndReg(). + */ +int transportDec_CrcStartReg ( const HANDLE_TRANSPORTDEC hTp, + const INT mBits ); + +/** + * \brief Set end of data region. + * \param hTp Transport handle. + * \param reg Data region ID, opbtained from transportDec_CrcStartReg(). + * \return void + */ +void transportDec_CrcEndReg ( const HANDLE_TRANSPORTDEC hTp, + const INT reg ); + +/** + * \brief Calculate ADTS crc and check if it is correct. The ADTS checksum is held internally. + * \param hTp Transport handle. + * \return Return TRANSPORTDEC_OK if the CRC is ok, or error if CRC is not correct. + */ +TRANSPORTDEC_ERROR transportDec_CrcCheck ( const HANDLE_TRANSPORTDEC hTp ); + + +#endif /* #ifndef __TPDEC_LIB_H__ */ 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; irawDataBlockDist[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<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= 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; progm_numProgram; prog++ ) { + for (UINT lay=0; laym_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<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__ -- cgit v1.2.3