Mark ab/7061308 as merged in stage.

Bug: 180401296
Merged-In: Id04d2590c249cad13da8dd8975d0a12ce96a9597
Change-Id: I4da99b78b01817308d8572d3c0d5b224b7d36a73
diff --git a/Android.bp b/Android.bp
index 555223b..0c67186 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,36 @@
+// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS.  PLEASE
+//     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+//     DEPENDING ON IT IN YOUR PROJECT. ***
+package {
+    default_applicable_licenses: ["external_aac_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+    name: "external_aac_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "legacy_by_exception_only", // by exception only
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_static {
     name: "libFraunhoferAAC",
     vendor_available: true,
@@ -32,8 +65,7 @@
             "signed-integer-overflow",
             "bounds",
         ],
-        // Enable CFI if this becomes a shared library.
-        // cfi: true,
+        cfi: true,
     },
     shared_libs: [
         "liblog",
diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp
index 28a21b9..6739798 100644
--- a/fuzzer/Android.bp
+++ b/fuzzer/Android.bp
@@ -18,17 +18,21 @@
  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
  */
 
-cc_fuzz {
-    name: "aac_dec_fuzzer",
-    host_supported:true,
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_aac_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["external_aac_license"],
+}
+
+cc_defaults {
+    name: "aac_fuzz_defaults",
+    host_supported: true,
 
     static_libs: [
         "libFraunhoferAAC",
-        "liblog",
-    ],
-
-    srcs: [
-        "aac_dec_fuzzer.cpp",
     ],
 
     target: {
@@ -44,3 +48,35 @@
         componentid: 155276,
     },
 }
+
+cc_fuzz {
+    name: "aac_dec_fuzzer",
+
+    srcs: [
+        "aac_dec_fuzzer.cpp",
+    ],
+
+    static_libs: [
+        "liblog",
+    ],
+
+    defaults: [
+        "aac_fuzz_defaults"
+    ],
+}
+
+cc_fuzz {
+    name: "aac_enc_fuzzer",
+
+    srcs: [
+        "aac_enc_fuzzer.cpp",
+    ],
+
+    defaults: [
+        "aac_fuzz_defaults"
+    ],
+
+    include_dirs: [
+        "external/aac/libAACenc/"
+    ],
+}
diff --git a/fuzzer/README.md b/fuzzer/README.md
index d99bc75..b8cc260 100644
--- a/fuzzer/README.md
+++ b/fuzzer/README.md
@@ -53,7 +53,98 @@
   $ $ANDROID_HOST_OUT/fuzz/x86_64/aac_dec_fuzzer/aac_dec_fuzzer CORPUS_DIR
 ```
 
+# Fuzzer for libFraunhoferAAC encoder
+
+## Plugin Design Considerations
+The fuzzer plugin for aac encoder is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+Following arguments are passed to aacEncoder_SetParam to set the respective AACENC_PARAM parameter:
+
+| AACENC_PARAM param| Valid Values| Configured Value|
+|-------------| ----- |----- |
+|`AACENC_SBR_MODE` | `-1 ` `0 ` `1 ` `2 ` | Calculated using first byte of data |
+|`AACENC_AOT` |`AOT_NONE ` `AOT_NULL_OBJECT ` `AOT_AAC_MAIN ` `AOT_AAC_LC ` `AOT_AAC_SSR ` `AOT_AAC_LTP ` `AOT_SBR ` `AOT_AAC_SCAL ` `AOT_TWIN_VQ ` `AOT_CELP ` `AOT_HVXC ` `AOT_RSVD_10 ` `AOT_RSVD_11 ` `AOT_TTSI ` `AOT_MAIN_SYNTH ` `AOT_WAV_TAB_SYNTH ` `AOT_GEN_MIDI ` `AOT_ALG_SYNTH_AUD_FX ` `AOT_ER_AAC_LC ` `AOT_RSVD_18 ` `AOT_ER_AAC_LTP ` `AOT_ER_AAC_SCAL ` `AOT_ER_TWIN_VQ ` `AOT_ER_BSAC ` `AOT_ER_AAC_LD ` `AOT_ER_CELP ` `AOT_ER_HVXC ` `AOT_ER_HILN ` `AOT_ER_PARA ` `AOT_RSVD_28 ` `AOT_PS ` `AOT_MPEGS ` `AOT_ESCAPE ` `AOT_MP3ONMP4_L1 ` `AOT_MP3ONMP4_L2 ` `AOT_MP3ONMP4_L3 ` `AOT_RSVD_35 ` `AOT_RSVD_36 ` `AOT_AAC_SLS ` `AOT_SLS ` `AOT_ER_AAC_ELD ` `AOT_USAC ` `AOT_SAOC ` `AOT_LD_MPEGS ` `AOT_MP2_AAC_LC ` `AOT_MP2_SBR ` `AOT_DRM_AAC ` `AOT_DRM_SBR ` `AOT_DRM_MPEG_PS ` `AOT_DRM_SURROUND ` `AOT_DRM_USAC `  | Calculated using second byte of data  |
+|`AACENC_SAMPLERATE` |  `8000 ` `11025 ` `12000 ` `16000 ` `22050 ` `24000 ` `32000 ` `44100 ` `48000 ` `64000 ` `88200 ` `96000 `| Calculated using third byte of data  |
+|`AACENC_BITRATE` | In range `8000 ` to `960000 ` | Calculated using fourth, fifth and sixth byte of data  |
+|`AACENC_CHANNELMODE` | `MODE_1 ` `MODE_2 ` `MODE_1_2 ` `MODE_1_2_1 ` `MODE_1_2_2 ` `MODE_1_2_2_1 ` `MODE_1_2_2_2_1 ` `MODE_6_1 `  `MODE_7_1_BACK ` `MODE_7_1_TOP_FRONT ` `MODE_7_1_REAR_SURROUND ` `MODE_7_1_FRONT_CENTER ` `MODE_212 ` | Calculated using seventh byte of data |
+|`AACENC_TRANSMUX` | `TT_MP4_RAW ` `TT_MP4_ADIF ` `TT_MP4_ADTS ` `TT_MP4_LATM_MCP1 ` `TT_MP4_LATM_MCP0 ` `TT_MP4_LOAS ` `TT_DRM `  | Calculated using eight byte of data  |`AACENC_SBR_RATIO` |`-1 ` `0 ` `1 ` `2 ` | Calculated using ninth byte of data |
+|`AACENC_BITRATEMODE` |`AACENC_BR_MODE_INVALID ` `AACENC_BR_MODE_CBR ` `AACENC_BR_MODE_VBR_1 ` `AACENC_BR_MODE_VBR_2 ` `AACENC_BR_MODE_VBR_3 ` `AACENC_BR_MODE_VBR_4 ` `AACENC_BR_MODE_VBR_5 ` `AACENC_BR_MODE_FF ` `AACENC_BR_MODE_SFR `  | Calculated using thirty-fourth byte of data |
+|`AACENC_GRANULE_LENGTH` |`120 ` `128 ` `240 ` `256 ` `480 ` `512 ` `1024 ` | Calculated using thirty-fifth byte of data |
+|`AACENC_CHANNELORDER` |`CH_ORDER_MPEG ` `CH_ORDER_WAV ` | Calculated using thirty-sixth byte of data |
+|`AACENC_AFTERBURNER` |`0 ` `1 ` | Calculated using thirty-seventh byte of data |
+|`AACENC_BANDWIDTH` |`0 ` `1`  | Calculated using thirty-eigth byte of data |
+|` AACENC_IDX_PEAK_BITRATE` | In range `8000 ` to `960000 ` | Calculated using thirty-ninth byte of data |
+|` AACENC_HEADER_PERIOD` |In range `0 ` to `255 ` | Calculated using fortieth byte of data |
+|` AACENC_SIGNALING_MODE` |`-1 ` `0 ` `1 ` `2 ` `3 `  | Calculated using forty-first byte of data |
+|` AACENC_TPSUBFRAMES` |In range `0 ` to `255 ` | Calculated using forty-second byte of data |
+|` AACENC_AUDIOMUXVER` |`-1 ` `0 ` `1 ` `2 ` | Calculated using forty-third byte of data |
+|` AACENC_PROTECTION` |`0 ` `1 ` | Calculated using forty-fourth of data |
+|`AACENC_ANCILLARY_BITRATE` |In range `0 ` to `960000 `| Calculated using forty-fifth byte of data |
+|`AACENC_METADATA_MODE ` |`0 ` `1 ` `2 ` `3 ` | Calculated using forty-sixth byte of data |
+
+Following values are configured to set up the meta data represented by the class variable `mMetaData ` :
+
+| Variable name| Possible Values| Configured Value|
+|------------- | ----- |----- |
+| `drc_profile`   | `AACENC_METADATA_DRC_NONE ` `AACENC_METADATA_DRC_FILMSTANDARD ` `AACENC_METADATA_DRC_FILMLIGHT ` `AACENC_METADATA_DRC_MUSICSTANDARD ` `AACENC_METADATA_DRC_MUSICLIGHT ` `AACENC_METADATA_DRC_SPEECH ` `AACENC_METADATA_DRC_NOT_PRESENT `  | Calculated using tenth byte of data |
+| `comp_profile`   | `AACENC_METADATA_DRC_NONE ` `AACENC_METADATA_DRC_FILMSTANDARD ` `AACENC_METADATA_DRC_FILMLIGHT ` `AACENC_METADATA_DRC_MUSICSTANDARD ` `AACENC_METADATA_DRC_MUSICLIGHT ` `AACENC_METADATA_DRC_SPEECH ` `AACENC_METADATA_DRC_NOT_PRESENT `  | Calculated using eleventh byte of data |
+| `drc_TargetRefLevel`   | In range `0 ` to `255 `  | Calculated using twelfth byte of data |
+| `comp_TargetRefLevel`   | In range `0 ` to `255 `  | Calculated using thirteenth byte of data |
+| `prog_ref_level_present`   | `0 ` `1 `  | Calculated using fourteenth byte of data |
+| `prog_ref_level`   | In range `0 ` to `255 `  | Calculated using fifteenth byte of data |
+| `PCE_mixdown_idx_present`   | `0 ` `1 `   | Calculated using sixteenth byte of data |
+| `ETSI_DmxLvl_present`   | `0 ` `1 `   | Calculated using seventeenth byte of data |
+| `centerMixLevel`   | In range `0 ` to `7 `  | Calculated using eighteenth byte of data |
+| `surroundMixLevel`   | In range `0 ` to `7 `  | Calculated using nineteenth byte of data |
+| `dolbySurroundMode`   | In range `0 ` to `2 `   | Calculated using twentieth byte of data |
+| `drcPresentationMode`   | In range `0 ` to `2 `   | Calculated using twenty-first byte of data |
+| `extAncDataEnable`   | `0 ` `1 `  | Calculated using twenty-second byte of data |
+| `extDownmixLevelEnable`   | `0 ` `1 `  | Calculated using twenty-third byte of data |
+| `extDownmixLevel_A`   | In range `0 ` to `7 `  | Calculated using twenty-fourth byte of data |
+| `extDownmixLevel_B`   | In range `0 ` to `7 `  | Calculated using twenty-fifth byte of data |
+| `dmxGainEnable`   |  `0 ` `1 `   | Calculated using twenty-sixth byte of data |
+| `dmxGain5`   | In range `0 ` to `255 `  | Calculated using twenty-seventh byte of data |
+| `dmxGain2`   | In range `0 ` to `255 `  | Calculated using twenty-eighth byte of data |
+| `lfeDmxEnable`   | `0 ` `1 `  | Calculated using twenty-ninth byte of data |
+| `lfeDmxLevel`   | In range `0 ` to `15 `  | Calculated using thirtieth byte of data |
+
+Indexes `mInBufferIdx_1`, `mInBufferIdx_2`  and `mInBufferIdx_3`(in range `0 ` to `2`) are calculated using the thirty-first, thirty-second and thirty-third byte respectively.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec and continues with the encoding even on a failure. This ensures that the plugin tolerates any kind of input (empty, huge, malformed, etc) and doesnt `exit()` on any input and thereby increasing the chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build aac_enc_fuzzer binary.
+
+## Android
+
+### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) aac_enc_fuzzer
+```
+
+### Steps to run
+Create a directory CORPUS_DIR and copy some raw files to that folder.
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/aac_enc_fuzzer/aac_enc_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/aac_enc_fuzzer/aac_enc_fuzzer CORPUS_DIR
+```
+
 ## References:
  * http://llvm.org/docs/LibFuzzer.html
  * https://github.com/google/oss-fuzz
-
diff --git a/fuzzer/aac_enc_fuzzer.cpp b/fuzzer/aac_enc_fuzzer.cpp
new file mode 100644
index 0000000..5a35d70
--- /dev/null
+++ b/fuzzer/aac_enc_fuzzer.cpp
@@ -0,0 +1,479 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+#include <string>
+#include "aacenc_lib.h"
+#include "src/aacenc.h"
+
+using namespace std;
+
+// IN_AUDIO_DATA, IN_ANCILLRY_DATA and IN_METADATA_SETUP
+constexpr size_t kMaxBuffers = 3;
+
+constexpr size_t kMaxOutputBufferSize = 8192;
+
+constexpr uint32_t kMinBitRate = 8000;
+constexpr uint32_t kMaxBitRate = 960000;
+
+constexpr int32_t kSampleRates[] = {8000,  11025, 12000, 16000, 22050, 24000,
+                                    32000, 44100, 48000, 64000, 88200, 96000};
+constexpr size_t kSampleRatesSize = size(kSampleRates);
+
+constexpr CHANNEL_MODE kChannelModes[] = {MODE_1,
+                                          MODE_2,
+                                          MODE_1_2,
+                                          MODE_1_2_1,
+                                          MODE_1_2_2,
+                                          MODE_1_2_2_1,
+                                          MODE_1_2_2_2_1,
+                                          MODE_6_1,
+                                          MODE_7_1_BACK,
+                                          MODE_7_1_TOP_FRONT,
+                                          MODE_7_1_REAR_SURROUND,
+                                          MODE_7_1_FRONT_CENTER,
+                                          MODE_212};
+constexpr size_t kChannelModesSize = size(kChannelModes);
+
+constexpr TRANSPORT_TYPE kIdentifiers[] = {
+    TT_MP4_RAW, TT_MP4_ADIF, TT_MP4_ADTS, TT_MP4_LATM_MCP1, TT_MP4_LATM_MCP0, TT_MP4_LOAS, TT_DRM};
+constexpr size_t kIdentifiersSize = size(kIdentifiers);
+
+constexpr AUDIO_OBJECT_TYPE kAudioObjectTypes[] = {AOT_NONE,        AOT_NULL_OBJECT,
+                                                   AOT_AAC_MAIN,    AOT_AAC_LC,
+                                                   AOT_AAC_SSR,     AOT_AAC_LTP,
+                                                   AOT_SBR,         AOT_AAC_SCAL,
+                                                   AOT_TWIN_VQ,     AOT_CELP,
+                                                   AOT_HVXC,        AOT_RSVD_10,
+                                                   AOT_RSVD_11,     AOT_TTSI,
+                                                   AOT_MAIN_SYNTH,  AOT_WAV_TAB_SYNTH,
+                                                   AOT_GEN_MIDI,    AOT_ALG_SYNTH_AUD_FX,
+                                                   AOT_ER_AAC_LC,   AOT_RSVD_18,
+                                                   AOT_ER_AAC_LTP,  AOT_ER_AAC_SCAL,
+                                                   AOT_ER_TWIN_VQ,  AOT_ER_BSAC,
+                                                   AOT_ER_AAC_LD,   AOT_ER_CELP,
+                                                   AOT_ER_HVXC,     AOT_ER_HILN,
+                                                   AOT_ER_PARA,     AOT_RSVD_28,
+                                                   AOT_PS,          AOT_MPEGS,
+                                                   AOT_ESCAPE,      AOT_MP3ONMP4_L1,
+                                                   AOT_MP3ONMP4_L2, AOT_MP3ONMP4_L3,
+                                                   AOT_RSVD_35,     AOT_RSVD_36,
+                                                   AOT_AAC_SLS,     AOT_SLS,
+                                                   AOT_ER_AAC_ELD,  AOT_USAC,
+                                                   AOT_SAOC,        AOT_LD_MPEGS,
+                                                   AOT_MP2_AAC_LC,  AOT_MP2_SBR,
+                                                   AOT_DRM_AAC,     AOT_DRM_SBR,
+                                                   AOT_DRM_MPEG_PS, AOT_DRM_SURROUND,
+                                                   AOT_DRM_USAC};
+
+constexpr size_t kAudioObjectTypesSize = size(kAudioObjectTypes);
+
+constexpr int32_t kSbrRatios[] = {-1, 0, 1, 2};
+constexpr size_t kSbrRatiosSize = size(kSbrRatios);
+
+constexpr int32_t kBitRateModes[] = {
+    AACENC_BR_MODE_INVALID, AACENC_BR_MODE_CBR,   AACENC_BR_MODE_VBR_1,
+    AACENC_BR_MODE_VBR_2,   AACENC_BR_MODE_VBR_3, AACENC_BR_MODE_VBR_4,
+    AACENC_BR_MODE_VBR_5,   AACENC_BR_MODE_FF,    AACENC_BR_MODE_SFR};
+constexpr size_t kBitRateModesSize = size(kBitRateModes);
+
+constexpr int32_t kGranuleLengths[] = {120, 128, 240, 256, 480, 512, 1024};
+constexpr size_t kGranuleLengthsSize = size(kGranuleLengths);
+
+constexpr int32_t kChannelOrder[] = {CH_ORDER_MPEG, CH_ORDER_WAV};
+constexpr size_t kChannelOrderSize = size(kChannelOrder);
+
+constexpr int32_t kSignalingModes[] = {-1, 0, 1, 2, 3};
+constexpr size_t kSignalingModesSize = size(kSignalingModes);
+
+constexpr int32_t kAudioMuxVer[] = {-1, 0, 1, 2};
+constexpr size_t kAudioMuxVerSize = size(kAudioMuxVer);
+
+constexpr int32_t kSbrModes[] = {-1, 0, 1, 2};
+constexpr size_t kSbrModesSize = size(kSbrModes);
+
+constexpr AACENC_METADATA_DRC_PROFILE kMetaDataDrcProfiles[] = {
+    AACENC_METADATA_DRC_NONE,       AACENC_METADATA_DRC_FILMSTANDARD,
+    AACENC_METADATA_DRC_FILMLIGHT,  AACENC_METADATA_DRC_MUSICSTANDARD,
+    AACENC_METADATA_DRC_MUSICLIGHT, AACENC_METADATA_DRC_SPEECH,
+    AACENC_METADATA_DRC_NOT_PRESENT};
+constexpr size_t kMetaDataDrcProfilesSize = size(kMetaDataDrcProfiles);
+
+enum {
+    IDX_SBR_MODE = 0,
+    IDX_AAC_AOT,
+    IDX_SAMPLE_RATE,
+    IDX_BIT_RATE_1,
+    IDX_BIT_RATE_2,
+    IDX_BIT_RATE_3,
+    IDX_CHANNEL,
+    IDX_IDENTIFIER,
+    IDX_SBR_RATIO,
+    IDX_METADATA_DRC_PROFILE,
+    IDX_METADATA_COMP_PROFILE,
+    IDX_METADATA_DRC_TARGET_REF_LEVEL,
+    IDX_METADATA_COMP_TARGET_REF_LEVEL,
+    IDX_METADATA_PROG_LEVEL_PRESENT,
+    IDX_METADATA_PROG_LEVEL,
+    IDX_METADATA_PCE_MIXDOWN_IDX_PRESENT,
+    IDX_METADATA_ETSI_DMXLVL_PRESENT,
+    IDX_METADATA_CENTER_MIX_LEVEL,
+    IDX_METADATA_SURROUND_MIX_LEVEL,
+    IDX_METADATA_DOLBY_SURROUND_MODE,
+    IDX_METADATA_DRC_PRESENTATION_MODE,
+    IDX_METADATA_EXT_ANC_DATA_ENABLE,
+    IDX_METADATA_EXT_DOWNMIX_LEVEL_ENABLE,
+    IDX_METADATA_EXT_DOWNMIX_LEVEL_A,
+    IDX_METADATA_EXT_DOWNMIX_LEVEL_B,
+    IDX_METADATA_DMX_GAIN_ENABLE,
+    IDX_METADATA_DMX_GAIN_5,
+    IDX_METADATA_DMX_GAIN_2,
+    IDX_METADATA_LFE_DMX_ENABLE,
+    IDX_METADATA_LFE_DMX_LEVEL,
+    IDX_IN_BUFFER_INDEX_1,
+    IDX_IN_BUFFER_INDEX_2,
+    IDX_IN_BUFFER_INDEX_3,
+    IDX_BIT_RATE_MODE,
+    IDX_GRANULE_LENGTH,
+    IDX_CHANNELORDER,
+    IDX_AFTERBURNER,
+    IDX_BANDWIDTH,
+    IDX_PEAK_BITRATE,
+    IDX_HEADER_PERIOD,
+    IDX_SIGNALING_MODE,
+    IDX_TPSUBFRAMES,
+    IDX_AUDIOMUXVER,
+    IDX_PROTECTION,
+    IDX_ANCILLARY_BITRATE,
+    IDX_METADATA_MODE,
+    IDX_LAST
+};
+
+template <typename type1, typename type2, typename type3>
+auto generateNumberInRangeFromData(type1 data, type2 min, type3 max) -> decltype(max) {
+    return (data % (1 + max - min)) + min;
+}
+
+class Codec {
+   public:
+    ~Codec() { deInitEncoder(); }
+    bool initEncoder(uint8_t **dataPtr, size_t *sizePtr);
+    void encodeFrames(const uint8_t *data, size_t size);
+    void deInitEncoder();
+
+   private:
+    template <typename type1, typename type2, typename type3>
+    void setAACParam(type1 data, const AACENC_PARAM aacParam, type2 min, type2 max,
+                     const type3 *array = nullptr);
+    void setupMetaData(uint8_t *data);
+
+    HANDLE_AACENCODER mEncoder = nullptr;
+    AACENC_MetaData mMetaData = {};
+    uint32_t mInBufferIdx_1 = 0;
+    uint32_t mInBufferIdx_2 = 0;
+    uint32_t mInBufferIdx_3 = 0;
+};
+
+void Codec::setupMetaData(uint8_t *data) {
+    uint32_t drcProfileIndex = generateNumberInRangeFromData(data[IDX_METADATA_DRC_PROFILE], 0,
+                                                             kMetaDataDrcProfilesSize - 1);
+    AACENC_METADATA_DRC_PROFILE drcProfile = kMetaDataDrcProfiles[drcProfileIndex];
+    mMetaData.drc_profile = drcProfile;
+
+    uint32_t compProfileIndex = generateNumberInRangeFromData(data[IDX_METADATA_COMP_PROFILE], 0,
+                                                              kMetaDataDrcProfilesSize - 1);
+    AACENC_METADATA_DRC_PROFILE compProfile = kMetaDataDrcProfiles[compProfileIndex];
+    mMetaData.comp_profile = compProfile;
+
+    INT drcTargetRefLevel =
+        generateNumberInRangeFromData(data[IDX_METADATA_DRC_TARGET_REF_LEVEL], 0, UINT8_MAX);
+    mMetaData.drc_TargetRefLevel = drcTargetRefLevel;
+
+    INT compTargetRefLevel =
+        generateNumberInRangeFromData(data[IDX_METADATA_COMP_TARGET_REF_LEVEL], 0, UINT8_MAX);
+    mMetaData.comp_TargetRefLevel = compTargetRefLevel;
+
+    INT isProgRefLevelPresent =
+        generateNumberInRangeFromData(data[IDX_METADATA_PROG_LEVEL_PRESENT], 0, 1);
+    mMetaData.prog_ref_level_present = isProgRefLevelPresent;
+
+    INT progRefLevel = generateNumberInRangeFromData(data[IDX_METADATA_PROG_LEVEL], 0, UINT8_MAX);
+    mMetaData.prog_ref_level = progRefLevel;
+
+    UCHAR isPCEMixdownIdxPresent =
+        generateNumberInRangeFromData(data[IDX_METADATA_PCE_MIXDOWN_IDX_PRESENT], 0, 1);
+    mMetaData.PCE_mixdown_idx_present = isPCEMixdownIdxPresent;
+
+    UCHAR isETSIDmxLvlPresent =
+        generateNumberInRangeFromData(data[IDX_METADATA_ETSI_DMXLVL_PRESENT], 0, 1);
+    mMetaData.ETSI_DmxLvl_present = isETSIDmxLvlPresent;
+
+    SCHAR centerMixLevel = generateNumberInRangeFromData(data[IDX_METADATA_CENTER_MIX_LEVEL], 0, 7);
+    mMetaData.centerMixLevel = centerMixLevel;
+
+    SCHAR surroundMixLevel =
+        generateNumberInRangeFromData(data[IDX_METADATA_SURROUND_MIX_LEVEL], 0, 7);
+    mMetaData.surroundMixLevel = surroundMixLevel;
+
+    UCHAR dolbySurroundMode =
+        generateNumberInRangeFromData(data[IDX_METADATA_DOLBY_SURROUND_MODE], 0, 2);
+    mMetaData.dolbySurroundMode = dolbySurroundMode;
+
+    UCHAR drcPresentationMode =
+        generateNumberInRangeFromData(data[IDX_METADATA_DRC_PRESENTATION_MODE], 0, 2);
+    mMetaData.drcPresentationMode = drcPresentationMode;
+
+    UCHAR extAncDataEnable =
+        generateNumberInRangeFromData(data[IDX_METADATA_EXT_ANC_DATA_ENABLE], 0, 1);
+    mMetaData.ExtMetaData.extAncDataEnable = extAncDataEnable;
+
+    UCHAR extDownmixLevelEnable =
+        generateNumberInRangeFromData(data[IDX_METADATA_EXT_DOWNMIX_LEVEL_ENABLE], 0, 1);
+    mMetaData.ExtMetaData.extDownmixLevelEnable = extDownmixLevelEnable;
+
+    UCHAR extDownmixLevel_A =
+        generateNumberInRangeFromData(data[IDX_METADATA_EXT_DOWNMIX_LEVEL_A], 0, 7);
+    mMetaData.ExtMetaData.extDownmixLevel_A = extDownmixLevel_A;
+
+    UCHAR extDownmixLevel_B =
+        generateNumberInRangeFromData(data[IDX_METADATA_EXT_DOWNMIX_LEVEL_B], 0, 7);
+    mMetaData.ExtMetaData.extDownmixLevel_B = extDownmixLevel_B;
+
+    UCHAR dmxGainEnable = generateNumberInRangeFromData(data[IDX_METADATA_DMX_GAIN_ENABLE], 0, 1);
+    mMetaData.ExtMetaData.dmxGainEnable = dmxGainEnable;
+
+    INT dmxGain5 = generateNumberInRangeFromData(data[IDX_METADATA_DMX_GAIN_5], 0, UINT8_MAX);
+    mMetaData.ExtMetaData.dmxGain5 = dmxGain5;
+
+    INT dmxGain2 = generateNumberInRangeFromData(data[IDX_METADATA_DMX_GAIN_2], 0, UINT8_MAX);
+    mMetaData.ExtMetaData.dmxGain2 = dmxGain2;
+
+    UCHAR lfeDmxEnable = generateNumberInRangeFromData(data[IDX_METADATA_LFE_DMX_ENABLE], 0, 1);
+    mMetaData.ExtMetaData.lfeDmxEnable = lfeDmxEnable;
+
+    UCHAR lfeDmxLevel = generateNumberInRangeFromData(data[IDX_METADATA_LFE_DMX_LEVEL], 0, 15);
+    mMetaData.ExtMetaData.lfeDmxLevel = lfeDmxLevel;
+}
+
+template <typename type1, typename type2, typename type3>
+void Codec::setAACParam(type1 data, const AACENC_PARAM aacParam, type2 min, type2 max,
+                        const type3 *array) {
+    auto value = 0;
+    if (array) {
+        uint32_t index = generateNumberInRangeFromData(data, min, max);
+        value = array[index];
+    } else {
+        value = generateNumberInRangeFromData(data, min, max);
+    }
+    aacEncoder_SetParam(mEncoder, aacParam, value);
+    (void)aacEncoder_GetParam(mEncoder, aacParam);
+}
+
+bool Codec::initEncoder(uint8_t **dataPtr, size_t *sizePtr) {
+    uint8_t *data = *dataPtr;
+
+    if (AACENC_OK != aacEncOpen(&mEncoder, 0, 0)) {
+        return false;
+    }
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_SBR_MODE], AACENC_SBR_MODE, 0, kSbrModesSize - 1,
+                                          kSbrModes);
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_SBR_RATIO], AACENC_SBR_RATIO, 0,
+                                          kSbrRatiosSize - 1, kSbrRatios);
+
+    setAACParam<uint8_t, size_t, AUDIO_OBJECT_TYPE>(data[IDX_AAC_AOT], AACENC_AOT, 0,
+                                                    kAudioObjectTypesSize - 1, kAudioObjectTypes);
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_SAMPLE_RATE], AACENC_SAMPLERATE, 0,
+                                          kSampleRatesSize - 1, kSampleRates);
+
+    uint32_t tempValue =
+        (data[IDX_BIT_RATE_1] << 16) | (data[IDX_BIT_RATE_2] << 8) | data[IDX_BIT_RATE_3];
+    setAACParam<uint8_t, uint32_t, uint32_t>(tempValue, AACENC_BITRATE, kMinBitRate, kMaxBitRate);
+
+    setAACParam<uint8_t, size_t, CHANNEL_MODE>(data[IDX_CHANNEL], AACENC_CHANNELMODE, 0,
+                                               kChannelModesSize - 1, kChannelModes);
+
+    setAACParam<uint8_t, size_t, TRANSPORT_TYPE>(data[IDX_IDENTIFIER], AACENC_TRANSMUX, 0,
+                                                 kIdentifiersSize - 1, kIdentifiers);
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_BIT_RATE_MODE], AACENC_BITRATEMODE, 0,
+                                          kBitRateModesSize - 1, kBitRateModes);
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_GRANULE_LENGTH], AACENC_GRANULE_LENGTH, 0,
+                                          kGranuleLengthsSize - 1, kGranuleLengths);
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_CHANNELORDER], AACENC_CHANNELORDER, 0,
+                                          kChannelOrderSize - 1, kChannelOrder);
+
+    setAACParam<uint8_t, int32_t, int32_t>(data[IDX_AFTERBURNER], AACENC_AFTERBURNER, 0, 1);
+
+    setAACParam<uint8_t, int32_t, int32_t>(data[IDX_BANDWIDTH], AACENC_BANDWIDTH, 0, 1);
+
+    setAACParam<uint8_t, uint32_t, uint32_t>(data[IDX_PEAK_BITRATE], AACENC_PEAK_BITRATE,
+                                             kMinBitRate, kMinBitRate);
+
+    setAACParam<uint8_t, uint32_t, uint32_t>(data[IDX_HEADER_PERIOD], AACENC_HEADER_PERIOD, 0,
+                                             UINT8_MAX);
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_SIGNALING_MODE], AACENC_SIGNALING_MODE, 0,
+                                          kSignalingModesSize - 1, kSignalingModes);
+
+    setAACParam<uint8_t, uint32_t, uint32_t>(data[IDX_TPSUBFRAMES], AACENC_TPSUBFRAMES, 0,
+                                             UINT8_MAX);
+
+    setAACParam<uint8_t, size_t, int32_t>(data[IDX_AUDIOMUXVER], AACENC_AUDIOMUXVER, 0,
+                                          kAudioMuxVerSize - 1, kAudioMuxVer);
+
+    setAACParam<uint8_t, uint32_t, uint32_t>(data[IDX_PROTECTION], AACENC_PROTECTION, 0, 1);
+
+    setAACParam<uint8_t, uint32_t, uint32_t>(data[IDX_ANCILLARY_BITRATE], AACENC_ANCILLARY_BITRATE,
+                                             0, kMaxBitRate);
+
+    setAACParam<uint8_t, uint32_t, uint32_t>(data[IDX_METADATA_MODE], AACENC_METADATA_MODE, 0, 3);
+
+    AACENC_InfoStruct encInfo;
+    aacEncInfo(mEncoder, &encInfo);
+
+    mInBufferIdx_1 = generateNumberInRangeFromData(data[IDX_IN_BUFFER_INDEX_1], 0, kMaxBuffers - 1);
+    mInBufferIdx_2 = generateNumberInRangeFromData(data[IDX_IN_BUFFER_INDEX_2], 0, kMaxBuffers - 1);
+    mInBufferIdx_3 = generateNumberInRangeFromData(data[IDX_IN_BUFFER_INDEX_3], 0, kMaxBuffers - 1);
+
+    setupMetaData(data);
+
+    // Not re-using the data which was used for configuration for encoding
+    *dataPtr += IDX_LAST;
+    *sizePtr -= IDX_LAST;
+
+    return true;
+}
+
+static void deleteBuffers(uint8_t **buffers, size_t size) {
+    for (size_t n = 0; n < size; ++n) {
+        delete[] buffers[n];
+    }
+    delete[] buffers;
+}
+
+void Codec::encodeFrames(const uint8_t *data, size_t size) {
+    uint8_t *audioData = (uint8_t *)data;
+    uint8_t *ancData = (uint8_t *)data;
+    size_t audioSize = size;
+    size_t ancSize = size;
+
+    while ((audioSize > 0) && (ancSize > 0)) {
+        AACENC_InArgs inargs;
+        memset(&inargs, 0, sizeof(inargs));
+        inargs.numInSamples = audioSize / sizeof(int16_t);
+        inargs.numAncBytes = ancSize;
+
+        void *buffers[] = {(void *)audioData, (void *)ancData, &mMetaData};
+        INT bufferIds[] = {IN_AUDIO_DATA, IN_ANCILLRY_DATA, IN_METADATA_SETUP};
+        INT bufferSizes[] = {static_cast<INT>(audioSize), static_cast<INT>(ancSize),
+                             static_cast<INT>(sizeof(mMetaData))};
+        INT bufferElSizes[] = {sizeof(int16_t), sizeof(UCHAR), sizeof(AACENC_MetaData)};
+
+        void *inBuffer[kMaxBuffers] = {};
+        INT inBufferIds[kMaxBuffers] = {};
+        INT inBufferSize[kMaxBuffers] = {};
+        INT inBufferElSize[kMaxBuffers] = {};
+        for (int32_t buffer = 0; buffer < kMaxBuffers; ++buffer) {
+            uint32_t Idxs[] = {mInBufferIdx_1, mInBufferIdx_2, mInBufferIdx_3};
+            inBuffer[buffer] = buffers[Idxs[buffer]];
+            inBufferIds[buffer] = bufferIds[Idxs[buffer]];
+            inBufferSize[buffer] = bufferSizes[Idxs[buffer]];
+            inBufferElSize[buffer] = bufferElSizes[Idxs[buffer]];
+        }
+
+        AACENC_BufDesc inBufDesc;
+        inBufDesc.numBufs = kMaxBuffers;
+        inBufDesc.bufs = (void **)&inBuffer;
+        inBufDesc.bufferIdentifiers = inBufferIds;
+        inBufDesc.bufSizes = inBufferSize;
+        inBufDesc.bufElSizes = inBufferElSize;
+
+        uint8_t **outPtrRef = new uint8_t *[kMaxBuffers];
+        for (int32_t buffer = 0; buffer < kMaxBuffers; ++buffer) {
+            outPtrRef[buffer] = new uint8_t[kMaxOutputBufferSize];
+        }
+
+        void *outBuffer[kMaxBuffers];
+        INT outBufferIds[kMaxBuffers];
+        INT outBufferSize[kMaxBuffers];
+        INT outBufferElSize[kMaxBuffers];
+
+        for (int32_t buffer = 0; buffer < kMaxBuffers; ++buffer) {
+            outBuffer[buffer] = outPtrRef[buffer];
+            outBufferIds[buffer] = OUT_BITSTREAM_DATA;
+            outBufferSize[buffer] = (INT)kMaxOutputBufferSize;
+            outBufferElSize[buffer] = sizeof(UCHAR);
+        }
+
+        AACENC_BufDesc outBufDesc;
+        outBufDesc.numBufs = kMaxBuffers;
+        outBufDesc.bufs = (void **)&outBuffer;
+        outBufDesc.bufferIdentifiers = outBufferIds;
+        outBufDesc.bufSizes = outBufferSize;
+        outBufDesc.bufElSizes = outBufferElSize;
+
+        AACENC_OutArgs outargs = {};
+        aacEncEncode(mEncoder, &inBufDesc, &outBufDesc, &inargs, &outargs);
+
+        if (outargs.numOutBytes == 0) {
+            if (audioSize > 0) {
+                ++audioData;
+                --audioSize;
+            }
+            if (ancSize > 0) {
+                ++ancData;
+                --ancSize;
+            }
+        } else {
+            size_t audioConsumed = outargs.numInSamples * sizeof(int16_t);
+            audioData += audioConsumed;
+            audioSize -= audioConsumed;
+
+            size_t ancConsumed = outargs.numAncBytes;
+            ancData += ancConsumed;
+            ancSize -= ancConsumed;
+        }
+        deleteBuffers(outPtrRef, kMaxBuffers);
+
+        // break out of loop if only metadata was sent in all the input buffers
+        // as sending it multiple times in a loop is redundant.
+        if ((mInBufferIdx_1 == kMaxBuffers - 1) && (mInBufferIdx_2 == kMaxBuffers - 1) &&
+            (mInBufferIdx_3 == kMaxBuffers - 1)) {
+            break;
+        }
+    }
+}
+
+void Codec::deInitEncoder() { aacEncClose(&mEncoder); }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    if (size < IDX_LAST) {
+        return 0;
+    }
+    Codec encoder;
+    if (encoder.initEncoder(const_cast<uint8_t **>(&data), &size)) {
+        encoder.encodeFrames(data, size);
+    }
+    return 0;
+}
diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp
index b6f733d..1af8a2e 100644
--- a/libAACenc/src/aacenc.cpp
+++ b/libAACenc/src/aacenc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -245,6 +245,46 @@
   return bitrate;
 }
 
+/*-----------------------------------------------------------------------------
+
+    functionname: FDKaacEnc_AdjustVBRBitrateMode
+    description:  Adjust bitrate mode to given bitrate parameter
+    input params: int vbrQuality (VBR0, VBR1, VBR2)
+                  bitrate
+                  channelMode
+    returns:      vbr bitrate mode
+
+ ------------------------------------------------------------------------------*/
+AACENC_BITRATE_MODE FDKaacEnc_AdjustVBRBitrateMode(
+    AACENC_BITRATE_MODE bitrateMode, INT bitrate, CHANNEL_MODE channelMode) {
+  AACENC_BITRATE_MODE newBitrateMode = bitrateMode;
+
+  if (bitrate != -1) {
+    const INT monoStereoMode =
+        (FDKaacEnc_GetMonoStereoMode(channelMode) == EL_MODE_STEREO) ? 1 : 0;
+    const INT nChannelsEff =
+        FDKaacEnc_GetChannelModeConfiguration(channelMode)->nChannelsEff;
+    newBitrateMode = AACENC_BR_MODE_INVALID;
+
+    for (int idx = (int)(sizeof(configTabVBR) / sizeof(*configTabVBR)) - 1;
+         idx >= 0; idx--) {
+      if (bitrate >=
+          configTabVBR[idx].chanBitrate[monoStereoMode] * nChannelsEff) {
+        if (configTabVBR[idx].chanBitrate[monoStereoMode] * nChannelsEff <
+            FDKaacEnc_GetVBRBitrate(bitrateMode, channelMode)) {
+          newBitrateMode = configTabVBR[idx].bitrateMode;
+        } else {
+          newBitrateMode = bitrateMode;
+        }
+        break;
+      }
+    }
+  }
+
+  return AACENC_BR_MODE_IS_VBR(newBitrateMode) ? newBitrateMode
+                                               : AACENC_BR_MODE_INVALID;
+}
+
 /**
  * \brief  Convert encoder bitreservoir value for transport library.
  *
@@ -397,7 +437,6 @@
   FIXP_DBL mbfac, bw_ratio;
   QC_INIT qcInit;
   INT averageBitsPerFrame = 0;
-  int bitresMin = 0; /* the bitreservoir is always big for AAC-LC */
   const CHANNEL_MODE prevChannelMode = hAacEnc->encoderMode;
 
   if (config == NULL) return AAC_ENC_INVALID_HANDLE;
@@ -553,7 +592,6 @@
     qcInit.minBits = fixMin(qcInit.minBits, averageBitsPerFrame & ~7);
   } else {
     INT bitreservoir = -1; /* default bitreservoir size*/
-    bitresMin = BITRES_MIN;
     if (isLowDelay(config->audioObjectType)) {
       INT brPerChannel = config->bitRate / config->nChannels;
       brPerChannel = fMin(BITRATE_MAX_LD, fMax(BITRATE_MIN_LD, brPerChannel));
@@ -567,7 +605,6 @@
       bitreservoir = fMultI(slope, (INT)(BITRES_MAX_LD - BITRES_MIN_LD)) +
                      BITRES_MIN_LD;     /* interpolate */
       bitreservoir = bitreservoir & ~7; /* align to bytes */
-      bitresMin = BITRES_MIN_LD;
     }
 
     int maxBitres;
@@ -604,7 +641,8 @@
   qcInit.nSubFrames = config->nSubFrames;
   qcInit.padding.paddingRest = config->sampleRate;
 
-  if (qcInit.maxBits - qcInit.averageBits >= bitresMin * config->nChannels) {
+  if (qcInit.maxBits - qcInit.averageBits >=
+      ((qcInit.isLowDelay) ? BITRES_MIN_LD : BITRES_MIN) * config->nChannels) {
     qcInit.bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */
   } else if (qcInit.maxBits > qcInit.averageBits) {
     qcInit.bitResMode = AACENC_BR_MODE_REDUCED; /* reduced bitreservoir */
diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h
index 0e0d8c1..b7e0ef2 100644
--- a/libAACenc/src/aacenc.h
+++ b/libAACenc/src/aacenc.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -335,6 +335,19 @@
 
 /*-----------------------------------------------------------------------------
 
+    functionname: FDKaacEnc_AdjustVBRBitrateMode
+    description:  Adjust bitrate mode to given bitrate parameter
+    input params: int vbrQuality (VBR0, VBR1, VBR2)
+                  bitrate
+                  channelMode
+    returns:      vbr bitrate mode
+
+ ------------------------------------------------------------------------------*/
+AACENC_BITRATE_MODE FDKaacEnc_AdjustVBRBitrateMode(
+    AACENC_BITRATE_MODE bitrateMode, INT bitrate, CHANNEL_MODE channelMode);
+
+/*-----------------------------------------------------------------------------
+
      functionname: FDKaacEnc_AacInitDefaultConfig
      description:  gives reasonable default configuration
      returns:      ---
diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp
index c3977f3..0ae329b 100644
--- a/libAACenc/src/aacenc_lib.cpp
+++ b/libAACenc/src/aacenc_lib.cpp
@@ -1028,6 +1028,13 @@
     case AACENC_BR_MODE_VBR_3:
     case AACENC_BR_MODE_VBR_4:
     case AACENC_BR_MODE_VBR_5:
+      /* Adjust bitrate mode in case given peak bitrate is lower than expected
+       * VBR bitrate. */
+      if ((INT)config->userPeakBitrate != -1) {
+        hAacConfig->bitrateMode = FDKaacEnc_AdjustVBRBitrateMode(
+            hAacConfig->bitrateMode, config->userPeakBitrate,
+            hAacConfig->channelMode);
+      }
       /* Get bitrate in VBR configuration */
       /* In VBR mode; SBR-modul depends on bitrate, core encoder on bitrateMode.
        */
diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp
index bcfaa23..9a42550 100644
--- a/libAACenc/src/qc_main.cpp
+++ b/libAACenc/src/qc_main.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -373,13 +373,8 @@
   hQC->invQuant = init->invQuant;
   hQC->maxIterations = init->maxIterations;
 
-  if (isConstantBitrateMode(hQC->bitrateMode)) {
-    /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir
-     */
-    hQC->bitResMode = init->bitResMode;
-  } else {
-    hQC->bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */
-  }
+  /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
+  hQC->bitResMode = init->bitResMode;
 
   hQC->padding.paddingRest = init->padding.paddingRest;
 
@@ -800,10 +795,15 @@
   INT avgTotalDynBits = 0; /* maximal allowed dynamic bits for all frames */
   INT totalAvailableBits = 0;
   INT nSubFrames = 1;
+  const INT isCBRAdjustment = (isConstantBitrateMode(hQC->bitrateMode) ||
+                               (hQC->bitResMode != AACENC_BR_MODE_FULL))
+                                  ? 1
+                                  : 0;
 
   /*-------------------------------------------- */
   /* redistribute total bitreservoir to elements */
-  ErrorStatus = FDKaacEnc_BitResRedistribution(hQC, cm, avgTotalBits);
+  ErrorStatus = FDKaacEnc_BitResRedistribution(
+      hQC, cm, (isCBRAdjustment == 0) ? hQC->maxBitsPerFrame : avgTotalBits);
   if (ErrorStatus != AAC_ENC_OK) {
     return ErrorStatus;
   }
@@ -831,33 +831,22 @@
 
   /*-------------------------------------------- */
   /*-------------------------------------------- */
-  if (isConstantBitrateMode(hQC->bitrateMode)) {
-    /* calc granted dynamic bits for sub frame and
-       distribute it to each element */
-    ErrorStatus = FDKaacEnc_prepareBitDistribution(
-        hQC, psyOut, qcOut, cm, qcElement, avgTotalBits, &totalAvailableBits,
-        &avgTotalDynBits);
+  /* calc granted dynamic bits for sub frame and
+     distribute it to each element */
+  ErrorStatus = FDKaacEnc_prepareBitDistribution(
+      hQC, psyOut, qcOut, cm, qcElement,
+      (isCBRAdjustment == 0) ? hQC->maxBitsPerFrame : avgTotalBits,
+      &totalAvailableBits, &avgTotalDynBits);
 
-    if (ErrorStatus != AAC_ENC_OK) {
-      return ErrorStatus;
-    }
-  } else {
-    qcOut[0]->grantedDynBits =
-        ((hQC->maxBitsPerFrame - (hQC->globHdrBits)) & ~7) -
-        (qcOut[0]->globalExtBits + qcOut[0]->staticBits +
-         qcOut[0]->elementExtBits);
-    qcOut[0]->maxDynBits = qcOut[0]->grantedDynBits;
-
-    totalAvailableBits = hQC->maxBitsPerFrame;
-    avgTotalDynBits = 0;
+  if (ErrorStatus != AAC_ENC_OK) {
+    return ErrorStatus;
   }
 
   /* for ( all sub frames ) ... */
   for (c = 0; c < nSubFrames; c++) {
     /* for CBR and VBR mode */
     FDKaacEnc_AdjustThresholds(hQC->hAdjThr, qcElement[c], qcOut[c],
-                               psyOut[c]->psyOutElement,
-                               isConstantBitrateMode(hQC->bitrateMode), cm);
+                               psyOut[c]->psyOutElement, isCBRAdjustment, cm);
 
   } /* -end- sub frame counter */