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 }