aboutsummaryrefslogtreecommitdiff
path: root/fuzzer/opus_enc_fuzzer.cpp
diff options
context:
space:
mode:
authorAnuj Joshi <anuj.joshi@ittiam.com>2020-09-23 20:21:53 +0530
committerAnuj Joshi <anuj.joshi@ittiam.com>2020-12-07 11:40:46 +0530
commitd56e7d51afe43dc86cf85842c5ce5db36387cbd8 (patch)
treeee75d35a8254b14ba056aa31817a7bdc75318883 /fuzzer/opus_enc_fuzzer.cpp
parent3281c0eb15bd1bbfb05938469a2f61a21d8d333a (diff)
downloadlibopus-d56e7d51afe43dc86cf85842c5ce5db36387cbd8.tar.gz
Added opus_enc_fuzzer and opus_multistream_enc_fuzzer
Test: ./opus_enc_fuzzer Test: ./opus_multistream_enc_fuzzer Bug: 171467315 Change-Id: I8be269ab8595eb5e9fab43bb52bee16123d6c9b1
Diffstat (limited to 'fuzzer/opus_enc_fuzzer.cpp')
-rw-r--r--fuzzer/opus_enc_fuzzer.cpp314
1 files changed, 314 insertions, 0 deletions
diff --git a/fuzzer/opus_enc_fuzzer.cpp b/fuzzer/opus_enc_fuzzer.cpp
new file mode 100644
index 00000000..c2258fde
--- /dev/null
+++ b/fuzzer/opus_enc_fuzzer.cpp
@@ -0,0 +1,314 @@
+/******************************************************************************
+ *
+ * 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 <algorithm>
+
+#include "opus.h"
+
+using namespace std;
+
+constexpr int kFrameDuration = 50;
+constexpr int kMaxPacket = 1500;
+constexpr int kMinBitRate = 500;
+constexpr int kMaxBitRate = 512000;
+
+constexpr opus_int32 kSampleRates[] = {8000, 12000, 16000, 24000, 48000};
+constexpr size_t kSampleRatesSize = size(kSampleRates);
+
+#ifndef MULTISTREAM
+constexpr int kChannels[] = {1, 2};
+constexpr size_t kChannelsSize = size(kChannels);
+#endif
+
+constexpr int kApplications[] = {OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO,
+ OPUS_APPLICATION_RESTRICTED_LOWDELAY};
+constexpr size_t kApplicationsSize = size(kApplications);
+
+constexpr int kSignals[] = {OPUS_AUTO, OPUS_SIGNAL_VOICE, OPUS_SIGNAL_MUSIC};
+constexpr size_t kSignalsSize = size(kSignals);
+
+constexpr int kSetDTX[] = {0, 1};
+constexpr size_t kSetDTXSize = size(kSetDTX);
+
+constexpr int kSetVBR[] = {0, 1};
+constexpr size_t kSetVBRSize = size(kSetVBR);
+
+constexpr int kSetInbandFec[] = {0, 1};
+constexpr size_t kSetInbandFecSize = size(kSetInbandFec);
+
+constexpr int kSetVBRConstraint[] = {0, 1};
+constexpr size_t kSetVBRConstraintSize = size(kSetVBRConstraint);
+
+constexpr int kSetPredDisable[] = {0, 1};
+constexpr size_t kSetPredDisableSize = size(kSetPredDisable);
+
+constexpr int kComplexities[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+constexpr size_t kComplexitiesSize = size(kComplexities);
+
+constexpr int kForceChannels[] = {OPUS_AUTO, 1, 2};
+constexpr size_t kForceChannelsSize = size(kForceChannels);
+
+constexpr int kMaxBandwidths[] = {OPUS_BANDWIDTH_NARROWBAND, OPUS_BANDWIDTH_MEDIUMBAND,
+ OPUS_BANDWIDTH_WIDEBAND, OPUS_BANDWIDTH_SUPERWIDEBAND,
+ OPUS_BANDWIDTH_FULLBAND};
+constexpr size_t kMaxBandwidthsSize = size(kMaxBandwidths);
+
+constexpr int kPacketLossPerc[] = {0, 1, 2, 5};
+constexpr size_t kPacketLossPercSize = size(kPacketLossPerc);
+
+constexpr int kLsbDepths[] = {8, 24};
+constexpr size_t kLsbDepthsSize = size(kLsbDepths);
+
+constexpr int kFrameDurations[] = {
+ OPUS_FRAMESIZE_2_5_MS, OPUS_FRAMESIZE_5_MS, OPUS_FRAMESIZE_10_MS,
+ OPUS_FRAMESIZE_20_MS, OPUS_FRAMESIZE_40_MS, OPUS_FRAMESIZE_60_MS,
+ OPUS_FRAMESIZE_80_MS, OPUS_FRAMESIZE_100_MS, OPUS_FRAMESIZE_120_MS};
+constexpr size_t kFrameDurationsSize = size(kFrameDurations);
+
+#ifdef MULTISTREAM
+#include "opus_multistream.h"
+#define OPUS_ENC_DATA_TYPE OpusMSEncoder
+#define OPUS_ENC_ENCODE_API opus_multistream_encode
+#define OPUS_ENC_CTL_API opus_multistream_encoder_ctl
+#define OPUS_ENC_CREATE_API ms_opus_encoder_create
+#define OPUS_ENC_DESTROY_API opus_multistream_encoder_destroy
+static OpusMSEncoder* ms_opus_encoder_create(opus_int32 sampleRate, int channels, int application,
+ int* error) {
+ unsigned char* mapping = (unsigned char*)malloc(sizeof(unsigned char) * channels);
+ if (!mapping) {
+ *error = 1;
+ return nullptr;
+ }
+ for (unsigned char x = 0; x < channels; ++x) {
+ mapping[x] = x;
+ }
+ OpusMSEncoder* enc = opus_multistream_encoder_create(sampleRate, channels, 1, channels - 1,
+ mapping, application, error);
+ free(mapping);
+ return enc;
+}
+#else
+#define OPUS_ENC_DATA_TYPE OpusEncoder
+#define OPUS_ENC_ENCODE_API opus_encode
+#define OPUS_ENC_CTL_API opus_encoder_ctl
+#define OPUS_ENC_CREATE_API opus_encoder_create
+#define OPUS_ENC_DESTROY_API opus_encoder_destroy
+#endif
+
+enum {
+ IDX_SAMPLE_RATE_INDEX = 0,
+ IDX_CHANNEL,
+ IDX_BIT_RATE_1,
+ IDX_BIT_RATE_2,
+ IDX_BIT_RATE_3,
+ IDX_COMPLEXITY,
+ IDX_APPLICATION,
+ IDX_SET_DTX,
+ IDX_SET_SIGNAL,
+ IDX_SET_VBR,
+ IDX_SET_VBR_CONSTRAINT,
+ IDX_FORCE_CHANNEL_INDEX,
+ IDX_SET_MAX_BANDWIDTH,
+ IDX_SET_INBAND_FEC,
+ IDX_SET_PACKET_LOSS_PERC,
+ IDX_SET_LSB_DEPTH,
+ IDX_SET_PREDICTION_DISABLED,
+ IDX_FRAME_ENUM,
+ 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:
+ OPUS_ENC_DATA_TYPE* mEncoder = nullptr;
+ int mChannels = 0;
+ int mNumSamplesPerFrame = 0;
+ size_t mFrameSize = 0;
+ size_t mNumPcmBytesPerInputFrame = 0;
+};
+
+int get_frame_size(int frameSizeEnum, int samplingRate) {
+ int frameSize = 0;
+ switch (frameSizeEnum) {
+ case OPUS_FRAMESIZE_2_5_MS:
+ frameSize = samplingRate / 400;
+ break;
+ case OPUS_FRAMESIZE_5_MS:
+ frameSize = samplingRate / 200;
+ break;
+ case OPUS_FRAMESIZE_10_MS:
+ frameSize = samplingRate / 100;
+ break;
+ case OPUS_FRAMESIZE_20_MS:
+ frameSize = samplingRate / 50;
+ break;
+ case OPUS_FRAMESIZE_40_MS:
+ frameSize = samplingRate / 25;
+ break;
+ case OPUS_FRAMESIZE_60_MS:
+ frameSize = 3 * samplingRate / 50;
+ break;
+ case OPUS_FRAMESIZE_80_MS:
+ frameSize = 4 * samplingRate / 50;
+ break;
+ case OPUS_FRAMESIZE_100_MS:
+ frameSize = 5 * samplingRate / 50;
+ break;
+ case OPUS_FRAMESIZE_120_MS:
+ frameSize = 6 * samplingRate / 50;
+ break;
+ default:
+ break;
+ }
+ return frameSize;
+}
+
+bool Codec::initEncoder(uint8_t** dataPtr, size_t* sizePtr) {
+ uint8_t* data = *dataPtr;
+
+ int sampleRateIndex = data[IDX_SAMPLE_RATE_INDEX] % kSampleRatesSize;
+ opus_int32 sampleRate = kSampleRates[sampleRateIndex];
+
+#ifdef MULTISTREAM
+ mChannels = generateNumberInRangeFromData(data[IDX_CHANNEL], 1, 255);
+#else
+ int channelIndex = data[IDX_CHANNEL] % kChannelsSize;
+ mChannels = kChannels[channelIndex];
+#endif
+
+ mNumSamplesPerFrame = sampleRate / kFrameDuration;
+ mNumPcmBytesPerInputFrame = mChannels * mNumSamplesPerFrame * sizeof(int16_t);
+
+ int application = kApplications[data[IDX_APPLICATION] % kApplicationsSize];
+ int err = 0;
+ mEncoder = OPUS_ENC_CREATE_API(sampleRate, mChannels, application, &err);
+ if (err) {
+ return false;
+ }
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_APPLICATION(application));
+
+ int complexityIndex = data[IDX_COMPLEXITY] % kComplexitiesSize;
+ int complexity = kComplexities[complexityIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_COMPLEXITY(complexity));
+
+ int setDTXIndex = data[IDX_SET_DTX] % kSetDTXSize;
+ int setDTX = kSetDTX[setDTXIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_DTX(setDTX));
+
+ int signalIndex = data[IDX_SET_SIGNAL] % kSignalsSize;
+ int signal = kSignals[signalIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_SIGNAL(signal));
+
+ int setVBRIndex = data[IDX_SET_VBR] % kSetVBRSize;
+ int setVBR = kSetVBR[setVBRIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_VBR(setVBR));
+
+ int setVBRConstraintIndex = data[IDX_SET_VBR_CONSTRAINT] % kSetVBRConstraintSize;
+ int setVBRConstraint = kSetVBRConstraint[setVBRConstraintIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_VBR_CONSTRAINT(setVBRConstraint));
+
+ // Clubbing 3 bytes of data to ensure bit rate in the range [kMinBitRate, kMaxBitRate]
+ 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);
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_BITRATE(bitRate));
+
+ int forceChanneIndex = data[IDX_FORCE_CHANNEL_INDEX] % kForceChannelsSize;
+ int forceChannel = kForceChannels[forceChanneIndex];
+ forceChannel = min(forceChannel, mChannels);
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_FORCE_CHANNELS(forceChannel));
+
+ int maxBandwidthIndex = data[IDX_SET_MAX_BANDWIDTH] % kMaxBandwidthsSize;
+ opus_int32 maxBandwidth = kMaxBandwidths[maxBandwidthIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_MAX_BANDWIDTH(maxBandwidth));
+
+ int setInbandFecIndex = data[IDX_SET_INBAND_FEC] % kSetInbandFecSize;
+ int setInbandFec = kSetInbandFec[setInbandFecIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_INBAND_FEC(setInbandFec));
+
+ int pktLossIndex = data[IDX_SET_PACKET_LOSS_PERC] % kPacketLossPercSize;
+ int pktLoss = kPacketLossPerc[pktLossIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_PACKET_LOSS_PERC(pktLoss));
+
+ int lsbDepthIndex = data[IDX_SET_LSB_DEPTH] % kLsbDepthsSize;
+ int lsbDepth = kLsbDepths[lsbDepthIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_LSB_DEPTH(lsbDepth));
+
+ int setPredDisableIndex = data[IDX_SET_PREDICTION_DISABLED] % kSetPredDisableSize;
+ int setPredDisable = kSetPredDisable[setPredDisableIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_PREDICTION_DISABLED(setPredDisable));
+
+ int frameSizesEnumIndex = data[IDX_FRAME_ENUM] % kFrameDurationsSize;
+ int frameSizeEnum = kFrameDurations[frameSizesEnumIndex];
+ OPUS_ENC_CTL_API(mEncoder, OPUS_SET_EXPERT_FRAME_DURATION(frameSizeEnum));
+
+ mFrameSize = get_frame_size(frameSizeEnum, sampleRate);
+ if (mFrameSize == 0) {
+ return false;
+ }
+
+ // Not re-using the data which was used for configuration for encoding
+ *dataPtr += IDX_LAST;
+ *sizePtr -= IDX_LAST;
+ return true;
+}
+
+void Codec::encodeFrames(const uint8_t* data, size_t size) {
+ opus_int16* inputBuffer = (opus_int16*)data;
+ size = size / sizeof(opus_int16);
+ size_t offset = 0;
+ do {
+ size_t frameSize = mFrameSize / mChannels;
+ if (frameSize > (size - offset)) {
+ frameSize = size - offset;
+ }
+ unsigned char packet[kMaxPacket];
+ (void)OPUS_ENC_ENCODE_API(mEncoder, &inputBuffer[offset], frameSize, packet, kMaxPacket);
+ offset += mFrameSize * mChannels;
+ } while (offset < size);
+}
+
+void Codec::deInitEncoder() {
+ if (mEncoder) {
+ OPUS_ENC_DESTROY_API(mEncoder);
+ mEncoder = nullptr;
+ }
+}
+
+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;
+}