|
10 | 10 | * www.aomedia.org/license/patent. |
11 | 11 | */ |
12 | 12 |
|
| 13 | +#include <algorithm> |
13 | 14 | #include <cstddef> |
14 | 15 | #include <cstdint> |
15 | 16 | #include <optional> |
@@ -200,6 +201,153 @@ auto AnyChannelOrdering() { |
200 | 201 | }); |
201 | 202 | } |
202 | 203 |
|
| 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 | + |
203 | 351 | FUZZ_TEST(IamfDecoderFuzzTest_AllArbitraryParams, DoesNotDieAllParams) |
204 | 352 | .WithDomains(OptionalOf(AnyOutputLayout()), // output_layout, |
205 | 353 | AnyOutputSampleType(), // output_sample_type, |
|
0 commit comments