Coverage Report

Created: 2026-06-15 07:18

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