Decode dynamic range control improvements

* AAC-Decoder

   - Only set the program reference level if it has changed compared to the
     previous value. This allows setting it on a frame-by-frame basis without
     limitations.
     Modified file(s):
        libAACdec/src/aacdec_drc.cpp
        libAACdec/src/aacdec_drc.h

   - Add expiry counter for the program reference level.
     Modified file(s):
        libAACdec/src/aacdec_drc.cpp
        libAACdec/src/aacdec_drc_types.h

   - Disable scaling of light compression gain values when heavy compression
     mode is enabled to have the full light compression as fallback if no heavy
     values are available.
     Modified file(s):
        libAACdec/src/aacdec_drc.cpp
        libAACdec/src/aacdecoder_lib.cpp
        libAACdec/src/aacdec_drc_types.h

   - Change initialization and channel disabling to improve start-up behavior in
     SBR decoder.
     Modified file(s):
        libSBRdec/src/sbrdecoder.cpp
        libSBRdec/src/sbrdec_drc.cpp

Bug 9428126

Change-Id: Ie1d3949c53910506da2547d32fe3bf6ee7606eb4
diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp
index 942a651..2666454 100644
--- a/libAACdec/src/aacdec_drc.cpp
+++ b/libAACdec/src/aacdec_drc.cpp
@@ -135,10 +135,13 @@
   /* init params */
   pParams = &self->params;
   pParams->bsDelayEnable = 0;
-  pParams->cut   = FL2FXCONST_DBL(0.0f);
-  pParams->boost = FL2FXCONST_DBL(0.0f);
+  pParams->cut      = FL2FXCONST_DBL(0.0f);
+  pParams->usrCut   = FL2FXCONST_DBL(0.0f);
+  pParams->boost    = FL2FXCONST_DBL(0.0f);
+  pParams->usrBoost = FL2FXCONST_DBL(0.0f);
   pParams->targetRefLevel = AACDEC_DRC_DEFAULT_REF_LEVEL;
   pParams->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES;
+  pParams->applyHeavyCompression = 0;
 
   /* initial program ref level = target ref level */
   self->progRefLevel = pParams->targetRefLevel;
@@ -193,7 +196,9 @@
     if (self == NULL) {
       return AAC_DEC_INVALID_HANDLE;
     }
-    self->params.cut = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)value);
+    self->params.usrCut = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)value);
+    if (self->params.applyHeavyCompression == 0)
+      self->params.cut = self->params.usrCut;
     break;
   case DRC_BOOST_SCALE:
     /* set boost factor */
@@ -204,7 +209,9 @@
     if (self == NULL) {
       return AAC_DEC_INVALID_HANDLE;
     }
-    self->params.boost = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)value);
+    self->params.usrBoost = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)value);
+    if (self->params.applyHeavyCompression == 0)
+      self->params.boost = self->params.usrBoost;
     break;
   case TARGET_REF_LEVEL:
     if ( value >  MAX_REFERENCE_LEVEL
@@ -220,9 +227,11 @@
     else {
       /* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */
       self->digitalNorm    = 1;
-      self->params.targetRefLevel = value;
-      self->progRefLevel = (SCHAR)value;  /* Set the program reference level equal to the target
-                                               level according to 4.5.2.7.3 of ISO/IEC 14496-3. */
+      if (self->params.targetRefLevel != (SCHAR)value) {
+        self->params.targetRefLevel = (SCHAR)value;
+        self->progRefLevel = (SCHAR)value;  /* Always set the program reference level equal to the
+                                               target level according to 4.5.2.7.3 of ISO/IEC 14496-3. */
+      }
     }
     break;
   case APPLY_HEAVY_COMPRESSION:
@@ -232,7 +241,19 @@
     if (self == NULL) {
       return AAC_DEC_INVALID_HANDLE;
     }
-    self->params.applyHeavyCompression = (UCHAR)value;
+    if (self->params.applyHeavyCompression != (UCHAR)value) {
+      if (value == 1) {
+        /* Disable scaling of DRC values by setting the max values */
+        self->params.boost = FL2FXCONST_DBL(1.0f/(float)(1<<DRC_PARAM_SCALE));
+        self->params.cut   = FL2FXCONST_DBL(1.0f/(float)(1<<DRC_PARAM_SCALE));
+      } else {
+        /* Restore the user params */
+        self->params.boost = self->params.usrBoost;
+        self->params.cut   = self->params.usrCut;
+      }
+      /* Store new parameter value */
+      self->params.applyHeavyCompression = (UCHAR)value;
+    }
     break;
   case DRC_BS_DELAY:
     if (value < 0 || value > 1) {
@@ -473,7 +494,7 @@
     }
   }
   else {
-    pDrcBs->channelData.bandTop[0] = 255;
+    pDrcBs->channelData.bandTop[0] = (1024 >> 2) - 1;  /* ... comprising the whole spectrum. */;
   }
 
   pDrcBs->channelData.numBands = numBands;
