/src/libultrahdr/fuzzer/ultrahdr_legacy_fuzzer.cpp
Line  | Count  | Source  | 
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 <iostream>  | 
20  |  | #include <memory>  | 
21  |  | #include <random>  | 
22  |  |  | 
23  |  | #include "ultrahdr/ultrahdrcommon.h"  | 
24  |  | #include "ultrahdr/gainmapmath.h"  | 
25  |  | #include "ultrahdr/jpegr.h"  | 
26  |  |  | 
27  |  | using namespace ultrahdr;  | 
28  |  |  | 
29  |  | // Color gamuts for image data, sync with ultrahdr.h  | 
30  |  | const int kCgMin = ULTRAHDR_COLORGAMUT_UNSPECIFIED;  | 
31  |  | const int kCgMax = ULTRAHDR_COLORGAMUT_BT2100;  | 
32  |  |  | 
33  |  | // Transfer functions for image data, sync with ultrahdr.h  | 
34  |  | const int kTfMin = ULTRAHDR_TF_UNSPECIFIED;  | 
35  |  | const int kTfMax = ULTRAHDR_TF_SRGB;  | 
36  |  |  | 
37  |  | // Transfer functions for image data, sync with ultrahdr.h  | 
38  |  | const int kOfMin = ULTRAHDR_OUTPUT_UNSPECIFIED;  | 
39  |  | const int kOfMax = ULTRAHDR_OUTPUT_HDR_HLG;  | 
40  |  |  | 
41  |  | // quality factor  | 
42  |  | const int kQfMin = -10;  | 
43  |  | const int kQfMax = 110;  | 
44  |  |  | 
45  |  | class UltraHdrEncFuzzer { | 
46  |  |  public:  | 
47  | 3.02k  |   UltraHdrEncFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {}; | 
48  |  |   void process();  | 
49  |  |   template <typename T>  | 
50  |  |   void fillBuffer(T* data, int width, int height, int stride);  | 
51  |  |  | 
52  |  |  private:  | 
53  |  |   FuzzedDataProvider mFdp;  | 
54  |  | };  | 
55  |  |  | 
56  |  | template <typename T>  | 
57  | 11.1k  | void UltraHdrEncFuzzer::fillBuffer(T* data, int width, int height, int stride) { | 
58  | 11.1k  |   if (!mFdp.remaining_bytes()) return;  | 
59  |  |  | 
60  | 3.38k  |   T* tmp = data;  | 
61  | 3.38k  |   std::vector<T> buffer(width);  | 
62  | 1.68M  |   for (int i = 0; i < buffer.size(); i++) { | 
63  | 1.68M  |     buffer[i] = mFdp.ConsumeIntegral<T>();  | 
64  | 1.68M  |   }  | 
65  | 2.60M  |   for (int j = 0; j < height; j++) { | 
66  | 5.19M  |     for (int i = 0; i < width; i += buffer.size()) { | 
67  | 2.59M  |       memcpy(tmp + i, buffer.data(), std::min((int)buffer.size(), (width - i)) * sizeof(*data));  | 
68  | 2.59M  |       std::shuffle(buffer.begin(), buffer.end(),  | 
69  | 2.59M  |                    std::default_random_engine(std::random_device{}())); | 
70  | 2.59M  |     }  | 
71  | 2.59M  |     tmp += stride;  | 
72  | 2.59M  |   }  | 
73  | 3.38k  | } void UltraHdrEncFuzzer::fillBuffer<unsigned short>(unsigned short*, int, int, int) Line  | Count  | Source  |  57  | 4.07k  | void UltraHdrEncFuzzer::fillBuffer(T* data, int width, int height, int stride) { |  58  | 4.07k  |   if (!mFdp.remaining_bytes()) return;  |  59  |  |  |  60  | 1.48k  |   T* tmp = data;  |  61  | 1.48k  |   std::vector<T> buffer(width);  |  62  | 640k  |   for (int i = 0; i < buffer.size(); i++) { |  63  | 638k  |     buffer[i] = mFdp.ConsumeIntegral<T>();  |  64  | 638k  |   }  |  65  | 1.13M  |   for (int j = 0; j < height; j++) { |  66  | 2.26M  |     for (int i = 0; i < width; i += buffer.size()) { |  67  | 1.13M  |       memcpy(tmp + i, buffer.data(), std::min((int)buffer.size(), (width - i)) * sizeof(*data));  |  68  | 1.13M  |       std::shuffle(buffer.begin(), buffer.end(),  |  69  | 1.13M  |                    std::default_random_engine(std::random_device{}())); |  70  | 1.13M  |     }  |  71  | 1.13M  |     tmp += stride;  |  72  | 1.13M  |   }  |  73  | 1.48k  | }  |  
 void UltraHdrEncFuzzer::fillBuffer<unsigned char>(unsigned char*, int, int, int) Line  | Count  | Source  |  57  | 7.11k  | void UltraHdrEncFuzzer::fillBuffer(T* data, int width, int height, int stride) { |  58  | 7.11k  |   if (!mFdp.remaining_bytes()) return;  |  59  |  |  |  60  | 1.90k  |   T* tmp = data;  |  61  | 1.90k  |   std::vector<T> buffer(width);  |  62  | 1.04M  |   for (int i = 0; i < buffer.size(); i++) { |  63  | 1.04M  |     buffer[i] = mFdp.ConsumeIntegral<T>();  |  64  | 1.04M  |   }  |  65  | 1.46M  |   for (int j = 0; j < height; j++) { |  66  | 2.93M  |     for (int i = 0; i < width; i += buffer.size()) { |  67  | 1.46M  |       memcpy(tmp + i, buffer.data(), std::min((int)buffer.size(), (width - i)) * sizeof(*data));  |  68  | 1.46M  |       std::shuffle(buffer.begin(), buffer.end(),  |  69  | 1.46M  |                    std::default_random_engine(std::random_device{}())); |  70  | 1.46M  |     }  |  71  | 1.46M  |     tmp += stride;  |  72  | 1.46M  |   }  |  73  | 1.90k  | }  |  
  | 
