Coverage Report

Created: 2025-07-14 07:19

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