/src/fuzz_webp_animencoder.cc
Line | Count | Source (jump to first uncovered line) |
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 <stdio.h> |
18 | | #include <stdlib.h> |
19 | | #include "fuzz.h" |
20 | | #include "webp/encode.h" |
21 | | #include "webp/mux.h" |
22 | | |
23 | | namespace { |
24 | | |
25 | | const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo; |
26 | | |
27 | | int AddFrame(WebPAnimEncoder** const enc, |
28 | | const WebPAnimEncoderOptions& anim_config, int* const width, |
29 | | int* const height, int timestamp_ms, const uint8_t data[], |
30 | 34.4k | size_t size, uint32_t* const bit_pos) { |
31 | 34.4k | if (enc == nullptr || width == nullptr || height == nullptr) { |
32 | 0 | fprintf(stderr, "NULL parameters.\n"); |
33 | 0 | if (enc != nullptr) WebPAnimEncoderDelete(*enc); |
34 | 0 | abort(); |
35 | 0 | } |
36 | 34.4k | |
37 | 34.4k | // Init the source picture. |
38 | 34.4k | WebPPicture pic; |
39 | 34.4k | if (!WebPPictureInit(&pic)) { |
40 | 0 | fprintf(stderr, "WebPPictureInit failed.\n"); |
41 | 0 | WebPAnimEncoderDelete(*enc); |
42 | 0 | abort(); |
43 | 0 | } |
44 | 34.4k | pic.use_argb = Extract(1, data, size, bit_pos); |
45 | 34.4k | |
46 | 34.4k | // Read the source picture. |
47 | 34.4k | if (!ExtractSourcePicture(&pic, data, size, bit_pos)) { |
48 | 0 | fprintf(stderr, "Can't read input image.\n"); |
49 | 0 | WebPPictureFree(&pic); |
50 | 0 | abort(); |
51 | 0 | } |
52 | 34.4k | |
53 | 34.4k | // Crop and scale. |
54 | 34.4k | if (*enc == nullptr) { // First frame will set canvas width and height. |
55 | 3.44k | if (!ExtractAndCropOrScale(&pic, data, size, bit_pos)) { |
56 | 0 | fprintf(stderr, "ExtractAndCropOrScale failed."); |
57 | 0 | WebPPictureFree(&pic); |
58 | 0 | abort(); |
59 | 0 | } |
60 | 30.9k | } else { // Other frames will be resized to the first frame's dimensions. |
61 | 30.9k | if (!WebPPictureRescale(&pic, *width, *height)) { |
62 | 0 | fprintf(stderr, "WebPPictureRescale failed. Size: %d,%d\n", *width, |
63 | 0 | *height); |
64 | 0 | WebPAnimEncoderDelete(*enc); |
65 | 0 | WebPPictureFree(&pic); |
66 | 0 | abort(); |
67 | 0 | } |
68 | 34.4k | } |
69 | 34.4k | |
70 | 34.4k | // Create encoder if it doesn't exist. |
71 | 34.4k | if (*enc == nullptr) { |
72 | 3.44k | *width = pic.width; |
73 | 3.44k | *height = pic.height; |
74 | 3.44k | *enc = WebPAnimEncoderNew(*width, *height, &anim_config); |
75 | 3.44k | if (*enc == nullptr) { |
76 | 0 | fprintf(stderr, "WebPAnimEncoderNew failed.\n"); |
77 | 0 | WebPPictureFree(&pic); |
78 | 0 | abort(); |
79 | 0 | } |
80 | 34.4k | } |
81 | 34.4k | |
82 | 34.4k | // Create frame encoding config. |
83 | 34.4k | WebPConfig config; |
84 | 34.4k | if (!ExtractWebPConfig(&config, data, size, bit_pos)) { |
85 | 0 | fprintf(stderr, "ExtractWebPConfig failed.\n"); |
86 | 0 | WebPAnimEncoderDelete(*enc); |
87 | 0 | WebPPictureFree(&pic); |
88 | 0 | abort(); |
89 | 0 | } |
90 | 34.4k | // Skip slow settings on big images, it's likely to timeout. |
91 | 34.4k | if (pic.width * pic.height > 32 * 32) { |
92 | 17.0k | config.method = (config.method > 4) ? 4 : config.method; |
93 | 17.0k | config.quality = (config.quality > 99.0f) ? 99.0f : config.quality; |
94 | 17.0k | config.alpha_quality = |
95 | 17.0k | (config.alpha_quality > 99) ? 99 : config.alpha_quality; |
96 | 17.0k | } |
97 | 34.4k | |
98 | 34.4k | // Encode. |
99 | 34.4k | if (!WebPAnimEncoderAdd(*enc, &pic, timestamp_ms, &config)) { |
100 | 0 | fprintf(stderr, "WebPEncode failed. Error code: %d\n", pic.error_code); |
101 | 0 | WebPAnimEncoderDelete(*enc); |
102 | 0 | WebPPictureFree(&pic); |
103 | 0 | abort(); |
104 | 0 | } |
105 | 34.4k | |
106 | 34.4k | WebPPictureFree(&pic); |
107 | 34.4k | return 1; |
108 | 34.4k | } |
109 | | |
110 | | } // namespace |
111 | | |
112 | 3.44k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { |
113 | 3.44k | WebPAnimEncoder* enc = nullptr; |
114 | 3.44k | int width = 0, height = 0, timestamp_ms = 0; |
115 | 3.44k | uint32_t bit_pos = 0; |
116 | 3.44k | |
117 | 3.44k | ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos); |
118 | 3.44k | |
119 | 3.44k | // Extract a configuration from the packed bits. |
120 | 3.44k | WebPAnimEncoderOptions anim_config; |
121 | 3.44k | if (!WebPAnimEncoderOptionsInit(&anim_config)) { |
122 | 0 | fprintf(stderr, "WebPAnimEncoderOptionsInit failed.\n"); |
123 | 0 | abort(); |
124 | 0 | } |
125 | 3.44k | anim_config.minimize_size = Extract(1, data, size, &bit_pos); |
126 | 3.44k | anim_config.kmax = Extract(15, data, size, &bit_pos); |
127 | 3.44k | const int min_kmin = (anim_config.kmax > 1) ? (anim_config.kmax / 2) : 0; |
128 | 3.44k | const int max_kmin = (anim_config.kmax > 1) ? (anim_config.kmax - 1) : 0; |
129 | 3.44k | anim_config.kmin = |
130 | 3.44k | min_kmin + Extract((uint32_t)(max_kmin - min_kmin), data, size, &bit_pos); |
131 | 3.44k | anim_config.allow_mixed = Extract(1, data, size, &bit_pos); |
132 | 3.44k | anim_config.verbose = 0; |
133 | 3.44k | |
134 | 3.44k | const int nb_frames = 1 + Extract(15, data, size, &bit_pos); |
135 | 3.44k | |
136 | 3.44k | // For each frame. |
137 | 37.8k | for (int i = 0; i < nb_frames; ++i) { |
138 | 34.4k | if (!AddFrame(&enc, anim_config, &width, &height, timestamp_ms, data, size, |
139 | 34.4k | &bit_pos)) { |
140 | 0 | return 0; |
141 | 0 | } |
142 | 34.4k | |
143 | 34.4k | timestamp_ms += (1 << (2 + Extract(15, data, size, &bit_pos))) + |
144 | 34.4k | Extract(1, data, size, &bit_pos); // [1..131073], arbitrary |
145 | 34.4k | } |
146 | 3.44k | |
147 | 3.44k | // Assemble. |
148 | 3.44k | if (!WebPAnimEncoderAdd(enc, nullptr, timestamp_ms, nullptr)) { |
149 | 0 | fprintf(stderr, "Last WebPAnimEncoderAdd failed."); |
150 | 0 | WebPAnimEncoderDelete(enc); |
151 | 0 | abort(); |
152 | 0 | } |
153 | 3.44k | WebPData webp_data; |
154 | 3.44k | WebPDataInit(&webp_data); |
155 | 3.44k | if (!WebPAnimEncoderAssemble(enc, &webp_data)) { |
156 | 0 | fprintf(stderr, "WebPAnimEncoderAssemble failed."); |
157 | 0 | WebPAnimEncoderDelete(enc); |
158 | 0 | WebPDataClear(&webp_data); |
159 | 0 | abort(); |
160 | 0 | } |
161 | 3.44k | |
162 | 3.44k | WebPAnimEncoderDelete(enc); |
163 | 3.44k | WebPDataClear(&webp_data); |
164 | 3.44k | return 0; |
165 | 3.44k | } |