enc_dec_fuzzer.cc (5367B)
1 // Copyright 2018 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 #include <cstddef> 18 #include <cstdint> 19 #include <cstdio> 20 #include <cstdlib> 21 22 #include "./fuzz_utils.h" 23 #include "src/dsp/cpu.h" 24 #include "src/webp/decode.h" 25 #include "src/webp/encode.h" 26 27 namespace { 28 29 const VP8CPUInfo default_VP8GetCPUInfo = fuzz_utils::VP8GetCPUInfo; 30 31 void EncDecTest(bool use_argb, int source_image_index, WebPConfig config, 32 int optimization_index, 33 const fuzz_utils::CropOrScaleParams& crop_or_scale_params) { 34 fuzz_utils::SetOptimization(default_VP8GetCPUInfo, optimization_index); 35 36 // Init the source picture. 37 WebPPicture pic = fuzz_utils::GetSourcePicture(source_image_index, use_argb); 38 39 // Crop and scale. 40 if (!fuzz_utils::CropOrScale(&pic, crop_or_scale_params)) { 41 const WebPEncodingError error_code = pic.error_code; 42 WebPPictureFree(&pic); 43 if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return; 44 fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n", 45 error_code); 46 std::abort(); 47 } 48 49 // Skip slow settings on big images, it's likely to timeout. 50 if (pic.width * pic.height > 32 * 32) { 51 if (config.lossless) { 52 if (config.quality > 99.0f && config.method >= 5) { 53 config.quality = 99.0f; 54 config.method = 5; 55 } 56 } else { 57 if (config.quality > 99.0f && config.method == 6) { 58 config.quality = 99.0f; 59 } 60 } 61 if (config.alpha_quality == 100 && config.method == 6) { 62 config.alpha_quality = 99; 63 } 64 } 65 66 // Encode. 67 WebPMemoryWriter memory_writer; 68 WebPMemoryWriterInit(&memory_writer); 69 pic.writer = WebPMemoryWrite; 70 pic.custom_ptr = &memory_writer; 71 if (!WebPEncode(&config, &pic)) { 72 const WebPEncodingError error_code = pic.error_code; 73 WebPMemoryWriterClear(&memory_writer); 74 WebPPictureFree(&pic); 75 if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY || 76 error_code == VP8_ENC_ERROR_BAD_WRITE) { 77 return; 78 } 79 fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code); 80 std::abort(); 81 } 82 83 // Try decoding the result. 84 const uint8_t* const out_data = memory_writer.mem; 85 const size_t out_size = memory_writer.size; 86 WebPDecoderConfig dec_config; 87 if (!WebPInitDecoderConfig(&dec_config)) { 88 fprintf(stderr, "WebPInitDecoderConfig failed.\n"); 89 WebPMemoryWriterClear(&memory_writer); 90 WebPPictureFree(&pic); 91 std::abort(); 92 } 93 94 dec_config.output.colorspace = MODE_BGRA; 95 const VP8StatusCode status = WebPDecode(out_data, out_size, &dec_config); 96 if ((status != VP8_STATUS_OK && status != VP8_STATUS_OUT_OF_MEMORY && 97 status != VP8_STATUS_USER_ABORT) || 98 (status == VP8_STATUS_OK && (dec_config.output.width != pic.width || 99 dec_config.output.height != pic.height))) { 100 fprintf(stderr, "WebPDecode failed. status: %d.\n", status); 101 WebPFreeDecBuffer(&dec_config.output); 102 WebPMemoryWriterClear(&memory_writer); 103 WebPPictureFree(&pic); 104 std::abort(); 105 } 106 107 if (status == VP8_STATUS_OK) { 108 const uint8_t* const rgba = dec_config.output.u.RGBA.rgba; 109 const int w = dec_config.output.width; 110 const int h = dec_config.output.height; 111 112 // Compare the results if exact encoding. 113 if (pic.use_argb && config.lossless && config.near_lossless == 100) { 114 const uint32_t* src1 = (const uint32_t*)rgba; 115 const uint32_t* src2 = pic.argb; 116 for (int y = 0; y < h; ++y, src1 += w, src2 += pic.argb_stride) { 117 for (int x = 0; x < w; ++x) { 118 uint32_t v1 = src1[x], v2 = src2[x]; 119 if (!config.exact) { 120 if ((v1 & 0xff000000u) == 0 || (v2 & 0xff000000u) == 0) { 121 // Only keep alpha for comparison of fully transparent area. 122 v1 &= 0xff000000u; 123 v2 &= 0xff000000u; 124 } 125 } 126 if (v1 != v2) { 127 fprintf(stderr, "Lossless compression failed pixel-exactness.\n"); 128 WebPFreeDecBuffer(&dec_config.output); 129 WebPMemoryWriterClear(&memory_writer); 130 WebPPictureFree(&pic); 131 std::abort(); 132 } 133 } 134 } 135 } 136 } 137 138 WebPFreeDecBuffer(&dec_config.output); 139 WebPMemoryWriterClear(&memory_writer); 140 WebPPictureFree(&pic); 141 } 142 143 } // namespace 144 145 FUZZ_TEST(EncDec, EncDecTest) 146 .WithDomains(/*use_argb=*/fuzztest::Arbitrary<bool>(), 147 /*source_image_index=*/ 148 fuzztest::InRange<int>(0, fuzz_utils::kNumSourceImages - 1), 149 fuzz_utils::ArbitraryWebPConfig(), 150 /*optimization_index=*/ 151 fuzztest::InRange<uint32_t>(0, 152 fuzz_utils::kMaxOptimizationIndex), 153 fuzz_utils::ArbitraryCropOrScaleParams());