xref: /aosp_15_r20/external/libultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp (revision 89a0ef05262152531a00a15832a2d3b1e3990773)
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <fuzzer/FuzzedDataProvider.h>
18 #include <algorithm>
19 #include <random>
20 #include <type_traits>
21 
22 #include "ultrahdr_api.h"
23 #include "ultrahdr/ultrahdrcommon.h"
24 #include "ultrahdr/jpegr.h"
25 
26 using namespace ultrahdr;
27 
28 // Color gamuts for image data, sync with ultrahdr_api.h
29 constexpr int kCgMin = UHDR_CG_UNSPECIFIED;
30 constexpr int kCgMax = UHDR_CG_BT_2100;
31 
32 // Color ranges for image data, sync with ultrahdr_api.h
33 constexpr int kCrMin = UHDR_CR_UNSPECIFIED;
34 constexpr int kCrMax = UHDR_CR_FULL_RANGE;
35 
36 // Transfer functions for image data, sync with ultrahdr_api.h
37 constexpr int kTfMin = UHDR_CT_UNSPECIFIED;
38 constexpr int kTfMax = UHDR_CT_SRGB;
39 
40 class UltraHdrEncFuzzer {
41  public:
UltraHdrEncFuzzer(const uint8_t * data,size_t size)42   UltraHdrEncFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {};
43   void process();
44   template <typename T>
45   void fillBuffer(T* data, int width, int height, int stride);
46 
47  private:
48   FuzzedDataProvider mFdp;
49 };
50 
51 template <typename T>
fillBuffer(T * data,int width,int height,int stride)52 void UltraHdrEncFuzzer::fillBuffer(T* data, int width, int height, int stride) {
53   if (!mFdp.remaining_bytes()) return;
54 
55   T* tmp = data;
56   std::vector<T> buffer(width);
57   for (int i = 0; i < buffer.size(); i++) {
58     buffer[i] = mFdp.ConsumeIntegral<T>();
59   }
60   for (int j = 0; j < height; j++) {
61     for (int i = 0; i < width; i += buffer.size()) {
62       memcpy(tmp + i, buffer.data(), std::min((int)buffer.size(), (width - i)) * sizeof(*data));
63       std::shuffle(buffer.begin(), buffer.end(),
64                    std::default_random_engine(std::random_device{}()));
65     }
66     tmp += stride;
67   }
68 }
69 
process()70 void UltraHdrEncFuzzer::process() {
71   if (mFdp.remaining_bytes()) {
72     struct uhdr_raw_image hdrImg{};
73     struct uhdr_raw_image sdrImg{};
74     struct uhdr_raw_image gainmapImg{};
75 
76     // which encode api to select
77     int muxSwitch = mFdp.ConsumeIntegralInRange<int8_t>(0, 4);
78 
79     // hdr_img_fmt
80     uhdr_img_fmt_t hdr_img_fmt =
81         mFdp.PickValueInArray({UHDR_IMG_FMT_24bppYCbCrP010, UHDR_IMG_FMT_32bppRGBA1010102,
82                                UHDR_IMG_FMT_64bppRGBAHalfFloat});
83 
84     // sdr_img_fmt
85     uhdr_img_fmt_t sdr_img_fmt =
86         mFdp.ConsumeBool() ? UHDR_IMG_FMT_12bppYCbCr420 : UHDR_IMG_FMT_32bppRGBA8888;
87     if (muxSwitch > 1) sdr_img_fmt = UHDR_IMG_FMT_12bppYCbCr420;
88 
89     // width
90     int width = mFdp.ConsumeIntegralInRange<uint16_t>(kMinWidth, kMaxWidth);
91     if (hdr_img_fmt == UHDR_IMG_FMT_24bppYCbCrP010 || sdr_img_fmt == UHDR_IMG_FMT_12bppYCbCr420) {
92       width = (width >> 1) << 1;
93     }
94 
95     // height
96     int height = mFdp.ConsumeIntegralInRange<uint16_t>(kMinHeight, kMaxHeight);
97     if (hdr_img_fmt == UHDR_IMG_FMT_24bppYCbCrP010 || sdr_img_fmt == UHDR_IMG_FMT_12bppYCbCr420) {
98       height = (height >> 1) << 1;
99     }
100 
101     // hdr Ct
102     auto hdr_ct =
103         static_cast<uhdr_color_transfer_t>(mFdp.ConsumeIntegralInRange<int8_t>(kTfMin, kTfMax));
104 
105     // hdr Cg
106     auto hdr_cg =
107         static_cast<uhdr_color_gamut_t>(mFdp.ConsumeIntegralInRange<int8_t>(kCgMin, kCgMax));
108 
109     // sdr Cg
110     auto sdr_cg =
111         static_cast<uhdr_color_gamut_t>(mFdp.ConsumeIntegralInRange<int8_t>(kCgMin, kCgMax));
112 
113     // color range
114     auto hdr_cr =
115         static_cast<uhdr_color_range_t>(mFdp.ConsumeIntegralInRange<int8_t>(kCrMin, kCrMax));
116 
117     // base quality factor
118     auto base_quality = mFdp.ConsumeIntegral<int8_t>();
119 
120     // gain_map quality factor
121     auto gainmap_quality = mFdp.ConsumeIntegral<int8_t>();
122 
123     // multi channel gainmap
124     auto multi_channel_gainmap = mFdp.ConsumeIntegral<int8_t>();
125 
126     // gainmap scale factor
127     auto gm_scale_factor = mFdp.ConsumeIntegralInRange<int16_t>(-32, 192);
128 
129     // encoding speed preset
130     auto enc_preset = mFdp.ConsumeBool() ? UHDR_USAGE_REALTIME : UHDR_USAGE_BEST_QUALITY;
131 
132     // gainmap metadata
133     auto minBoost = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 64.0f);
134     auto maxBoost = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 64.0f);
135     auto gamma = mFdp.ConsumeFloatingPointInRange<float>(-1.0f, 5);
136     auto offsetSdr = mFdp.ConsumeFloatingPointInRange<float>(-1.0f, 1.0f);
137     auto offsetHdr = mFdp.ConsumeFloatingPointInRange<float>(-1.0f, 1.0f);
138     auto minCapacity = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 48.0f);
139     auto maxCapacity = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 48.0f);
140 
141     // target display peak brightness
142     auto targetDispPeakBrightness = mFdp.ConsumeFloatingPointInRange<float>(100.0f, 10500.0f);
143 
144     // raw buffer config
145     bool hasHdrStride = mFdp.ConsumeBool();
146     size_t yHdrStride = mFdp.ConsumeIntegralInRange<uint16_t>(width, width + 128);
147     if (!hasHdrStride) yHdrStride = width;
148     bool isHdrUVContiguous = mFdp.ConsumeBool();
149     bool hasHdrUVStride = mFdp.ConsumeBool();
150     size_t uvHdrStride = mFdp.ConsumeIntegralInRange<uint16_t>(width, width + 128);
151     if (!hasHdrUVStride) uvHdrStride = width;
152 
153     bool hasSdrStride = mFdp.ConsumeBool();
154     size_t ySdrStride = mFdp.ConsumeIntegralInRange<uint16_t>(width, width + 128);
155     if (!hasSdrStride) ySdrStride = width;
156     bool isSdrUVContiguous = mFdp.ConsumeBool();
157     bool hasSdrUVStride = mFdp.ConsumeBool();
158     size_t uvSdrStride = mFdp.ConsumeIntegralInRange<uint16_t>(width / 2, width / 2 + 128);
159     if (!hasSdrUVStride) uvSdrStride = width / 2;
160 
161     // editing effects
162     auto applyMirror = mFdp.ConsumeBool();
163     uhdr_mirror_direction_t direction =
164         mFdp.ConsumeBool() ? UHDR_MIRROR_VERTICAL : UHDR_MIRROR_HORIZONTAL;
165 
166     auto applyRotate = mFdp.ConsumeBool();
167     int degrees = degrees = mFdp.PickValueInArray({-90, 0, 90, 180, 270});
168 
169     auto applyCrop = mFdp.ConsumeBool();
170     int left = mFdp.ConsumeIntegral<int16_t>();
171     int right = mFdp.ConsumeIntegral<int16_t>();
172     int top = mFdp.ConsumeIntegral<int16_t>();
173     int bottom = mFdp.ConsumeIntegral<int16_t>();
174 
175     auto applyResize = mFdp.ConsumeBool();
176     int resizeWidth = mFdp.ConsumeIntegralInRange<int32_t>(-32, kMaxWidth + 128);
177     int resizeHeight = mFdp.ConsumeIntegralInRange<int32_t>(-32, kMaxHeight + 128);
178 
179     // exif
180     char greeting[] = "Exif says hello world";
181     uhdr_mem_block_t exif{greeting, mFdp.ConsumeIntegralInRange<uint8_t>(0, sizeof greeting * 2),
182                           sizeof greeting};
183 
184     ALOGV("encoding configuration options : ");
185     ALOGV("encoding api - %d ", (int)muxSwitch);
186     ALOGV("image dimensions %d x %d ", (int)width, (int)height);
187     ALOGV("hdr intent color aspects: gamut %d, transfer %d, range %d, format %d ", (int)hdr_cg,
188           (int)hdr_ct, (int)hdr_cr, (int)hdr_img_fmt);
189     ALOGV("sdr intent color aspects: gamut %d, format %d ", (int)sdr_cg, (int)sdr_img_fmt);
190     ALOGV(
191         "gainmap img config: scale factor %d, enabled multichannel gainmap %s, gainmap quality %d ",
192         (int)gm_scale_factor, (int)multi_channel_gainmap ? "Yes" : "No", (int)gainmap_quality);
193     ALOGV("base image quality %d ", (int)base_quality);
194     ALOGV("encoding preset %d ", (int)enc_preset);
195     ALOGV(
196         "gainmap metadata: min content boost %f, max content boost %f, gamma %f, offset sdr %f, "
197         "offset hdr %f, hdr min capacity %f, hdr max capacity %f",
198         (float)minBoost, (float)maxBoost, (float)gamma, (float)offsetSdr, (float)offsetHdr,
199         (float)minCapacity, (float)maxCapacity);
200     ALOGV("hdr intent luma stride %d, chroma stride %d", yHdrStride, uvHdrStride);
201     ALOGV("sdr intent luma stride %d, chroma stride %d", ySdrStride, uvSdrStride);
202     if (applyMirror) ALOGV("added mirror effect, direction %d", (int)direction);
203     if (applyRotate) ALOGV("added rotate effect, degrees %d", (int)degrees);
204     if (applyCrop)
205       ALOGV("added crop effect, crop-left %d, crop-right %d, crop-top %d, crop-bottom %d", left,
206             right, top, bottom);
207     if (applyResize)
208       ALOGV("added resize effect, resize wd %d, resize ht %d", resizeWidth, resizeHeight);
209 
210     std::unique_ptr<uint64_t[]> bufferFpHdr = nullptr;
211     std::unique_ptr<uint32_t[]> bufferHdr = nullptr;
212     std::unique_ptr<uint16_t[]> bufferYHdr = nullptr;
213     std::unique_ptr<uint16_t[]> bufferUVHdr = nullptr;
214     std::unique_ptr<uint8_t[]> bufferYSdr = nullptr;
215     std::unique_ptr<uint8_t[]> bufferUVSdr = nullptr;
216     std::unique_ptr<uint8_t[]> gainMapImageRaw = nullptr;
217     uhdr_codec_private_t* enc_handle = uhdr_create_encoder();
218     if (!enc_handle) {
219       ALOGE("Failed to create encoder");
220       return;
221     }
222 
223 #define ON_ERR(x)                              \
224   {                                            \
225     uhdr_error_info_t status_ = (x);           \
226     if (status_.error_code != UHDR_CODEC_OK) { \
227       if (status_.has_detail) {                \
228         ALOGE("%s", status_.detail);           \
229       }                                        \
230     }                                          \
231   }
232     if (muxSwitch != 4) {
233       // init p010/rgba1010102 image
234       hdrImg.w = width;
235       hdrImg.h = height;
236       hdrImg.cg = hdr_cg;
237       hdrImg.fmt = hdr_img_fmt;
238       hdrImg.ct = hdr_ct;
239       hdrImg.range = hdr_cr;
240       hdrImg.stride[UHDR_PLANE_Y] = yHdrStride;
241       if (hdr_img_fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
242         if (isHdrUVContiguous) {
243           size_t p010Size = yHdrStride * height * 3 / 2;
244           bufferYHdr = std::make_unique<uint16_t[]>(p010Size);
245           hdrImg.planes[UHDR_PLANE_Y] = bufferYHdr.get();
246           fillBuffer<uint16_t>(bufferYHdr.get(), width, height, yHdrStride);
247           fillBuffer<uint16_t>(bufferYHdr.get() + yHdrStride * height, width, height / 2,
248                                yHdrStride);
249           hdrImg.planes[UHDR_PLANE_UV] = bufferYHdr.get() + yHdrStride * height;
250           hdrImg.stride[UHDR_PLANE_UV] = yHdrStride;
251         } else {
252           size_t p010Size = yHdrStride * height;
253           bufferYHdr = std::make_unique<uint16_t[]>(p010Size);
254           hdrImg.planes[UHDR_PLANE_Y] = bufferYHdr.get();
255           fillBuffer<uint16_t>(bufferYHdr.get(), width, height, yHdrStride);
256           size_t p010UVSize = uvHdrStride * hdrImg.h / 2;
257           bufferUVHdr = std::make_unique<uint16_t[]>(p010UVSize);
258           hdrImg.planes[UHDR_PLANE_UV] = bufferUVHdr.get();
259           hdrImg.stride[UHDR_PLANE_UV] = uvHdrStride;
260           fillBuffer<uint16_t>(bufferUVHdr.get(), width, height / 2, uvHdrStride);
261         }
262       } else if (hdr_img_fmt == UHDR_IMG_FMT_32bppRGBA1010102) {
263         size_t rgba1010102Size = yHdrStride * height;
264         bufferHdr = std::make_unique<uint32_t[]>(rgba1010102Size);
265         hdrImg.planes[UHDR_PLANE_PACKED] = bufferHdr.get();
266         fillBuffer<uint32_t>(bufferHdr.get(), width, height, yHdrStride);
267         hdrImg.planes[UHDR_PLANE_U] = nullptr;
268         hdrImg.stride[UHDR_PLANE_U] = 0;
269       } else if (hdr_img_fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
270         size_t rgbafp16Size = yHdrStride * height;
271         bufferFpHdr = std::make_unique<uint64_t[]>(rgbafp16Size);
272         hdrImg.planes[UHDR_PLANE_PACKED] = bufferFpHdr.get();
273         fillBuffer<uint64_t>(bufferFpHdr.get(), width, height, yHdrStride);
274         hdrImg.planes[UHDR_PLANE_U] = nullptr;
275         hdrImg.stride[UHDR_PLANE_U] = 0;
276       }
277       hdrImg.planes[UHDR_PLANE_V] = nullptr;
278       hdrImg.stride[UHDR_PLANE_V] = 0;
279       ON_ERR(uhdr_enc_set_raw_image(enc_handle, &hdrImg, UHDR_HDR_IMG))
280     } else {
281       size_t map_width = width / ((gm_scale_factor <= 0) ? 1 : gm_scale_factor);
282       size_t map_height = height / ((gm_scale_factor <= 0) ? 1 : gm_scale_factor);
283       gainmapImg.fmt = UHDR_IMG_FMT_8bppYCbCr400;
284       gainmapImg.w = map_width;
285       gainmapImg.h = map_height;
286       gainmapImg.cg = UHDR_CG_UNSPECIFIED;
287       gainmapImg.ct = UHDR_CT_UNSPECIFIED;
288       gainmapImg.range = UHDR_CR_FULL_RANGE;
289       const size_t graySize = map_width * map_height;
290       gainMapImageRaw = std::make_unique<uint8_t[]>(graySize);
291       gainmapImg.planes[UHDR_PLANE_Y] = gainMapImageRaw.get();
292       gainmapImg.stride[UHDR_PLANE_Y] = map_width;
293       gainmapImg.planes[UHDR_PLANE_U] = nullptr;
294       gainmapImg.planes[UHDR_PLANE_V] = nullptr;
295       gainmapImg.stride[UHDR_PLANE_U] = 0;
296       gainmapImg.stride[UHDR_PLANE_V] = 0;
297       fillBuffer<uint8_t>(gainMapImageRaw.get(), map_width, map_height, map_width);
298     }
299 
300     if (muxSwitch > 0) {
301       // init yuv420 Image
302       if (sdr_img_fmt == UHDR_IMG_FMT_12bppYCbCr420) {
303         sdrImg.w = width;
304         sdrImg.h = height;
305         sdrImg.cg = sdr_cg;
306         sdrImg.fmt = UHDR_IMG_FMT_12bppYCbCr420;
307         sdrImg.ct = UHDR_CT_SRGB;
308         sdrImg.range = UHDR_CR_FULL_RANGE;
309         sdrImg.stride[UHDR_PLANE_Y] = ySdrStride;
310         if (isSdrUVContiguous) {
311           size_t yuv420Size = ySdrStride * height * 3 / 2;
312           bufferYSdr = std::make_unique<uint8_t[]>(yuv420Size);
313           sdrImg.planes[UHDR_PLANE_Y] = bufferYSdr.get();
314           sdrImg.planes[UHDR_PLANE_U] = bufferYSdr.get() + ySdrStride * height;
315           sdrImg.planes[UHDR_PLANE_V] = bufferYSdr.get() + ySdrStride * height * 5 / 4;
316           sdrImg.stride[UHDR_PLANE_U] = ySdrStride / 2;
317           sdrImg.stride[UHDR_PLANE_V] = ySdrStride / 2;
318           fillBuffer<uint8_t>(bufferYSdr.get(), width, height, ySdrStride);
319           fillBuffer<uint8_t>(bufferYSdr.get() + ySdrStride * height, width / 2, height / 2,
320                               ySdrStride / 2);
321           fillBuffer<uint8_t>(bufferYSdr.get() + ySdrStride * height * 5 / 4, width / 2, height / 2,
322                               ySdrStride / 2);
323         } else {
324           size_t yuv420YSize = ySdrStride * height;
325           bufferYSdr = std::make_unique<uint8_t[]>(yuv420YSize);
326           sdrImg.planes[UHDR_PLANE_Y] = bufferYSdr.get();
327           fillBuffer<uint8_t>(bufferYSdr.get(), width, height, ySdrStride);
328           size_t yuv420UVSize = uvSdrStride * sdrImg.h / 2 * 2;
329           bufferUVSdr = std::make_unique<uint8_t[]>(yuv420UVSize);
330           sdrImg.planes[UHDR_PLANE_U] = bufferUVSdr.get();
331           sdrImg.stride[UHDR_PLANE_U] = uvSdrStride;
332           fillBuffer<uint8_t>(bufferUVSdr.get(), width / 2, height / 2, uvSdrStride);
333           fillBuffer<uint8_t>(bufferUVSdr.get() + uvSdrStride * height / 2, width / 2, height / 2,
334                               uvSdrStride);
335           sdrImg.planes[UHDR_PLANE_V] = bufferUVSdr.get() + uvSdrStride * height / 2;
336           sdrImg.stride[UHDR_PLANE_V] = uvSdrStride;
337         }
338       } else if (sdr_img_fmt == UHDR_IMG_FMT_32bppRGBA8888) {
339         sdrImg.w = width;
340         sdrImg.h = height;
341         sdrImg.cg = sdr_cg;
342         sdrImg.fmt = UHDR_IMG_FMT_32bppRGBA8888;
343         sdrImg.ct = UHDR_CT_SRGB;
344         sdrImg.range = UHDR_CR_FULL_RANGE;
345         sdrImg.stride[UHDR_PLANE_PACKED] = ySdrStride;
346         size_t rgba8888Size = ySdrStride * height;
347         bufferHdr = std::make_unique<uint32_t[]>(rgba8888Size);
348         sdrImg.planes[UHDR_PLANE_PACKED] = bufferHdr.get();
349         fillBuffer<uint32_t>(bufferHdr.get(), width, height, ySdrStride);
350         sdrImg.planes[UHDR_PLANE_U] = nullptr;
351         sdrImg.planes[UHDR_PLANE_V] = nullptr;
352         sdrImg.stride[UHDR_PLANE_U] = 0;
353         sdrImg.stride[UHDR_PLANE_V] = 0;
354       }
355     }
356     if (muxSwitch == 1 || muxSwitch == 2) {
357       ON_ERR(uhdr_enc_set_raw_image(enc_handle, &sdrImg, UHDR_SDR_IMG))
358     }
359     ON_ERR(uhdr_enc_set_quality(enc_handle, base_quality, UHDR_BASE_IMG))
360     ON_ERR(uhdr_enc_set_quality(enc_handle, gainmap_quality, UHDR_GAIN_MAP_IMG))
361     ON_ERR(uhdr_enc_set_exif_data(enc_handle, &exif))
362     ON_ERR(uhdr_enc_set_using_multi_channel_gainmap(enc_handle, multi_channel_gainmap))
363     ON_ERR(uhdr_enc_set_gainmap_scale_factor(enc_handle, gm_scale_factor))
364     ON_ERR(uhdr_enc_set_gainmap_gamma(enc_handle, gamma))
365     ON_ERR(uhdr_enc_set_min_max_content_boost(enc_handle, minBoost, maxBoost))
366     ON_ERR(uhdr_enc_set_target_display_peak_brightness(enc_handle, targetDispPeakBrightness))
367     ON_ERR(uhdr_enc_set_preset(enc_handle, enc_preset))
368     ON_ERR(uhdr_enable_gpu_acceleration(enc_handle, 1))
369     if (applyMirror) ON_ERR(uhdr_add_effect_mirror(enc_handle, direction))
370     if (applyRotate) ON_ERR(uhdr_add_effect_rotate(enc_handle, degrees))
371     if (applyCrop) ON_ERR(uhdr_add_effect_crop(enc_handle, left, right, top, bottom))
372     if (applyResize) ON_ERR(uhdr_add_effect_resize(enc_handle, resizeWidth, resizeHeight))
373 
374     uhdr_error_info_t status = {UHDR_CODEC_OK, 0, ""};
375     if (muxSwitch == 0 || muxSwitch == 1) {  // api 0 or api 1
376       status = uhdr_encode(enc_handle);
377     } else {
378       // compressed img
379       JpegEncoderHelper encoder;
380       if (encoder.compressImage(&sdrImg, base_quality, nullptr, 0).error_code == UHDR_CODEC_OK) {
381         struct uhdr_compressed_image jpegImg = encoder.getCompressedImage();
382         jpegImg.cg = sdr_cg;
383         if (muxSwitch != 4) {
384           // for api 4 compressed image will be set with UHDR_BASE_IMG intent
385           uhdr_enc_set_compressed_image(enc_handle, &jpegImg, UHDR_SDR_IMG);
386         }
387         if (muxSwitch == 2 || muxSwitch == 3) {  // api 2 or api 3
388           status = uhdr_encode(enc_handle);
389         } else if (muxSwitch == 4) {  // api 4
390           JpegEncoderHelper gainMapEncoder;
391           if (gainMapEncoder.compressImage(&gainmapImg, gainmap_quality, nullptr, 0).error_code ==
392               UHDR_CODEC_OK) {
393             struct uhdr_compressed_image jpegGainMap = gainMapEncoder.getCompressedImage();
394             uhdr_gainmap_metadata metadata;
395             metadata.max_content_boost = maxBoost;
396             metadata.min_content_boost = minBoost;
397             metadata.gamma = gamma;
398             metadata.offset_sdr = offsetSdr;
399             metadata.offset_hdr = offsetHdr;
400             metadata.hdr_capacity_min = minCapacity;
401             metadata.hdr_capacity_max = maxCapacity;
402             ON_ERR(uhdr_enc_set_compressed_image(enc_handle, &jpegImg, UHDR_BASE_IMG))
403             ON_ERR(uhdr_enc_set_gainmap_image(enc_handle, &jpegGainMap, &metadata))
404             status = uhdr_encode(enc_handle);
405           }
406         }
407       }
408     }
409     if (status.error_code == UHDR_CODEC_OK) {
410       auto output = uhdr_get_encoded_stream(enc_handle);
411       if (output != nullptr) {
412         uhdr_codec_private_t* dec_handle = uhdr_create_decoder();
413         if (dec_handle) {
414           ON_ERR(uhdr_dec_set_image(dec_handle, output))
415           ON_ERR(uhdr_dec_set_out_color_transfer(dec_handle, hdr_ct))
416           if (hdr_ct == UHDR_CT_LINEAR)
417             ON_ERR(uhdr_dec_set_out_img_format(dec_handle, UHDR_IMG_FMT_64bppRGBAHalfFloat))
418           else if (hdr_ct == UHDR_CT_SRGB)
419             ON_ERR(uhdr_dec_set_out_img_format(dec_handle, UHDR_IMG_FMT_32bppRGBA8888))
420           else
421             ON_ERR(uhdr_dec_set_out_img_format(dec_handle, UHDR_IMG_FMT_32bppRGBA1010102))
422           ON_ERR(uhdr_decode(dec_handle))
423           uhdr_release_decoder(dec_handle);
424         }
425       }
426     }
427     uhdr_reset_encoder(enc_handle);
428     uhdr_release_encoder(enc_handle);
429     ON_ERR(status);
430   }
431 }
432 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)433 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
434   UltraHdrEncFuzzer fuzzHandle(data, size);
435   fuzzHandle.process();
436   return 0;
437 }
438