74  |  |  | 
75  | 3.02k  | void UltraHdrEncFuzzer::process() { | 
76  | 3.02k  |   if (mFdp.remaining_bytes()) { | 
77  | 3.02k  |     struct jpegr_uncompressed_struct p010Img{}; | 
78  | 3.02k  |     struct jpegr_uncompressed_struct yuv420Img{}; | 
79  | 3.02k  |     struct jpegr_uncompressed_struct grayImg{}; | 
80  | 3.02k  |     struct jpegr_compressed_struct jpegImgR{}; | 
81  | 3.02k  |     struct jpegr_compressed_struct jpegImg{}; | 
82  | 3.02k  |     struct jpegr_compressed_struct jpegGainMap{}; | 
83  |  |  | 
84  |  |     // which encode api to select  | 
85  | 3.02k  |     int muxSwitch = mFdp.ConsumeIntegralInRange<int>(0, 4);  | 
86  |  |  | 
87  |  |     // quality factor  | 
88  | 3.02k  |     int quality = mFdp.ConsumeIntegralInRange<int>(kQfMin, kQfMax);  | 
89  |  |  | 
90  |  |     // hdr_tf  | 
91  | 3.02k  |     auto tf =  | 
92  | 3.02k  |         static_cast<ultrahdr_transfer_function>(mFdp.ConsumeIntegralInRange<int>(kTfMin, kTfMax));  | 
93  |  |  | 
94  |  |     // p010 Cg  | 
95  | 3.02k  |     auto p010Cg =  | 
96  | 3.02k  |         static_cast<ultrahdr_color_gamut>(mFdp.ConsumeIntegralInRange<int>(kCgMin, kCgMax));  | 
97  |  |  | 
98  |  |     // 420 Cg  | 
99  | 3.02k  |     auto yuv420Cg =  | 
100  | 3.02k  |         static_cast<ultrahdr_color_gamut>(mFdp.ConsumeIntegralInRange<int>(kCgMin, kCgMax));  | 
101  |  |  | 
102  |  |     // hdr_of  | 
103  | 3.02k  |     auto of = static_cast<ultrahdr_output_format>(mFdp.ConsumeIntegralInRange<int>(kOfMin, kOfMax));  | 
104  |  |  | 
105  | 3.02k  |     int width = mFdp.ConsumeIntegralInRange<int>(kMinWidth, kMaxWidth);  | 
106  | 3.02k  |     width = (width >> 1) << 1;  | 
107  |  |  | 
108  | 3.02k  |     int height = mFdp.ConsumeIntegralInRange<int>(kMinHeight, kMaxHeight);  | 
109  | 3.02k  |     height = (height >> 1) << 1;  | 
110  |  |  | 
111  |  |     // gain_map quality factor  | 
112  | 3.02k  |     auto gainmap_quality = mFdp.ConsumeIntegral<int8_t>();  | 
113  |  |  | 
114  |  |     // multi channel gainmap  | 
115  | 3.02k  |     auto multi_channel_gainmap = mFdp.ConsumeIntegral<int8_t>();  | 
116  |  |  | 
117  |  |     // gainmap scale factor  | 
118  | 3.02k  |     auto gm_scale_factor = mFdp.ConsumeIntegralInRange<int16_t>(-32, 192);  | 
119  |  |  | 
120  |  |     // encoding speed preset  | 
121  | 3.02k  |     auto enc_preset = mFdp.ConsumeBool() ? UHDR_USAGE_REALTIME : UHDR_USAGE_BEST_QUALITY;  | 
122  |  |  | 
123  |  |     // gainmap metadata  | 
124  | 3.02k  |     auto minBoost = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 64.0f);  | 
125  | 3.02k  |     auto maxBoost = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 64.0f);  | 
126  | 3.02k  |     auto gamma = mFdp.ConsumeFloatingPointInRange<float>(-1.0f, 5);  | 
127  | 3.02k  |     auto offsetSdr = mFdp.ConsumeFloatingPointInRange<float>(-1.0f, 1.0f);  | 
128  | 3.02k  |     auto offsetHdr = mFdp.ConsumeFloatingPointInRange<float>(-1.0f, 1.0f);  | 
129  | 3.02k  |     auto minCapacity = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 48.0f);  | 
130  | 3.02k  |     auto maxCapacity = mFdp.ConsumeFloatingPointInRange<float>(-4.0f, 48.0f);  | 
131  |  |  | 
132  |  |     // target display peak brightness  | 
133  | 3.02k  |     auto targetDispPeakBrightness = mFdp.ConsumeFloatingPointInRange<float>(100.0f, 10500.0f);  | 
134  |  |  | 
135  |  |     // raw buffer config  | 
136  | 3.02k  |     bool hasP010Stride = mFdp.ConsumeBool();  | 
137  | 3.02k  |     size_t yP010Stride = mFdp.ConsumeIntegralInRange<uint16_t>(width, width + 128);  | 
138  | 3.02k  |     if (!hasP010Stride) yP010Stride = width;  | 
139  | 3.02k  |     bool isP010UVContiguous = mFdp.ConsumeBool();  | 
140  | 3.02k  |     bool hasP010UVStride = mFdp.ConsumeBool();  | 
141  | 3.02k  |     size_t uvP010Stride = mFdp.ConsumeIntegralInRange<uint16_t>(width, width + 128);  | 
142  | 3.02k  |     if (!hasP010UVStride) uvP010Stride = width;  | 
143  |  |  | 
144  | 3.02k  |     bool hasYuv420Stride = mFdp.ConsumeBool();  | 
145  | 3.02k  |     size_t yYuv420Stride = mFdp.ConsumeIntegralInRange<uint16_t>(width, width + 128);  | 
146  | 3.02k  |     if (!hasYuv420Stride) yYuv420Stride = width;  | 
147  | 3.02k  |     bool isYuv420UVContiguous = mFdp.ConsumeBool();  | 
148  | 3.02k  |     bool hasYuv420UVStride = mFdp.ConsumeBool();  | 
149  | 3.02k  |     size_t uvYuv420Stride = mFdp.ConsumeIntegralInRange<uint16_t>(width / 2, width / 2 + 128);  | 
150  | 3.02k  |     if (!hasYuv420UVStride) uvYuv420Stride = width / 2;  | 
151  |  |  | 
152  |  |     // display boost  | 
153  | 3.02k  |     float displayBoost = mFdp.ConsumeFloatingPointInRange<float>(1.0, FLT_MAX);  | 
154  |  |  | 
155  | 3.02k  |     std::unique_ptr<uint16_t[]> bufferYHdr = nullptr;  | 
156  | 3.02k  |     std::unique_ptr<uint16_t[]> bufferUVHdr = nullptr;  | 
157  | 3.02k  |     std::unique_ptr<uint8_t[]> bufferYSdr = nullptr;  | 
158  | 3.02k  |     std::unique_ptr<uint8_t[]> bufferUVSdr = nullptr;  | 
159  | 3.02k  |     std::unique_ptr<uint8_t[]> grayImgRaw = nullptr;  | 
160  | 3.02k  |     if (muxSwitch != 4) { | 
161  |  |       // init p010 image  | 
162  | 2.03k  |       p010Img.width = width;  | 
163  | 2.03k  |       p010Img.height = height;  | 
164  | 2.03k  |       p010Img.colorGamut = p010Cg;  | 
165  | 2.03k  |       p010Img.luma_stride = yP010Stride;  | 
166  | 2.03k  |       if (isP010UVContiguous) { | 
167  | 565  |         size_t p010Size = yP010Stride * height * 3 / 2;  | 
168  | 565  |         bufferYHdr = std::make_unique<uint16_t[]>(p010Size);  | 
169  | 565  |         p010Img.data = bufferYHdr.get();  | 
170  | 565  |         p010Img.chroma_data = nullptr;  | 
171  | 565  |         p010Img.chroma_stride = 0;  | 
172  | 565  |         fillBuffer<uint16_t>(bufferYHdr.get(), width, height, yP010Stride);  | 
173  | 565  |         fillBuffer<uint16_t>(bufferYHdr.get() + yP010Stride * height, width, height / 2,  | 
174  | 565  |                              yP010Stride);  | 
175  | 1.47k  |       } else { | 
176  | 1.47k  |         size_t p010YSize = yP010Stride * height;  | 
177  | 1.47k  |         bufferYHdr = std::make_unique<uint16_t[]>(p010YSize);  | 
178  | 1.47k  |         p010Img.data = bufferYHdr.get();  | 
179  | 1.47k  |         fillBuffer<uint16_t>(bufferYHdr.get(), width, height, yP010Stride);  | 
180  | 1.47k  |         size_t p010UVSize = uvP010Stride * p010Img.height / 2;  | 
181  | 1.47k  |         bufferUVHdr = std::make_unique<uint16_t[]>(p010UVSize);  | 
182  | 1.47k  |         p010Img.chroma_data = bufferUVHdr.get();  | 
183  | 1.47k  |         p010Img.chroma_stride = uvP010Stride;  | 
184  | 1.47k  |         fillBuffer<uint16_t>(bufferUVHdr.get(), width, height / 2, uvP010Stride);  | 
185  | 1.47k  |       }  | 
186  | 2.03k  |     } else { | 
187  | 991  |       size_t map_width = width / kMapDimensionScaleFactorDefault;  | 
188  | 991  |       size_t map_height = height / kMapDimensionScaleFactorDefault;  | 
189  |  |       // init 400 image  | 
190  | 991  |       grayImg.width = map_width;  | 
191  | 991  |       grayImg.height = map_height;  | 
192  | 991  |       grayImg.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;  | 
193  | 991  |       const size_t graySize = map_width * map_height;  | 
194  | 991  |       grayImgRaw = std::make_unique<uint8_t[]>(graySize);  | 
195  | 991  |       grayImg.data = grayImgRaw.get();  | 
196  | 991  |       fillBuffer<uint8_t>(grayImgRaw.get(), map_width, map_height, map_width);  | 
197  | 991  |       grayImg.chroma_data = nullptr;  | 
198  | 991  |       grayImg.luma_stride = 0;  | 
199  | 991  |       grayImg.chroma_stride = 0;  | 
200  | 991  |     }  | 
201  |  |  | 
202  | 3.02k  |     if (muxSwitch > 0) { | 
203  |  |       // init 420 image  | 
204  | 2.04k  |       yuv420Img.width = width;  | 
205  | 2.04k  |       yuv420Img.height = height;  | 
206  | 2.04k  |       yuv420Img.colorGamut = yuv420Cg;  | 
207  | 2.04k  |       yuv420Img.luma_stride = yYuv420Stride;  | 
208  | 2.04k  |       if (isYuv420UVContiguous) { | 
209  | 584  |         size_t yuv420Size = yYuv420Stride * height * 3 / 2;  | 
210  | 584  |         bufferYSdr = std::make_unique<uint8_t[]>(yuv420Size);  | 
211  | 584  |         yuv420Img.data = bufferYSdr.get();  | 
212  | 584  |         yuv420Img.chroma_data = nullptr;  | 
213  | 584  |         yuv420Img.chroma_stride = 0;  | 
214  | 584  |         fillBuffer<uint8_t>(bufferYSdr.get(), width, height, yYuv420Stride);  | 
215  | 584  |         fillBuffer<uint8_t>(bufferYSdr.get() + yYuv420Stride * height, width / 2, height / 2,  | 
216  | 584  |                             yYuv420Stride / 2);  | 
217  | 584  |         fillBuffer<uint8_t>(bufferYSdr.get() + yYuv420Stride * height * 5 / 4, width / 2,  | 
218  | 584  |                             height / 2, yYuv420Stride / 2);  | 
219  | 1.45k  |       } else { | 
220  | 1.45k  |         size_t yuv420YSize = yYuv420Stride * height;  | 
221  | 1.45k  |         bufferYSdr = std::make_unique<uint8_t[]>(yuv420YSize);  | 
222  | 1.45k  |         yuv420Img.data = bufferYSdr.get();  | 
223  | 1.45k  |         fillBuffer<uint8_t>(bufferYSdr.get(), width, height, yYuv420Stride);  | 
224  | 1.45k  |         size_t yuv420UVSize = uvYuv420Stride * yuv420Img.height / 2 * 2;  | 
225  | 1.45k  |         bufferUVSdr = std::make_unique<uint8_t[]>(yuv420UVSize);  | 
226  | 1.45k  |         yuv420Img.chroma_data = bufferUVSdr.get();  | 
227  | 1.45k  |         yuv420Img.chroma_stride = uvYuv420Stride;  | 
228  | 1.45k  |         fillBuffer<uint8_t>(bufferUVSdr.get(), width / 2, height / 2, uvYuv420Stride);  | 
229  | 1.45k  |         fillBuffer<uint8_t>(bufferUVSdr.get() + uvYuv420Stride * height / 2, width / 2, height / 2,  | 
230  | 1.45k  |                             uvYuv420Stride);  | 
231  | 1.45k  |       }  | 
232  | 2.04k  |     }  | 
233  |  |  | 
234  |  |     // dest  | 
235  |  |     // 2 * p010 size as input data is random, DCT compression might not behave as expected  | 
236  | 3.02k  |     jpegImgR.maxLength = std::max(64 * 1024 /* min size 8kb */, width * height * 3 * 2);  | 
237  | 3.02k  |     auto jpegImgRaw = std::make_unique<uint8_t[]>(jpegImgR.maxLength);  | 
238  | 3.02k  |     jpegImgR.data = jpegImgRaw.get();  | 
239  |  | // #define DUMP_PARAM  | 
240  |  | #ifdef DUMP_PARAM  | 
241  |  |     std::cout << "Api Select " << muxSwitch << std::endl;  | 
242  |  |     std::cout << "image dimensions " << width << " x " << height << std::endl;  | 
243  |  |     std::cout << "p010 color gamut " << p010Img.colorGamut << std::endl;  | 
244  |  |     std::cout << "p010 luma stride " << p010Img.luma_stride << std::endl;  | 
245  |  |     std::cout << "p010 chroma stride " << p010Img.chroma_stride << std::endl;  | 
246  |  |     std::cout << "420 color gamut " << yuv420Img.colorGamut << std::endl;  | 
247  |  |     std::cout << "420 luma stride " << yuv420Img.luma_stride << std::endl;  | 
248  |  |     std::cout << "420 chroma stride " << yuv420Img.chroma_stride << std::endl;  | 
249  |  |     std::cout << "quality factor " << quality << std::endl;  | 
250  |  | #endif  | 
251  | 3.02k  |     JpegR jpegHdr(nullptr, gm_scale_factor, gainmap_quality, multi_channel_gainmap, gamma,  | 
252  | 3.02k  |                   enc_preset, minBoost, maxBoost, targetDispPeakBrightness);  | 
253  | 3.02k  |     status_t status = JPEGR_UNKNOWN_ERROR;  | 
254  | 3.02k  |     if (muxSwitch == 0) {  // api 0 | 
255  | 985  |       jpegImgR.length = 0;  | 
256  | 985  |       status = jpegHdr.encodeJPEGR(&p010Img, tf, &jpegImgR, quality, nullptr);  | 
257  | 2.04k  |     } else if (muxSwitch == 1) {  // api 1 | 
258  | 338  |       jpegImgR.length = 0;  | 
259  | 338  |       status = jpegHdr.encodeJPEGR(&p010Img, &yuv420Img, tf, &jpegImgR, quality, nullptr);  | 
260  | 1.70k  |     } else { | 
261  |  |       // compressed img  | 
262  | 1.70k  |       JpegEncoderHelper encoder;  | 
263  | 1.70k  |       struct jpegr_uncompressed_struct yuv420ImgCopy = yuv420Img;  | 
264  | 1.70k  |       if (yuv420ImgCopy.luma_stride == 0) yuv420ImgCopy.luma_stride = yuv420Img.width;  | 
265  | 1.70k  |       if (!yuv420ImgCopy.chroma_data) { | 
266  | 437  |         uint8_t* data = reinterpret_cast<uint8_t*>(yuv420Img.data);  | 
267  | 437  |         yuv420ImgCopy.chroma_data = data + yuv420Img.luma_stride * yuv420Img.height;  | 
268  | 437  |         yuv420ImgCopy.chroma_stride = yuv420Img.luma_stride >> 1;  | 
269  | 437  |       }  | 
270  | 1.70k  |       const uint8_t* planes[3]{reinterpret_cast<uint8_t*>(yuv420ImgCopy.data), | 
271  | 1.70k  |                                reinterpret_cast<uint8_t*>(yuv420ImgCopy.chroma_data),  | 
272  | 1.70k  |                                reinterpret_cast<uint8_t*>(yuv420ImgCopy.chroma_data) +  | 
273  | 1.70k  |                                    yuv420ImgCopy.chroma_stride * yuv420ImgCopy.height / 2};  | 
274  | 1.70k  |       const unsigned int strides[3]{yuv420ImgCopy.luma_stride, yuv420ImgCopy.chroma_stride, | 
275  | 1.70k  |                                     yuv420ImgCopy.chroma_stride};  | 
276  | 1.70k  |       if (encoder  | 
277  | 1.70k  |               .compressImage(planes, strides, yuv420ImgCopy.width, yuv420ImgCopy.height,  | 
278  | 1.70k  |                              UHDR_IMG_FMT_12bppYCbCr420, quality, nullptr, 0)  | 
279  | 1.70k  |               .error_code == UHDR_CODEC_OK) { | 
280  | 1.70k  |         jpegImg.length = encoder.getCompressedImageSize();  | 
281  | 1.70k  |         jpegImg.maxLength = jpegImg.length;  | 
282  | 1.70k  |         jpegImg.data = encoder.getCompressedImagePtr();  | 
283  | 1.70k  |         jpegImg.colorGamut = yuv420Cg;  | 
284  | 1.70k  |         if (muxSwitch == 2) {  // api 2 | 
285  | 182  |           jpegImgR.length = 0;  | 
286  | 182  |           status = jpegHdr.encodeJPEGR(&p010Img, &yuv420Img, &jpegImg, tf, &jpegImgR);  | 
287  | 1.52k  |         } else if (muxSwitch == 3) {  // api 3 | 
288  | 531  |           jpegImgR.length = 0;  | 
289  | 531  |           status = jpegHdr.encodeJPEGR(&p010Img, &jpegImg, tf, &jpegImgR);  | 
290  | 991  |         } else if (muxSwitch == 4) {  // api 4 | 
291  | 991  |           jpegImgR.length = 0;  | 
292  | 991  |           JpegEncoderHelper gainMapEncoder;  | 
293  | 991  |           const uint8_t* planeGm[1]{reinterpret_cast<uint8_t*>(grayImg.data)}; | 
294  | 991  |           const unsigned int strideGm[1]{grayImg.width}; | 
295  | 991  |           if (gainMapEncoder  | 
296  | 991  |                   .compressImage(planeGm, strideGm, grayImg.width, grayImg.height,  | 
297  | 991  |                                  UHDR_IMG_FMT_8bppYCbCr400, quality, nullptr, 0)  | 
298  | 991  |                   .error_code == UHDR_CODEC_OK) { | 
299  | 991  |             jpegGainMap.length = gainMapEncoder.getCompressedImageSize();  | 
300  | 991  |             jpegGainMap.maxLength = jpegImg.length;  | 
301  | 991  |             jpegGainMap.data = gainMapEncoder.getCompressedImagePtr();  | 
302  | 991  |             jpegGainMap.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;  | 
303  | 991  |             ultrahdr_metadata_struct metadata;  | 
304  | 991  |             metadata.version = kJpegrVersion;  | 
305  | 991  |             metadata.maxContentBoost = maxBoost;  | 
306  | 991  |             metadata.minContentBoost = minBoost;  | 
307  | 991  |             metadata.gamma = gamma;  | 
308  | 991  |             metadata.offsetSdr = offsetSdr;  | 
309  | 991  |             metadata.offsetHdr = offsetHdr;  | 
310  | 991  |             metadata.hdrCapacityMin = minCapacity;  | 
311  | 991  |             metadata.hdrCapacityMax = maxCapacity;  | 
312  | 991  |             status = jpegHdr.encodeJPEGR(&jpegImg, &jpegGainMap, &metadata, &jpegImgR);  | 
313  | 991  |           }  | 
314  | 991  |         }  | 
315  | 1.70k  |       }  | 
316  | 1.70k  |     }  | 
317  | 3.02k  |     if (status == JPEGR_NO_ERROR) { | 
318  | 2.13k  |       jpegr_info_struct info{}; | 
319  | 2.13k  |       status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);  | 
320  | 2.13k  |       if (status == JPEGR_NO_ERROR) { | 
321  | 2.13k  |         size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);  | 
322  | 2.13k  |         jpegr_uncompressed_struct decodedJpegR;  | 
323  | 2.13k  |         auto decodedRaw = std::make_unique<uint8_t[]>(outSize);  | 
324  | 2.13k  |         decodedJpegR.data = decodedRaw.get();  | 
325  | 2.13k  |         ultrahdr_metadata_struct metadata;  | 
326  | 2.13k  |         status = jpegHdr.decodeJPEGR(&jpegImgR, &decodedJpegR, displayBoost, nullptr, of, nullptr,  | 
327  | 2.13k  |                                      &metadata);  | 
328  | 2.13k  |         if (status != JPEGR_NO_ERROR) { | 
329  | 700  |           ALOGE("encountered error during decoding %d", status); | 
330  | 700  |         }  | 
331  | 2.13k  |       } else { | 
332  | 0  |         ALOGE("encountered error during get jpeg info %d", status); | 
333  | 0  |       }  | 
334  | 2.13k  |     } else { | 
335  | 896  |       ALOGE("encountered error during encoding %d", status); | 
336  | 896  |     }  | 
337  | 3.02k  |   }  | 
338  | 3.02k  | }  | 
339  |  |  | 
340  | 13.6k  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 
341  | 13.6k  |   UltraHdrEncFuzzer fuzzHandle(data, size);  | 
342  | 13.6k  |   fuzzHandle.process();  | 
343  | 13.6k  |   return 0;  | 
344  | 13.6k  | }  |