1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "jpeg_yuvdata_converter.h"
17
18 #include <algorithm>
19
20 #include "jpeg_decoder_yuv.h"
21 #include "securec.h"
22
23 namespace OHOS {
24 namespace ImagePlugin {
25
26 #define EVEN_MASK 1
27 #define AVERAGE_FACTOR 2
28
29 #define SAMPLE_FACTOR420 2
30 #define MAXUVSCALE_JPEG 4
31
32 #define SCALE_444_X 1
33 #define SCALE_444_Y 1
34 #define SCALE_422_X 2
35 #define SCALE_422_Y 1
36 #define SCALE_420_X 2
37 #define SCALE_420_Y 2
38 #define SCALE_440_X 1
39 #define SCALE_440_Y 2
40 #define SCALE_411_X 4
41 #define SCALE_411_Y 1
42
IsValidYuvData(const YuvPlaneInfo & data)43 static bool IsValidYuvData(const YuvPlaneInfo &data)
44 {
45 if (data.planes[YCOM] == nullptr || data.planes[UCOM] == nullptr || data.planes[VCOM] == nullptr ||
46 data.strides[YCOM] == 0 || data.strides[UCOM] == 0 || data.strides[VCOM] == 0) {
47 return false;
48 } else {
49 return true;
50 }
51 }
52
IsValidYuvNVData(const YuvPlaneInfo & data)53 static bool IsValidYuvNVData(const YuvPlaneInfo &data)
54 {
55 if (data.planes[YCOM] == nullptr || data.planes[UVCOM] == nullptr ||
56 data.strides[YCOM] == 0 || data.strides[UVCOM] == 0) {
57 return false;
58 } else {
59 return true;
60 }
61 }
62
IsValidYuvGrayData(const YuvPlaneInfo & data)63 static bool IsValidYuvGrayData(const YuvPlaneInfo &data)
64 {
65 if (data.planes[YCOM] == nullptr || data.strides[YCOM] == 0) {
66 return false;
67 } else {
68 return true;
69 }
70 }
71
IsValidSize(uint32_t width,uint32_t height)72 static bool IsValidSize(uint32_t width, uint32_t height)
73 {
74 if (width == 0 || height == 0) {
75 return false;
76 } else {
77 return true;
78 }
79 }
80
IsValidScaleFactor(uint8_t factor)81 static bool IsValidScaleFactor(uint8_t factor)
82 {
83 if (factor > MAXUVSCALE_JPEG || factor == 0) {
84 return false;
85 } else {
86 return true;
87 }
88 }
89
CopyLineData(uint8_t * dest,uint32_t destStride,const uint8_t * src,uint32_t srcStride)90 static bool CopyLineData(uint8_t *dest, uint32_t destStride, const uint8_t *src, uint32_t srcStride)
91 {
92 if (srcStride == 0 || destStride == 0) {
93 return false;
94 }
95 errno_t ret = memcpy_s(dest, destStride, src, std::min(srcStride, destStride));
96 if (ret != EOK) {
97 return false;
98 }
99 if (destStride > srcStride) {
100 uint32_t count = destStride - srcStride;
101 uint8_t lastValueinCurrentSrcLine = *(src + srcStride - 1);
102 ret = memset_s(dest + srcStride, count, lastValueinCurrentSrcLine, count);
103 if (ret != EOK) {
104 return false;
105 }
106 }
107 return true;
108 }
109
SampleUV(const uint8_t * srcUV,int stride,bool canUseNextRow,bool canUseNextColumn)110 static uint8_t SampleUV(const uint8_t* srcUV, int stride, bool canUseNextRow, bool canUseNextColumn)
111 {
112 const uint8_t* srcUVNextLine = nullptr;
113 if (canUseNextRow) {
114 srcUVNextLine = srcUV + stride;
115 }
116 if (srcUVNextLine != nullptr) {
117 return (*srcUV + *srcUVNextLine) / AVERAGE_FACTOR;
118 }
119 if (canUseNextColumn) {
120 return (*srcUV + *(srcUV + 1)) / AVERAGE_FACTOR;
121 }
122 return *srcUV;
123 }
124
VerifyParameter(const YuvPlaneInfo & src,const YuvPlaneInfo & dest,uint8_t srcXScale,uint8_t srcYScale,bool outYU12)125 static bool VerifyParameter(const YuvPlaneInfo &src, const YuvPlaneInfo &dest,
126 uint8_t srcXScale, uint8_t srcYScale, bool outYU12)
127 {
128 uint32_t width = src.imageWidth;
129 uint32_t height = src.imageHeight;
130 if (!IsValidYuvData(src) || !IsValidSize(width, height) ||
131 !IsValidScaleFactor(srcXScale) || !IsValidScaleFactor(srcYScale)) {
132 return false;
133 }
134 if (outYU12 && !IsValidYuvData(dest)) {
135 return false;
136 } else if (!outYU12 && !IsValidYuvNVData(dest)) {
137 return false;
138 }
139 return true;
140 }
141
CopyYData(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)142 static bool CopyYData(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
143 {
144 uint32_t height = src.imageHeight;
145 const uint8_t* srcY = nullptr;
146 for (uint32_t k = 0; k < height; k++) {
147 srcY = src.planes[YCOM] + k * src.strides[YCOM];
148 uint8_t* outY = dest.planes[YCOM] + k * dest.strides[YCOM];
149 bool ret = CopyLineData(outY, dest.strides[YCOM], srcY, src.strides[YCOM]);
150 if (!ret) {
151 return false;
152 }
153 }
154 if (dest.planeHeight[YCOM] > height && srcY) {
155 uint8_t* outY = dest.planes[YCOM] + height * dest.strides[YCOM];
156 bool ret = CopyLineData(outY, dest.strides[YCOM], srcY, src.strides[YCOM]);
157 if (!ret) {
158 return false;
159 }
160 }
161 return true;
162 }
163
I4xxToI420_c(const YuvPlaneInfo & src,const YuvPlaneInfo & dest,uint8_t srcXScale,uint8_t srcYScale,bool outfmtIsYU12)164 int I4xxToI420_c(const YuvPlaneInfo &src, const YuvPlaneInfo &dest,
165 uint8_t srcXScale, uint8_t srcYScale, bool outfmtIsYU12)
166 {
167 if (!VerifyParameter(src, dest, srcXScale, srcYScale, outfmtIsYU12)) {
168 return -1;
169 }
170 if (!CopyYData(src, dest)) {
171 return -1;
172 }
173 if (srcYScale == 0) {
174 return -1;
175 }
176 for (uint32_t k = 0; k < src.imageHeight; k += SAMPLE_FACTOR420) {
177 const uint8_t* srcU = src.planes[UCOM] + k / srcYScale * src.strides[UCOM];
178 const uint8_t* srcV = src.planes[VCOM] + k / srcYScale * src.strides[VCOM];
179 uint8_t* outU = nullptr;
180 uint8_t* outV = nullptr;
181 uint8_t* outVU = nullptr;
182 if (outfmtIsYU12) {
183 outU = dest.planes[UCOM] + k / SAMPLE_FACTOR420 * dest.strides[UCOM];
184 outV = dest.planes[VCOM] + k / SAMPLE_FACTOR420 * dest.strides[VCOM];
185 if (srcXScale == SAMPLE_FACTOR420 && srcYScale >= SAMPLE_FACTOR420) {
186 CopyLineData(outU, dest.strides[UCOM], srcU, src.strides[UCOM]);
187 CopyLineData(outV, dest.strides[VCOM], srcV, src.strides[VCOM]);
188 continue;
189 }
190 } else {
191 outVU = dest.planes[UVCOM] + k / SAMPLE_FACTOR420 * dest.strides[UVCOM];
192 }
193 bool canUseNextRow = false;
194 if (srcYScale < SAMPLE_FACTOR420 && k != src.planeHeight[UCOM] - 1) {
195 canUseNextRow = true;
196 }
197 for (uint32_t j = 0; j < src.imageWidth; j++) {
198 if ((j & EVEN_MASK) == 0 && outfmtIsYU12) {
199 bool canUseNextColumn = ((j != src.imageWidth - 1) && (srcXScale < SAMPLE_FACTOR420));
200 *outU++ = SampleUV(srcU, src.strides[UCOM], canUseNextRow, canUseNextColumn);
201 *outV++ = SampleUV(srcV, src.strides[VCOM], canUseNextRow, canUseNextColumn);
202 } else if ((j & EVEN_MASK) == 0) {
203 bool canUseNextColumn = ((j != src.imageWidth - 1) && (srcXScale < SAMPLE_FACTOR420));
204 *outVU++ = SampleUV(srcV, src.strides[VCOM], canUseNextRow, canUseNextColumn);
205 *outVU++ = SampleUV(srcU, src.strides[UCOM], canUseNextRow, canUseNextColumn);
206 }
207 if (((j + 1) % srcXScale) == 0) {
208 srcU++;
209 srcV++;
210 }
211 }
212 }
213 return 0;
214 }
215
I444ToI420_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)216 int I444ToI420_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
217 {
218 if (JpegDecoderYuv::GetLibyuvConverter().I444ToI420) {
219 uint32_t width = src.imageWidth;
220 uint32_t height = src.imageHeight;
221 if (!IsValidYuvData(src) || !IsValidYuvData(dest) || !IsValidSize(width, height)) {
222 return -1;
223 }
224 return JpegDecoderYuv::GetLibyuvConverter().I444ToI420(src.planes[YCOM], src.strides[YCOM], src.planes[UCOM],
225 src.strides[UCOM], src.planes[VCOM], src.strides[VCOM], dest.planes[YCOM], dest.strides[YCOM],
226 dest.planes[UCOM], dest.strides[UCOM], dest.planes[VCOM], dest.strides[VCOM], width, height);
227 } else {
228 return I4xxToI420_c(src, dest, SCALE_444_X, SCALE_444_Y, true);
229 }
230 }
231
I444ToNV21_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)232 int I444ToNV21_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
233 {
234 if (JpegDecoderYuv::GetLibyuvConverter().I444ToNV21) {
235 uint32_t width = src.imageWidth;
236 uint32_t height = src.imageHeight;
237 if (!IsValidYuvData(src) || !IsValidYuvNVData(dest) || !IsValidSize(width, height)) {
238 return -1;
239 }
240 return JpegDecoderYuv::GetLibyuvConverter().I444ToNV21(src.planes[YCOM], src.strides[YCOM], src.planes[UCOM],
241 src.strides[UCOM], src.planes[VCOM], src.strides[VCOM], dest.planes[YCOM], dest.strides[YCOM],
242 dest.planes[UVCOM], dest.strides[UVCOM], width, height);
243 } else {
244 return I4xxToI420_c(src, dest, SCALE_444_X, SCALE_444_Y, false);
245 }
246 }
247
I422ToI420_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)248 int I422ToI420_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
249 {
250 if (JpegDecoderYuv::GetLibyuvConverter().I422ToI420) {
251 uint32_t width = src.imageWidth;
252 uint32_t height = src.imageHeight;
253 if (!IsValidYuvData(src) || !IsValidYuvData(dest) || !IsValidSize(width, height)) {
254 return -1;
255 }
256 return JpegDecoderYuv::GetLibyuvConverter().I422ToI420(src.planes[YCOM], src.strides[YCOM], src.planes[UCOM],
257 src.strides[UCOM], src.planes[VCOM], src.strides[VCOM], dest.planes[YCOM], dest.strides[YCOM],
258 dest.planes[UCOM], dest.strides[UCOM], dest.planes[VCOM], dest.strides[VCOM], width, height);
259 } else {
260 return I4xxToI420_c(src, dest, SCALE_422_X, SCALE_422_Y, true);
261 }
262 }
263
I422ToNV21_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)264 int I422ToNV21_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
265 {
266 if (JpegDecoderYuv::GetLibyuvConverter().I422ToNV21) {
267 uint32_t width = src.imageWidth;
268 uint32_t height = src.imageHeight;
269 if (!IsValidYuvData(src) || !IsValidYuvNVData(dest) || !IsValidSize(width, height)) {
270 return -1;
271 }
272 return JpegDecoderYuv::GetLibyuvConverter().I422ToNV21(src.planes[YCOM], src.strides[YCOM], src.planes[UCOM],
273 src.strides[UCOM], src.planes[VCOM], src.strides[VCOM], dest.planes[YCOM], dest.strides[YCOM],
274 dest.planes[UVCOM], dest.strides[UVCOM], width, height);
275 } else {
276 return I4xxToI420_c(src, dest, SCALE_422_X, SCALE_422_Y, false);
277 }
278 }
279
I420ToI420_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)280 int I420ToI420_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
281 {
282 return I4xxToI420_c(src, dest, SCALE_420_X, SCALE_420_Y, true);
283 }
284
I420ToNV21_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)285 int I420ToNV21_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
286 {
287 if (JpegDecoderYuv::GetLibyuvConverter().I420ToNV21) {
288 uint32_t width = src.imageWidth;
289 uint32_t height = src.imageHeight;
290 if (!IsValidYuvData(src) || !IsValidYuvNVData(dest) || !IsValidSize(width, height)) {
291 return -1;
292 }
293 return JpegDecoderYuv::GetLibyuvConverter().I420ToNV21(src.planes[YCOM], src.strides[YCOM], src.planes[UCOM],
294 src.strides[UCOM], src.planes[VCOM], src.strides[VCOM], dest.planes[YCOM], dest.strides[YCOM],
295 dest.planes[UVCOM], dest.strides[UVCOM], width, height);
296 } else {
297 return I4xxToI420_c(src, dest, SCALE_420_X, SCALE_420_Y, false);
298 }
299 }
300
I440ToI420_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)301 int I440ToI420_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
302 {
303 return I4xxToI420_c(src, dest, SCALE_440_X, SCALE_440_Y, true);
304 }
305
I440ToNV21_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)306 int I440ToNV21_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
307 {
308 return I4xxToI420_c(src, dest, SCALE_440_X, SCALE_440_Y, false);
309 }
310
I411ToI420_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)311 int I411ToI420_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
312 {
313 return I4xxToI420_c(src, dest, SCALE_411_X, SCALE_411_Y, true);
314 }
315
I411ToNV21_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)316 int I411ToNV21_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
317 {
318 return I4xxToI420_c(src, dest, SCALE_411_X, SCALE_411_Y, false);
319 }
320
I400ToI420_wrapper(const YuvPlaneInfo & src,const YuvPlaneInfo & dest)321 int I400ToI420_wrapper(const YuvPlaneInfo &src, const YuvPlaneInfo &dest)
322 {
323 uint32_t width = src.imageWidth;
324 uint32_t height = src.imageHeight;
325 if (!IsValidYuvGrayData(src) || !IsValidYuvData(dest) || !IsValidSize(width, height)) {
326 return -1;
327 }
328 if (JpegDecoderYuv::GetLibyuvConverter().I400ToI420) {
329 return JpegDecoderYuv::GetLibyuvConverter().I400ToI420(src.planes[YCOM], src.strides[YCOM], dest.planes[YCOM],
330 dest.strides[YCOM], dest.planes[UCOM], dest.strides[UCOM], dest.planes[VCOM], dest.strides[VCOM],
331 width, height);
332 } else {
333 const uint8_t* srcY = nullptr;
334 for (uint32_t k = 0; k < height; k++) {
335 srcY = src.planes[YCOM] + k * src.strides[YCOM];
336 uint8_t* outY = dest.planes[YCOM] + k * dest.strides[YCOM];
337 CopyLineData(outY, dest.strides[YCOM], srcY, std::min(src.strides[YCOM], dest.strides[YCOM]));
338 }
339 if (dest.planeHeight[YCOM] > height && srcY) {
340 uint8_t* outY = dest.planes[YCOM] + height * dest.strides[YCOM];
341 CopyLineData(outY, dest.strides[YCOM], srcY, src.strides[YCOM]);
342 }
343 const uint8_t chromaValueForGray = 0x80;
344 uint32_t UVCOMSize = dest.planeWidth[UCOM] * dest.planeHeight[UCOM];
345 UVCOMSize += dest.planeWidth[VCOM] * dest.planeHeight[VCOM];
346 errno_t ret = memset_s(dest.planes[UCOM], UVCOMSize, chromaValueForGray, UVCOMSize);
347 if (ret != EOK) {
348 return -1;
349 }
350 return 0;
351 }
352 }
353
354 }
355 }