blob: 3cbc64d50bfdb54b8f96b47ec67d88d2189edbca [file] [log] [blame]
Anuj Joshi3ff86be2020-11-11 10:46:00 +05301/******************************************************************************
2 *
3 * Copyright (C) 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20
21#include <math.h>
22#include <stdlib.h>
23#include <algorithm>
24
25#include "FLAC/stream_encoder.h"
26#include "audio_utils/primitives.h"
27#include "share/compat.h"
28
29constexpr int kMinSampleRate = 1;
30constexpr int kFramesPerBlock = 1152;
31constexpr int kMaxSampleRate = 655350;
32constexpr uint8_t kMinNumChannels = 1;
33constexpr uint8_t kMaxNumChannels = 2;
34constexpr uint8_t kMinCompressionLevel = 0;
35constexpr uint8_t kMaxCompressionLevel = 8;
36
37enum Encoding { PCM_16, PCM_FLOAT };
38
39enum {
40 IDX_SAMPLE_RATE_INDEX_1 = 0,
41 IDX_SAMPLE_RATE_INDEX_2,
42 IDX_SAMPLE_RATE_INDEX_3,
43 IDX_CHANNEL,
44 IDX_COMPRESSION_LEVEL,
45 IDX_PCM,
46 IDX_SET_VERIFY,
47 IDX_SET_STREAMABLE_SUBSET,
48 IDX_SET_DO_MID_SIDE_STEREO,
49 IDX_SET_LOOSE_MID_SIDE_STEREO,
50 IDX_SET_MAX_LPC_ORDER,
51 IDX_SET_COEFF_PRECISION,
52 IDX_SET_COEFF_PREC_SEARCH,
53 IDX_SET_DO_ESCAPE_CODING,
54 IDX_SET_DO_EXHAUSTIVE_MODEL_SEARCH,
55 IDX_SET_MIN_RESIDUAL_PARTITION_ORDER,
56 IDX_SET_MAX_RESIDUAL_PARTITION_ORDER,
57 IDX_SET_RICE_PARAMETER_SEARCH_DIST,
58 IDX_SET_TOTAL_SAMPLES_ESTIMATE,
59 IDX_LAST
60};
61
62class Codec {
63 public:
64 ~Codec() { deInitEncoder(); }
65 bool initEncoder(uint8_t **dataPtr, size_t *sizePtr);
66 void encodeFrames(const uint8_t *data, size_t size);
67 void deInitEncoder();
68 static FLAC__StreamEncoderWriteStatus flacEncoderWriteCallback(
69 const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes,
70 unsigned samples, unsigned current_frame, void *client_data);
71
72 private:
73 bool verifyStateAndReturn();
74 FLAC__StreamEncoder *mFlacStreamEncoder = nullptr;
75 uint32_t mChannels = 0;
76 uint32_t mPcmEncodingInfo = 0;
77 FLAC__int32 mInputBufferPcm32[kFramesPerBlock * kMaxNumChannels] = {};
78};
79
80FLAC__StreamEncoderWriteStatus Codec::flacEncoderWriteCallback(const FLAC__StreamEncoder *encoder,
81 const FLAC__byte buffer[],
82 size_t bytes, unsigned samples,
83 unsigned current_frame,
84 void *client_data) {
85 (void)encoder;
86 (void)buffer;
87 (void)bytes;
88 (void)samples;
89 (void)current_frame;
90 (void)client_data;
91 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
92}
93
94bool Codec::verifyStateAndReturn() {
95 FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(mFlacStreamEncoder);
96 if (state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
97 FLAC__stream_encoder_get_verify_decoder_state(mFlacStreamEncoder);
98 }
99 return false;
100}
101
102template <typename type1, typename type2, typename type3>
103auto generateNumberInRangeFromData(type1 data, type2 min, type3 max) -> decltype(max) {
104 return (data % (1 + max - min)) + min;
105}
106
107bool Codec::initEncoder(uint8_t **dataPtr, size_t *sizePtr) {
108 uint8_t *data = *dataPtr;
109 mFlacStreamEncoder = FLAC__stream_encoder_new();
110 if (!mFlacStreamEncoder) {
111 return false;
112 }
113
114 // Clubbing 3 bytes of data to ensure sample rate in the range [1, 655350]
115 uint32_t tempValue = (data[IDX_SAMPLE_RATE_INDEX_1] << 16) |
116 (data[IDX_SAMPLE_RATE_INDEX_2] << 8) | data[IDX_SAMPLE_RATE_INDEX_3];
117 uint32_t sampleRate = generateNumberInRangeFromData(tempValue, kMinSampleRate, kMaxSampleRate);
118 FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, sampleRate);
119
120 mChannels = generateNumberInRangeFromData(data[IDX_CHANNEL], kMinNumChannels, kMaxNumChannels);
121 FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mChannels);
122
123 int compression = generateNumberInRangeFromData(data[IDX_COMPRESSION_LEVEL],
124 kMinCompressionLevel, kMaxCompressionLevel);
125 FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, compression);
126
127 uint32_t pcmEncodingInfo =
128 generateNumberInRangeFromData(data[IDX_PCM], (int)PCM_16, (int)PCM_FLOAT);
129 mPcmEncodingInfo = pcmEncodingInfo;
130 uint32_t bitsPerSample = (mPcmEncodingInfo == PCM_FLOAT) ? 24 : 16;
131 FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, bitsPerSample);
132
133 int ver = data[IDX_SET_VERIFY] % 2;
134 FLAC__stream_encoder_set_verify(mFlacStreamEncoder, ver);
135
136 int streamableSubset = data[IDX_SET_STREAMABLE_SUBSET] % 2;
137 FLAC__stream_encoder_set_streamable_subset(mFlacStreamEncoder, streamableSubset);
138
139 int doMidSideStereo = data[IDX_SET_DO_MID_SIDE_STEREO] % 2;
140 FLAC__stream_encoder_set_do_mid_side_stereo(mFlacStreamEncoder, doMidSideStereo);
141
142 int looseMidSideStereo = data[IDX_SET_LOOSE_MID_SIDE_STEREO] % 2;
143 FLAC__stream_encoder_set_loose_mid_side_stereo(mFlacStreamEncoder, looseMidSideStereo);
144
145 int maxLpcOrder = data[IDX_SET_MAX_LPC_ORDER] % 2;
146 FLAC__stream_encoder_set_max_lpc_order(mFlacStreamEncoder, maxLpcOrder);
147
148 int coeffPrec = data[IDX_SET_COEFF_PRECISION] % 2;
149 FLAC__stream_encoder_set_qlp_coeff_precision(mFlacStreamEncoder, coeffPrec);
150
151 int coeffPrecSearch = data[IDX_SET_COEFF_PREC_SEARCH] % 2;
152 FLAC__stream_encoder_set_do_qlp_coeff_prec_search(mFlacStreamEncoder, coeffPrecSearch);
153
154 int escCoding = data[IDX_SET_DO_ESCAPE_CODING] % 2;
155 FLAC__stream_encoder_set_do_escape_coding(mFlacStreamEncoder, escCoding);
156
157 int exhaustiveModelSearch = data[IDX_SET_DO_EXHAUSTIVE_MODEL_SEARCH] % 2;
158 FLAC__stream_encoder_set_do_exhaustive_model_search(mFlacStreamEncoder, exhaustiveModelSearch);
159
160 int minResidualPartitionOrder = data[IDX_SET_MIN_RESIDUAL_PARTITION_ORDER] % 2;
161 FLAC__stream_encoder_set_min_residual_partition_order(mFlacStreamEncoder,
162 minResidualPartitionOrder);
163
164 int maxResidualPartitionOrder = data[IDX_SET_MAX_RESIDUAL_PARTITION_ORDER] % 2;
165 FLAC__stream_encoder_set_max_residual_partition_order(mFlacStreamEncoder,
166 maxResidualPartitionOrder);
167
168 int riceParam = data[IDX_SET_RICE_PARAMETER_SEARCH_DIST] % 2;
169 FLAC__stream_encoder_set_rice_parameter_search_dist(mFlacStreamEncoder, riceParam);
170
171 int totalSamplesEstimate = data[IDX_SET_TOTAL_SAMPLES_ESTIMATE] % 2;
172 FLAC__stream_encoder_set_total_samples_estimate(mFlacStreamEncoder, totalSamplesEstimate);
173
174 FLAC__StreamEncoderInitStatus status = FLAC__stream_encoder_init_stream(
175 mFlacStreamEncoder, flacEncoderWriteCallback /*write_callback*/, nullptr /*seek_callback*/,
176 nullptr /*tell_callback*/, nullptr /*metadata_callback*/, (void *)this /*client_data*/);
177
178 if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
179 return verifyStateAndReturn();
180 }
181
182 // Not re-using the data which was used for configuration for encoding
183 *dataPtr += IDX_LAST;
184 *sizePtr -= IDX_LAST;
185 return true;
186}
187
188void Codec::encodeFrames(const uint8_t *data, size_t size) {
189 size_t sampleSize = (mPcmEncodingInfo == PCM_FLOAT) ? sizeof(float) : sizeof(int16_t);
190 size_t frameSize = mChannels * sampleSize;
191 do {
192 const size_t bytesConsumed = std::min(kFramesPerBlock * frameSize, size);
193 const unsigned inputFrames = bytesConsumed / frameSize;
194 const unsigned inputSamples = inputFrames * mChannels;
195 if (mPcmEncodingInfo == PCM_FLOAT) {
196 const float *const pcmFloat = reinterpret_cast<const float *>(data);
197 memcpy_to_q8_23_from_float_with_clamp(mInputBufferPcm32, pcmFloat, inputSamples);
198 } else {
199 const int16_t *const pcm16 = reinterpret_cast<const int16_t *>(data);
200 for (unsigned i = 0; i < inputSamples; ++i) {
201 mInputBufferPcm32[i] = (FLAC__int32)pcm16[i];
202 }
203 }
204 FLAC__stream_encoder_process_interleaved(mFlacStreamEncoder, mInputBufferPcm32,
205 inputFrames);
206 data += bytesConsumed;
207 size -= bytesConsumed;
208 } while (size > 0);
209}
210
211void Codec::deInitEncoder() {
212 if (mFlacStreamEncoder) {
213 FLAC__stream_encoder_finish(mFlacStreamEncoder);
214 FLAC__stream_encoder_delete(mFlacStreamEncoder);
215 mFlacStreamEncoder = nullptr;
216 }
217}
218
219extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
220 if (size < IDX_LAST) {
221 return 0;
222 }
223 Codec encoder;
224 if (encoder.initEncoder(const_cast<uint8_t **>(&data), &size)) {
225 encoder.encodeFrames(data, size);
226 }
227 return 0;
228}