Merge "Add AOT specific number of qmf bands sanity check in SpatialSpecificConfig()"
diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp
index 2860bf6..cbcd404 100644
--- a/libAACdec/src/aacdecoder_lib.cpp
+++ b/libAACdec/src/aacdecoder_lib.cpp
@@ -387,7 +387,7 @@
 
 static INT aacDecoder_SscCallback(void *handle, HANDLE_FDK_BITSTREAM hBs,
                                   const AUDIO_OBJECT_TYPE coreCodec,
-                                  const INT samplingRate,
+                                  const INT samplingRate, const INT frameSize,
                                   const INT stereoConfigIndex,
                                   const INT coreSbrFrameLengthIndex,
                                   const INT configBytes, const UCHAR configMode,
@@ -398,8 +398,8 @@
 
   err = mpegSurroundDecoder_Config(
       (CMpegSurroundDecoder *)hAacDecoder->pMpegSurroundDecoder, hBs, coreCodec,
-      samplingRate, stereoConfigIndex, coreSbrFrameLengthIndex, configBytes,
-      configMode, configChanged);
+      samplingRate, frameSize, stereoConfigIndex, coreSbrFrameLengthIndex,
+      configBytes, configMode, configChanged);
 
   switch (err) {
     case MPS_UNSUPPORTED_CONFIG:
diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp
index 9e0630c..08cd57a 100644
--- a/libAACenc/src/aacenc_lib.cpp
+++ b/libAACenc/src/aacenc_lib.cpp
@@ -1216,7 +1216,8 @@
 
 INT aacenc_SscCallback(void *self, HANDLE_FDK_BITSTREAM hBs,
                        const AUDIO_OBJECT_TYPE coreCodec,
-                       const INT samplingRate, const INT stereoConfigIndex,
+                       const INT samplingRate, const INT frameSize,
+                       const INT stereoConfigIndex,
                        const INT coreSbrFrameLengthIndex, const INT configBytes,
                        const UCHAR configMode, UCHAR *configChanged) {
   HANDLE_AACENCODER hAacEncoder = (HANDLE_AACENCODER)self;
diff --git a/libMpegTPDec/include/tp_data.h b/libMpegTPDec/include/tp_data.h
index b4ab802..b015332 100644
--- a/libMpegTPDec/include/tp_data.h
+++ b/libMpegTPDec/include/tp_data.h
@@ -367,7 +367,8 @@
 typedef INT (*cbCtrlCFGChange_t)(void *, const CCtrlCFGChange *);
 typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM,
                        const AUDIO_OBJECT_TYPE coreCodec,
-                       const INT samplingRate, const INT stereoConfigIndex,
+                       const INT samplingRate, const INT frameSize,
+                       const INT stereoConfigIndex,
                        const INT coreSbrFrameLengthIndex, const INT configBytes,
                        const UCHAR configMode, UCHAR *configChanged);
 
diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
index 5270f2b..28bc22d 100644
--- a/libMpegTPDec/src/tpdec_asc.cpp
+++ b/libMpegTPDec/src/tpdec_asc.cpp
@@ -1413,7 +1413,9 @@
         esc->m_useLdQmfTimeAlign = 1;
         if (cb->cbSsc != NULL) {
           ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc(
-              cb->cbSscData, hBs, asc->m_aot, asc->m_extensionSamplingFrequency,
+              cb->cbSscData, hBs, asc->m_aot,
+              asc->m_samplingFrequency << esc->m_sbrSamplingRate,
+              asc->m_samplesPerFrame << esc->m_sbrSamplingRate,
               1,  /* stereoConfigIndex */
               -1, /* nTimeSlots: read from bitstream */
               eldExtLen, asc->configMode, &asc->SacConfigChanged);
@@ -1812,9 +1814,16 @@
 
           if (usc->element[i].m_stereoConfigIndex > 0) {
             if (cb->cbSsc != NULL) {
+              int samplesPerFrame = asc->m_samplesPerFrame;
+
+              if (usc->m_sbrRatioIndex == 1) samplesPerFrame <<= 2;
+              if (usc->m_sbrRatioIndex == 2)
+                samplesPerFrame = (samplesPerFrame * 8) / 3;
+              if (usc->m_sbrRatioIndex == 3) samplesPerFrame <<= 1;
+
               /* Mps212Config() ISO/IEC FDIS 23003-3 */
               if (cb->cbSsc(cb->cbSscData, hBs, asc->m_aot,
-                            asc->m_extensionSamplingFrequency,
+                            asc->m_extensionSamplingFrequency, samplesPerFrame,
                             usc->element[i].m_stereoConfigIndex,
                             usc->m_coreSbrFrameLengthIndex,
                             0, /* don't know the length */
@@ -2181,8 +2190,9 @@
     case AOT_MPEGS:
       if (cb->cbSsc != NULL) {
         if (cb->cbSsc(cb->cbSscData, bs, self->m_aot, self->m_samplingFrequency,
-                      1, -1, /* nTimeSlots: read from bitstream */
-                      0,     /* don't know the length */
+                      self->m_samplesPerFrame, 1,
+                      -1, /* nTimeSlots: read from bitstream */
+                      0,  /* don't know the length */
                       self->configMode, &self->SacConfigChanged)) {
           return TRANSPORTDEC_UNSUPPORTED_FORMAT;
         }
@@ -2365,10 +2375,17 @@
         /*usc->element[elemIdx].m_stereoConfigIndex =*/FDKreadBits(hBs, 2);
         if (usc->element[elemIdx].m_stereoConfigIndex > 0) {
           if (cb->cbSsc != NULL) {
+            int samplesPerFrame = asc->m_samplesPerFrame;
+
+            if (usc->m_sbrRatioIndex == 1) samplesPerFrame <<= 2;
+            if (usc->m_sbrRatioIndex == 2)
+              samplesPerFrame = (samplesPerFrame * 8) / 3;
+            if (usc->m_sbrRatioIndex == 3) samplesPerFrame <<= 1;
+
             ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc(
                 cb->cbSscData, hBs,
                 AOT_DRM_USAC, /* syntax differs from MPEG Mps212Config() */
-                asc->m_extensionSamplingFrequency,
+                asc->m_extensionSamplingFrequency, samplesPerFrame,
                 usc->element[elemIdx].m_stereoConfigIndex,
                 usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */
                 asc->configMode, &asc->SacConfigChanged);
diff --git a/libMpegTPEnc/include/tp_data.h b/libMpegTPEnc/include/tp_data.h
index 6f032d1..00de356 100644
--- a/libMpegTPEnc/include/tp_data.h
+++ b/libMpegTPEnc/include/tp_data.h
@@ -367,7 +367,8 @@
 typedef INT (*cbCtrlCFGChange_t)(void *, const CCtrlCFGChange *);
 typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM,
                        const AUDIO_OBJECT_TYPE coreCodec,
-                       const INT samplingRate, const INT stereoConfigIndex,
+                       const INT samplingRate, const INT frameSize,
+                       const INT stereoConfigIndex,
                        const INT coreSbrFrameLengthIndex, const INT configBytes,
                        const UCHAR configMode, UCHAR *configChanged);
 
diff --git a/libMpegTPEnc/src/tpenc_asc.cpp b/libMpegTPEnc/src/tpenc_asc.cpp
index ce4e364..0b484a0 100644
--- a/libMpegTPEnc/src/tpenc_asc.cpp
+++ b/libMpegTPEnc/src/tpenc_asc.cpp
@@ -795,7 +795,7 @@
 
     const INT eldExtLen =
         (cb->cbSsc(cb->cbSscData, NULL, config->aot, config->extSamplingRate, 0,
-                   0, 0, 0, NULL) +
+                   0, 0, 0, 0, NULL) +
          7) >>
         3;
     INT cnt = eldExtLen;
@@ -818,7 +818,7 @@
     }
 
     cb->cbSsc(cb->cbSscData, hBs, config->aot, config->extSamplingRate, 0, 0, 0,
-              0, NULL);
+              0, 0, NULL);
   }
 
   if (config->downscaleSamplingRate != 0 &&
diff --git a/libSACdec/include/sac_dec_lib.h b/libSACdec/include/sac_dec_lib.h
index 2797a10..9913279 100644
--- a/libSACdec/include/sac_dec_lib.h
+++ b/libSACdec/include/sac_dec_lib.h
@@ -315,9 +315,9 @@
  */
 SACDEC_ERROR mpegSurroundDecoder_Config(
     CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs,
-    AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT stereoConfigIndex,
-    INT coreSbrFrameLengthIndex, INT configBytes, const UCHAR configMode,
-    UCHAR *configChanged);
+    AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize,
+    INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes,
+    const UCHAR configMode, UCHAR *configChanged);
 
 SACDEC_ERROR
 mpegSurroundDecoder_ConfigureQmfDomain(
diff --git a/libSACdec/src/sac_bitdec.cpp b/libSACdec/src/sac_bitdec.cpp
index 1049c3d..883e1e8 100644
--- a/libSACdec/src/sac_bitdec.cpp
+++ b/libSACdec/src/sac_bitdec.cpp
@@ -517,6 +517,10 @@
 
   pSpatialSpecificConfig->tempShapeConfig =
       (SPATIALDEC_TS_CONF)FDKreadBits(bitstream, 2);
+  if (pSpatialSpecificConfig->tempShapeConfig > 2) {
+    return MPS_PARSE_ERROR; /* reserved value */
+  }
+
   pSpatialSpecificConfig->decorrConfig =
       (SPATIALDEC_DECORR_CONF)FDKreadBits(bitstream, 2);
   if (pSpatialSpecificConfig->decorrConfig > 2) {
diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp
index 7549e51..5792858 100644
--- a/libSACdec/src/sac_dec_lib.cpp
+++ b/libSACdec/src/sac_dec_lib.cpp
@@ -237,6 +237,11 @@
   SPATIAL_DEC_CONFIG decConfig;
 };
 
+SACDEC_ERROR
+static sscCheckOutOfBand(const SPATIAL_SPECIFIC_CONFIG *pSsc,
+                         const INT coreCodec, const INT sampleRate,
+                         const INT frameSize);
+
 static SACDEC_ERROR sscParseCheck(const SPATIAL_SPECIFIC_CONFIG *pSsc);
 
 /**
@@ -694,11 +699,13 @@
  **/
 SACDEC_ERROR mpegSurroundDecoder_Config(
     CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs,
-    AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT stereoConfigIndex,
-    INT coreSbrFrameLengthIndex, INT configBytes, const UCHAR configMode,
-    UCHAR *configChanged) {
+    AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize,
+    INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes,
+    const UCHAR configMode, UCHAR *configChanged) {
   SACDEC_ERROR err = MPS_OK;
   SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig;
+  SPATIAL_SPECIFIC_CONFIG *pSsc =
+      &pMpegSurroundDecoder->spatialSpecificConfigBackup;
 
   switch (coreCodec) {
     case AOT_DRM_USAC:
@@ -709,6 +716,7 @@
         err = SpatialDecParseMps212Config(
             hBs, &spatialSpecificConfig, samplingRate, coreCodec,
             stereoConfigIndex, coreSbrFrameLengthIndex);
+        pSsc = &spatialSpecificConfig;
       } else {
         err = SpatialDecParseMps212Config(
             hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
@@ -723,6 +731,7 @@
          * into temporarily allocated structure */
         err = SpatialDecParseSpecificConfig(hBs, &spatialSpecificConfig,
                                             configBytes, coreCodec);
+        pSsc = &spatialSpecificConfig;
       } else {
         err = SpatialDecParseSpecificConfig(
             hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
@@ -738,14 +747,21 @@
     goto bail;
   }
 
+  err = sscCheckOutOfBand(pSsc, coreCodec, samplingRate, frameSize);
+
+  if (err != MPS_OK) {
+    goto bail;
+  }
+
   if (configMode & AC_CM_DET_CFG_CHANGE) {
     return err;
   }
 
   if (configMode & AC_CM_ALLOC_MEM) {
     if (*configChanged) {
-      if ((err = mpegSurroundDecoder_Open(&pMpegSurroundDecoder,
-                                          stereoConfigIndex, NULL))) {
+      err = mpegSurroundDecoder_Open(&pMpegSurroundDecoder, stereoConfigIndex,
+                                     NULL);
+      if (err) {
         return err;
       }
     }
@@ -815,29 +831,9 @@
  * \return  MPS_OK on sucess, and else on parse error.
  */
 static SACDEC_ERROR sscParseCheck(const SPATIAL_SPECIFIC_CONFIG *pSsc) {
-  SACDEC_ERROR err = MPS_OK;
-
   if (pSsc->samplingFreq > 96000) return MPS_PARSE_ERROR;
   if (pSsc->samplingFreq < 8000) return MPS_PARSE_ERROR;
 
-  switch (pSsc->freqRes) {
-    case SPATIALDEC_FREQ_RES_28:
-    case SPATIALDEC_FREQ_RES_20:
-    case SPATIALDEC_FREQ_RES_14:
-    case SPATIALDEC_FREQ_RES_10:
-    case SPATIALDEC_FREQ_RES_23:
-    case SPATIALDEC_FREQ_RES_15:
-    case SPATIALDEC_FREQ_RES_12:
-    case SPATIALDEC_FREQ_RES_9:
-    case SPATIALDEC_FREQ_RES_7:
-    case SPATIALDEC_FREQ_RES_5:
-    case SPATIALDEC_FREQ_RES_4:
-      break;
-    case SPATIALDEC_FREQ_RES_40: /* 40 doesn't exist in ISO/IEC 23003-1 */
-    default:
-      return MPS_PARSE_ERROR;
-  }
-
   if ((pSsc->treeConfig < 0) || (pSsc->treeConfig > 7)) {
     return MPS_PARSE_ERROR;
   }
@@ -846,17 +842,9 @@
     return MPS_PARSE_ERROR;
   }
 
-  if (pSsc->tempShapeConfig == 3) {
-    return MPS_PARSE_ERROR;
-  }
-
-  if (pSsc->decorrConfig == 3) {
-    return MPS_PARSE_ERROR;
-  }
-
   /* now we are sure there were no parsing errors */
 
-  return err;
+  return MPS_OK;
 }
 
 /**
@@ -1024,6 +1012,11 @@
 
   FDK_ASSERT(pSsc != NULL);
 
+  /* check ssc for parse errors */
+  if (sscParseCheck(pSsc) != MPS_OK) {
+    err = MPS_PARSE_ERROR;
+  }
+
   /* core fs and mps fs must match */
   if (pSsc->samplingFreq != sampleRate) {
     err = MPS_PARSE_ERROR /* MPEGSDEC_SSC_PARSE_ERROR */;
@@ -1094,6 +1087,83 @@
 }
 
 /**
+ * \brief  Check out-of-band config
+ *
+ * \param pSsc         spatial specific config handle.
+ * \param coreCodec    core codec.
+ * \param sampleRate   sampling frequency.
+ *
+ * \return  errorStatus
+ */
+SACDEC_ERROR
+sscCheckOutOfBand(const SPATIAL_SPECIFIC_CONFIG *pSsc, const INT coreCodec,
+                  const INT sampleRate, const INT frameSize) {
+  FDK_ASSERT(pSsc != NULL);
+  int qmfBands = 0;
+
+  /* check ssc for parse errors */
+  if (sscParseCheck(pSsc) != MPS_OK) {
+    return MPS_PARSE_ERROR;
+  }
+
+  switch (coreCodec) {
+    case AOT_USAC:
+    case AOT_DRM_USAC:
+      /* ISO/IEC 23003-1:2007(E), Chapter 6.3.3, Support for lower and higher
+       * sampling frequencies */
+      if (pSsc->samplingFreq >= 55426) {
+        return MPS_PARSE_ERROR;
+      }
+      break;
+    case AOT_ER_AAC_LD:
+    case AOT_ER_AAC_ELD:
+      /* core fs and mps fs must match */
+      if (pSsc->samplingFreq != sampleRate) {
+        return MPS_PARSE_ERROR;
+      }
+
+      /* ISO/IEC 14496-3:2009 FDAM 3: Chapter 1.5.2.3, Levels for the Low Delay
+       * AAC v2 profile */
+      if (pSsc->samplingFreq > 48000) {
+        return MPS_PARSE_ERROR;
+      }
+
+      qmfBands = mpegSurroundDecoder_GetNrOfQmfBands(pSsc, pSsc->samplingFreq);
+      switch (frameSize) {
+        case 480:
+          if (!((qmfBands == 32) && (pSsc->nTimeSlots == 15))) {
+            return MPS_PARSE_ERROR;
+          }
+          break;
+        case 960:
+          if (!((qmfBands == 64) && (pSsc->nTimeSlots == 15))) {
+            return MPS_PARSE_ERROR;
+          }
+          break;
+        case 512:
+          if (!(((qmfBands == 32) && (pSsc->nTimeSlots == 16)) ||
+                ((qmfBands == 64) && (pSsc->nTimeSlots == 8)))) {
+            return MPS_PARSE_ERROR;
+          }
+          break;
+        case 1024:
+          if (!((qmfBands == 64) && (pSsc->nTimeSlots == 16))) {
+            return MPS_PARSE_ERROR;
+          }
+          break;
+        default:
+          return MPS_PARSE_ERROR;
+      }
+      break;
+    default:
+      return MPS_PARSE_ERROR;
+      break;
+  }
+
+  return MPS_OK;
+}
+
+/**
  * \brief Decode MPEG Surround frame.
  **/
 int mpegSurroundDecoder_ParseNoHeader(