@@ -627,10 +648,17 @@
 {
   CDrcPayload  threadBs[MAX_DRC_THREADS];
   CDrcPayload *validThreadBs[MAX_DRC_THREADS];
+  CDrcParams  *pParams;
   UINT backupBsPosition;
   int  i, thread, validThreads = 0;
   int  numExcludedChns[MAX_DRC_THREADS];
 
+  FDK_ASSERT(self != NULL);
+  FDK_ASSERT(hBs != NULL);
+  FDK_ASSERT(pAacDecoderStaticChannelInfo != NULL);
+
+  pParams = &self->params;
+
   self->numThreads = 0;
   backupBsPosition = FDKgetValidBits(hBs);
 
@@ -752,6 +780,7 @@
      */
     if (pThreadBs->progRefLevel >= 0) {
       self->progRefLevel = pThreadBs->progRefLevel;
+      self->prlExpiryCount = 0;  /* Got a new value -> Reset counter */
     }
 
     /* SCE, CPE and LFE */
@@ -769,6 +798,14 @@
     /* CCEs not supported by now */
   }
 
+  /* Increment and check expiry counter for the program reference level: */
+  if ( (pParams->expiryFrame > 0)
+    && (self->prlExpiryCount++ > pParams->expiryFrame) )
+  { /* The program reference level is too old, so set it back to the target level. */
+    self->progRefLevel = pParams->targetRefLevel;
+    self->prlExpiryCount = 0;
+  }
+
   return 0;
 }
 
diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h
index 124b6f5..2ebae2c 100644
--- a/libAACdec/src/aacdec_drc.h
+++ b/libAACdec/src/aacdec_drc.h
@@ -143,6 +143,16 @@
         UCHAR  channelMapping[],
         int    numChannels );
 
