Skip to content

Commit bf52823

Browse files
Googlerjwcullen
authored andcommitted
Add fuzz test for arbitrary sequences of IAMF decoder operations.
The test uses existing IAMF test files as seed data for the `Decode` calls and explores different combinations of API calls to uncover potential issues. PiperOrigin-RevId: 905064810
1 parent 0d531c9 commit bf52823

2 files changed

Lines changed: 149 additions & 1 deletion

File tree

iamf/api/decoder/tests/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ cc_test(
1010
data = [
1111
"//iamf/cli/testdata:fuzz_test_iamf",
1212
],
13-
shard_count = 2,
13+
shard_count = 5,
1414
target_compatible_with = [
1515
"@platforms//os:linux",
1616
],

iamf/api/decoder/tests/iamf_decoder_fuzz_test.cc

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* www.aomedia.org/license/patent.
1111
*/
1212

13+
#include <algorithm>
1314
#include <cstddef>
1415
#include <cstdint>
1516
#include <optional>
@@ -200,6 +201,153 @@ auto AnyChannelOrdering() {
200201
});
201202
}
202203

204+
enum class OperationType {
205+
kDecode,
206+
kGetOutputTemporalUnit,
207+
kIsTemporalUnitAvailable,
208+
kIsDescriptorProcessingComplete,
209+
kGetOutputMix,
210+
kGetNumberOfOutputChannels,
211+
kGetOutputSampleType,
212+
kGetSampleRate,
213+
kGetFrameSize,
214+
kReset,
215+
kResetWithNewMix,
216+
kSignalEndOfDecoding
217+
};
218+
219+
struct Operation {
220+
OperationType type;
221+
// Input data for methods that consume data.
222+
std::string data;
223+
int32_t chunk_size;
224+
std::optional<api::OutputLayout> output_layout;
225+
std::optional<uint32_t> mix_presentation_id;
226+
};
227+
228+
void RunOperation(api::IamfDecoder& iamf_decoder, const Operation& op,
229+
size_t& seed_offset, const std::string& seed_data) {
230+
switch (op.type) {
231+
case OperationType::kDecode: {
232+
size_t chunk_size = op.chunk_size;
233+
if (seed_offset < seed_data.size()) {
234+
chunk_size = std::min(chunk_size, seed_data.size() - seed_offset);
235+
auto unused_status = iamf_decoder.Decode(
236+
reinterpret_cast<const uint8_t*>(seed_data.data()) + seed_offset,
237+
chunk_size);
238+
seed_offset += chunk_size;
239+
} else {
240+
auto unused_status = iamf_decoder.Decode(nullptr, 0);
241+
}
242+
break;
243+
}
244+
case OperationType::kGetOutputTemporalUnit: {
245+
OutputAllTemporalUnits(iamf_decoder);
246+
break;
247+
}
248+
case OperationType::kIsTemporalUnitAvailable:
249+
iamf_decoder.IsTemporalUnitAvailable();
250+
break;
251+
case OperationType::kIsDescriptorProcessingComplete:
252+
iamf_decoder.IsDescriptorProcessingComplete();
253+
break;
254+
case OperationType::kGetOutputMix: {
255+
api::SelectedMix selected_mix;
256+
auto unused_status = iamf_decoder.GetOutputMix(selected_mix);
257+
break;
258+
}
259+
case OperationType::kGetNumberOfOutputChannels: {
260+
int num_channels = 0;
261+
auto unused_status = iamf_decoder.GetNumberOfOutputChannels(num_channels);
262+
break;
263+
}
264+
case OperationType::kGetOutputSampleType:
265+
iamf_decoder.GetOutputSampleType();
266+
break;
267+
case OperationType::kGetSampleRate: {
268+
uint32_t sample_rate = 0;
269+
auto unused_status = iamf_decoder.GetSampleRate(sample_rate);
270+
break;
271+
}
272+
case OperationType::kGetFrameSize: {
273+
uint32_t frame_size = 0;
274+
auto unused_status = iamf_decoder.GetFrameSize(frame_size);
275+
break;
276+
}
277+
case OperationType::kReset: {
278+
auto unused_status = iamf_decoder.Reset();
279+
break;
280+
}
281+
case OperationType::kResetWithNewMix: {
282+
api::RequestedMix requested_mix = {
283+
.mix_presentation_id = op.mix_presentation_id,
284+
.output_layout = op.output_layout};
285+
api::SelectedMix selected_mix;
286+
auto unused_status =
287+
iamf_decoder.ResetWithNewMix(requested_mix, selected_mix);
288+
break;
289+
}
290+
case OperationType::kSignalEndOfDecoding: {
291+
auto unused_status = iamf_decoder.SignalEndOfDecoding();
292+
break;
293+
}
294+
}
295+
}
296+
297+
void DoesNotDieWithArbitrarySequenceOfOperations(
298+
const std::string& seed_data, const std::vector<Operation>& operations) {
299+
std::unique_ptr<api::IamfDecoder> iamf_decoder;
300+
const api::IamfDecoder::Settings kDefaultSettings;
301+
302+
api::IamfStatus status =
303+
api::IamfDecoder::Create(kDefaultSettings, iamf_decoder);
304+
if (!status.ok()) {
305+
return;
306+
}
307+
308+
size_t seed_offset = 0;
309+
for (const auto& op : operations) {
310+
RunOperation(*iamf_decoder, op, seed_offset, seed_data);
311+
}
312+
}
313+
314+
auto AnyOperationType() {
315+
return ElementOf<OperationType>(
316+
{OperationType::kDecode, OperationType::kGetOutputTemporalUnit,
317+
OperationType::kIsTemporalUnitAvailable,
318+
OperationType::kIsDescriptorProcessingComplete,
319+
OperationType::kGetOutputMix, OperationType::kGetNumberOfOutputChannels,
320+
OperationType::kGetOutputSampleType, OperationType::kGetSampleRate,
321+
OperationType::kGetFrameSize, OperationType::kReset,
322+
OperationType::kResetWithNewMix, OperationType::kSignalEndOfDecoding});
323+
}
324+
325+
auto AnyOperation() {
326+
return fuzztest::StructOf<Operation>(
327+
AnyOperationType(), Arbitrary<std::string>(), Arbitrary<int32_t>(),
328+
OptionalOf(AnyOutputLayout()), OptionalOf(Arbitrary<uint32_t>()));
329+
}
330+
331+
std::vector<std::tuple<std::string, std::vector<Operation>>> GetSeeds() {
332+
auto files =
333+
fuzztest::ReadFilesFromDirectory(GetRunfilesPath(kIamfFileTestPath));
334+
// We have to return a tuple of string and vector of operations since that is
335+
// the argument of DoesNotDieWithArbitrarySequenceOfOperations. But we don't
336+
// have a specific set of operations to initially seed it with, so we leave it
337+
// as an empty vector. The fuzzer will start there and proceed to add
338+
// different sequences of operations.
339+
std::vector<std::tuple<std::string, std::vector<Operation>>> seeds;
340+
for (const auto& seed_file : files) {
341+
seeds.push_back({std::get<0>(seed_file), {}});
342+
}
343+
return seeds;
344+
}
345+
346+
FUZZ_TEST(IamfDecoderFuzzTest_RandomSequence,
347+
DoesNotDieWithArbitrarySequenceOfOperations)
348+
.WithDomains(Arbitrary<std::string>(), fuzztest::VectorOf(AnyOperation()))
349+
.WithSeeds(GetSeeds);
350+
203351
FUZZ_TEST(IamfDecoderFuzzTest_AllArbitraryParams, DoesNotDieAllParams)
204352
.WithDomains(OptionalOf(AnyOutputLayout()), // output_layout,
205353
AnyOutputSampleType(), // output_sample_type,

0 commit comments

Comments
 (0)