/****************************************************************************** * * 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 "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 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(&data), &size)) { encoder.encodeFrames(data, size); } return 0; }