+/**
+ * \brief Apply DRC. If SBR is present, DRC data is handed over to the SBR decoder.
+ * \param self AAC decoder instance
+ * \param pSbrDec pointer to SBR decoder instance
+ * \param pAacDecoderChannelInfo AAC decoder channel instance to be processed
+ * \param pDrcDat DRC channel data
+ * \param ch channel index
+ * \param aacFrameSize AAC frame size
+ * \param bSbrPresent flag indicating that SBR is present, in which case DRC is handed over to the SBR instance pSbrDec
+ */
 void aacDecoder_drcApply (
         HANDLE_AAC_DRC          self,
         void                   *pSbrDec,
diff --git a/libAACdec/src/aacdec_drc_types.h b/libAACdec/src/aacdec_drc_types.h
index e7c6f1a..1b5cd76 100644
--- a/libAACdec/src/aacdec_drc_types.h
+++ b/libAACdec/src/aacdec_drc_types.h
@@ -132,8 +132,10 @@
 
 typedef struct
 {
-  FIXP_DBL  cut;
-  FIXP_DBL  boost;
+  FIXP_DBL  cut;       /* The attenuation scale factor currently used.     */
+  FIXP_DBL  usrCut;    /* The latest attenuation scale factor set by user. */
+  FIXP_DBL  boost;     /* The boost scale factor currently used.           */
+  FIXP_DBL  usrBoost;  /* The latest boost scale factor set by user.       */
 
   UINT   expiryFrame;
   SCHAR  targetRefLevel;
@@ -154,6 +156,8 @@
   USHORT numThreads;                         /* The number of DRC data threads extracted from the found payload elements */
   SCHAR  progRefLevel;                       /* Program reference level for all channels */
 
+  UINT   prlExpiryCount;                     /* Counter that can be used to monitor the life time of the program reference level. */
+
   UCHAR  dvbAncDataAvailable;                  /* Flag that indicates whether DVB ancillary data is present or not */
   UINT   dvbAncDataPosition;                   /* Used to store the DVB ancillary data payload position in the bitstream (only one per frame) */
   UINT   drcPayloadPosition[MAX_DRC_THREADS];  /* Used to store the DRC payload positions in the bitstream */
diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp
index 5f0be30..247fcef 100644
--- a/libAACdec/src/aacdecoder_lib.cpp
+++ b/libAACdec/src/aacdecoder_lib.cpp
@@ -110,7 +110,7 @@
 /* Decoder library info */
 #define AACDECODER_LIB_VL0 2
 #define AACDECODER_LIB_VL1 5
-#define AACDECODER_LIB_VL2 2
+#define AACDECODER_LIB_VL2 3
 #define AACDECODER_LIB_TITLE "AAC Decoder Lib"
 #define AACDECODER_LIB_BUILD_DATE __DATE__
 #define AACDECODER_LIB_BUILD_TIME __TIME__
diff --git a/libSBRdec/src/sbrdec_drc.cpp b/libSBRdec/src/sbrdec_drc.cpp
index af71c41..a834c0b 100644
--- a/libSBRdec/src/sbrdec_drc.cpp
+++ b/libSBRdec/src/sbrdec_drc.cpp
@@ -127,8 +127,8 @@
   hDrcData->currFact_exp = 1;
   hDrcData->nextFact_exp = 1;
 
-  hDrcData->numBandsCurr = 0;
-  hDrcData->numBandsNext = 0;
+  hDrcData->numBandsCurr = 1;
+  hDrcData->numBandsNext = 1;
 
   hDrcData->winSequenceCurr = 0;
   hDrcData->winSequenceNext = 0;
@@ -490,9 +490,7 @@
   if (hDrcData == NULL) {
     return;
   }
-  if ( (hDrcData->enable == 0)
-    || ((hDrcData->numBandsCurr == 0) && (hDrcData->numBandsNext == 0))
-     ) {
+  if (hDrcData->enable == 0) {
     return;  /* Avoid changing the scaleFactor even though the processing is disabled. */
   }
 
diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp
index a0668bd..ecddec3 100644
--- a/libSBRdec/src/sbrdecoder.cpp
+++ b/libSBRdec/src/sbrdecoder.cpp
@@ -137,7 +137,7 @@
 /* Decoder library info */
 #define SBRDECODER_LIB_VL0 2
 #define SBRDECODER_LIB_VL1 2
-#define SBRDECODER_LIB_VL2 1
+#define SBRDECODER_LIB_VL2 2
 #define SBRDECODER_LIB_TITLE "SBR Decoder"
 #define SBRDECODER_LIB_BUILD_DATE __DATE__
 #define SBRDECODER_LIB_BUILD_TIME __TIME__
@@ -878,7 +878,7 @@
   pSbrDrcChannelData = sbrDecoder_drcGetChannel( self, ch );
 
   if ( pSbrDrcChannelData != NULL ) {
-    pSbrDrcChannelData->enable = 0;
+    sbrDecoder_drcInitChannel( pSbrDrcChannelData );
   }
 }