xref: /aosp_15_r20/external/flac/fuzzer/flac_enc_fuzzer.cpp (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1 /******************************************************************************
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 
29 constexpr int kMinSampleRate = 1;
30 constexpr int kFramesPerBlock = 1152;
31 constexpr int kMaxSampleRate = 655350;
32 constexpr uint8_t kMinNumChannels = 1;
33 constexpr uint8_t kMaxNumChannels = 2;
34 constexpr uint8_t kMinCompressionLevel = 0;
35 constexpr uint8_t kMaxCompressionLevel = 8;
36 
37 enum Encoding { PCM_16, PCM_FLOAT };
38 
39 enum {
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 
62 class Codec {
63    public:
~Codec()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 
flacEncoderWriteCallback(const FLAC__StreamEncoder * encoder,const FLAC__byte buffer[],size_t bytes,unsigned samples,unsigned current_frame,void * client_data)80 FLAC__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 
verifyStateAndReturn()94 bool 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 
102 template <typename type1, typename type2, typename type3>
generateNumberInRangeFromData(type1 data,type2 min,type3 max)103 auto generateNumberInRangeFromData(type1 data, type2 min, type3 max) -> decltype(max) {
104     return (data % (1 + max - min)) + min;
105 }
106 
initEncoder(uint8_t ** dataPtr,size_t * sizePtr)107 bool 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 
encodeFrames(const uint8_t * data,size_t size)188 void 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 
deInitEncoder()211 void Codec::deInitEncoder() {
212     if (mFlacStreamEncoder) {
213         FLAC__stream_encoder_finish(mFlacStreamEncoder);
214         FLAC__stream_encoder_delete(mFlacStreamEncoder);
215         mFlacStreamEncoder = nullptr;
216     }
217 }
218 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)219 extern "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 }
229