diff --git a/Android.bp b/Android.bp index 555223b..f40e05e 100644 --- a/Android.bp +++ b/Android.bp @@ -32,8 +32,7 @@ cc_library_static { "signed-integer-overflow", "bounds", ], - // Enable CFI if this becomes a shared library. - // cfi: true, + cfi: true, }, shared_libs: [ "liblog", @@ -58,6 +57,13 @@ cc_library_static { darwin: { enabled: false, }, + android: { + sanitize: { + diag: { + cfi: true, + }, + }, + }, }, apex_available: [ diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp index 28a21b9..470eb9a 100644 --- a/fuzzer/Android.bp +++ b/fuzzer/Android.bp @@ -18,17 +18,12 @@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ -cc_fuzz { - name: "aac_dec_fuzzer", - host_supported:true, +cc_defaults { + name: "aac_fuzz_defaults", + host_supported: true, static_libs: [ "libFraunhoferAAC", - "liblog", - ], - - srcs: [ - "aac_dec_fuzzer.cpp", ], target: { @@ -44,3 +39,31 @@ cc_fuzz { 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" + ], +} diff --git a/fuzzer/README.md b/fuzzer/README.md index d99bc75..43a7ff4 100644 --- a/fuzzer/README.md +++ b/fuzzer/README.md @@ -53,7 +53,85 @@ To run on host $ $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: + +| Variable name| AACENC_PARAM param| Valid Values| Configured Value| +|------------- |-------------| ----- |----- | +| `sbrMode` |`AACENC_SBR_MODE` | `AAC_SBR_OFF ` `AAC_SBR_SINGLE_RATE ` `AAC_SBR_DUAL_RATE ` `AAC_SBR_AUTO ` | Calculated using first byte of data | +| `aacAOT` | `AACENC_AOT` |`AOT_AAC_LC ` `AOT_ER_AAC_ELD ` `AOT_SBR ` `AOT_PS ` `AOT_ER_AAC_LD ` | Calculated using second byte of data | +| `sampleRate` |`AACENC_SAMPLERATE` | `8000 ` `11025 ` `12000 ` `16000 ` `22050 ` `24000 ` `32000 ` `44100 ` `48000 `| Calculated using third byte of data | +| `bitRate` |`AACENC_BITRATE` | In range `8000 ` to `960000 ` | Calculated using fourth, fifth and sixth byte of data | +| `channelMode` |`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_7_1_BACK ` | Calculated using seventh byte of data | +| `identifier` |`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 | +| `sbrRatio` | `AACENC_SBR_RATIO` |`0 ` `1 ` `2 ` | Calculated using ninth 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..4908922 --- /dev/null +++ b/fuzzer/aac_enc_fuzzer.cpp @@ -0,0 +1,374 @@ +/****************************************************************************** + * + * 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 +#include "aacenc_lib.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 uint32_t kSampleRates[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}; +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_7_1_BACK}; +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_AAC_LC, AOT_ER_AAC_ELD, AOT_SBR, AOT_PS, + AOT_ER_AAC_LD}; +constexpr size_t kAudioObjectTypesSize = size(kAudioObjectTypes); + +constexpr int32_t kSbrRatios[] = {0, 1, 2}; +constexpr size_t kSbrRatiosSize = size(kSbrRatios); + +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_LAST +}; + +enum aac_sbr_mode_t : uint32_t { + AAC_SBR_OFF, + AAC_SBR_SINGLE_RATE, + AAC_SBR_DUAL_RATE, + AAC_SBR_AUTO +}; + +template +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: + 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; +} + +bool Codec::initEncoder(uint8_t **dataPtr, size_t *sizePtr) { + uint8_t *data = *dataPtr; + + if (AACENC_OK != aacEncOpen(&mEncoder, 0, 0)) { + return false; + } + + uint32_t sbrMode = generateNumberInRangeFromData(data[IDX_SBR_MODE], (uint32_t)AAC_SBR_OFF, + (uint32_t)AAC_SBR_AUTO); + aacEncoder_SetParam(mEncoder, AACENC_SBR_MODE, sbrMode); + + uint32_t sbrRatioIndex = + generateNumberInRangeFromData(data[IDX_SBR_RATIO], 0, kSbrRatiosSize - 1); + int32_t sbrRatio = kSbrRatios[sbrRatioIndex]; + aacEncoder_SetParam(mEncoder, AACENC_SBR_RATIO, sbrRatio); + + uint32_t aacAOTIndex = + generateNumberInRangeFromData(data[IDX_AAC_AOT], 0, kAudioObjectTypesSize - 1); + uint32_t aacAOT = kAudioObjectTypes[aacAOTIndex]; + aacEncoder_SetParam(mEncoder, AACENC_AOT, aacAOT); + + uint32_t sampleRateIndex = + generateNumberInRangeFromData(data[IDX_SAMPLE_RATE], 0, kSampleRatesSize - 1); + uint32_t sampleRate = kSampleRates[sampleRateIndex]; + aacEncoder_SetParam(mEncoder, AACENC_SAMPLERATE, sampleRate); + + uint32_t tempValue = + (data[IDX_BIT_RATE_1] << 16) | (data[IDX_BIT_RATE_2] << 8) | data[IDX_BIT_RATE_3]; + uint32_t bitRate = generateNumberInRangeFromData(tempValue, kMinBitRate, kMaxBitRate); + aacEncoder_SetParam(mEncoder, AACENC_BITRATE, bitRate); + + uint32_t channelModeIndex = + generateNumberInRangeFromData(data[IDX_CHANNEL], 0, kChannelModesSize - 1); + CHANNEL_MODE channelMode = kChannelModes[channelModeIndex]; + aacEncoder_SetParam(mEncoder, AACENC_CHANNELMODE, channelMode); + + uint32_t identifierIndex = + generateNumberInRangeFromData(data[IDX_IDENTIFIER], 0, kIdentifiersSize - 1); + uint32_t identifier = kIdentifiers[identifierIndex]; + aacEncoder_SetParam(mEncoder, AACENC_TRANSMUX, identifier); + + 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(audioSize), static_cast(ancSize), + static_cast(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(&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 @@ INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode, 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 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( 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 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( 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 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( 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 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( 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 291ea54..2d95abb 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 @@ -334,6 +334,19 @@ INT FDKaacEnc_GetBitReservoirState(const HANDLE_AAC_ENC hAacEncoder); INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode, CHANNEL_MODE channelMode); +/*----------------------------------------------------------------------------- + + 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 diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index d2cb801..0df12f2 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1028,6 +1028,13 @@ static AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder, 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 @@ AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE* hQC, struct QC_INIT* init, 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 @@ AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, PSY_OUT** psyOut, 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 @@ AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, PSY_OUT** psyOut, /*-------------------------------------------- */ /*-------------------------------------------- */ - 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 */