blob: 8c7d00de3a02cb2eae4cb60bca8910debd35b745 [file] [log] [blame]
// Copyright 2019 Google LLC
//
// 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.
// -----------------------------------------------------------------------------
//
// Fuzzing of animation wp2 encoding settings.
//
// Author: Yannis Guyon (yguyon@google.com)
#include <iostream>
#include <string>
#include <vector>
#include "imageio/anim_image_dec.h"
#include "src/wp2/encode.h"
#include "tests/fuzz/fuzz_utils.h"
#include "tests/include/helpers.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Input is considered random data and converted to parameters.
WP2::testing::FuzzedParameters params(data, size);
const char* file_name;
const uint8_t* file_data;
size_t file_size;
if (!params.ExtractSource(&file_name, &file_data, &file_size)) abort();
// Read a randomly chosen valid image file (possibly an animation).
std::vector<WP2::ArgbBuffer> original_frames;
std::vector<uint32_t> durations_ms;
uint32_t loop_count = 1;
const WP2Status read_status = WP2::testing::ReadAnimation(
file_data, file_size, &original_frames, &durations_ms, &loop_count);
if (read_status != WP2_STATUS_OK) {
std::cerr << "Unable to read " << file_name << ": "
<< WP2GetStatusMessage(read_status) << std::endl;
abort();
}
const bool loop_forever = (loop_count != 1);
// Encode up to ~1M pixels to avoid timeouts.
const size_t kMaxNumPixels = (1u << 20);
const size_t num_pixels_per_frame =
original_frames.front().width() * original_frames.front().height();
const size_t max_num_frames = 1u + kMaxNumPixels / num_pixels_per_frame;
if (original_frames.size() > max_num_frames) {
original_frames.resize(max_num_frames);
durations_ms.resize(max_num_frames);
}
// Make sure durations are valid for wp2 (to keep the same number of frames).
for (size_t i = 0; i < original_frames.size(); ++i) {
if (durations_ms[i] == WP2::ImageReader::kInfiniteDuration ||
durations_ms[i] > WP2::kMaxFrameDurationMs) {
durations_ms[i] = params.ExtractUInt32(1, WP2::kMaxFrameDurationMs);
}
}
// Extract a random config.
// Encoding settings are limited to guarantee a reasonable test duration.
const bool use_fast_config = (original_frames.front().width() > 128u ||
original_frames.front().height() > 128u);
const bool use_advanced_config = params.ExtractBool();
WP2::EncoderConfig config;
params.ExtractSimpleConfig(/*max_effort=*/use_fast_config ? 0 : 3, &config);
if (use_advanced_config) {
params.ExtractAdvancedConfig(use_fast_config, &config);
}
WP2::testing::ProgressTester progress_tester;
if (params.ExtractBool()) {
config.progress_hook = &progress_tester;
progress_tester.fail_at_ = params.ExtractDouble(0., 1.);
}
const bool compare_after_decoding = !use_advanced_config;
const float expected_distortion = WP2::testing::GetExpectedDistortion(config);
return WP2::testing::TestAnimEncConfig(
original_frames, durations_ms, loop_forever, config,
compare_after_decoding, expected_distortion);
}