/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 | } |