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_decoder_yuv.h"
17 
18 #include <dlfcn.h>
19 #include <map>
20 #include <mutex>
21 #include <utility>
22 
23 #include "image_log.h"
24 #include "securec.h"
25 #include "jpegint.h"
26 
27 namespace OHOS {
28 namespace ImagePlugin {
29 using namespace OHOS::Media;
30 
31 const std::string YUV_LIB_PATH = "libyuv.z.so";
32 
33 void* JpegDecoderYuv::dlHandler_ = nullptr;
34 LibYuvConvertFuncs JpegDecoderYuv::libyuvFuncs_ = { nullptr };
35 
JpgYuvDeinitLibyuv()36 __attribute__((destructor)) void JpgYuvDeinitLibyuv()
37 {
38     JpegDecoderYuv::UnloadLibYuv();
39 }
40 
41 #define AVERAGE_FACTOR 2
42 
43 static const std::map<int, ConverterPair> CONVERTER_MAP = {
44     {TJSAMP_444, {&I444ToI420_wrapper, &I444ToNV21_wrapper}},
45     {TJSAMP_422, {&I422ToI420_wrapper, &I422ToNV21_wrapper}},
46     {TJSAMP_420, {&I420ToI420_wrapper, &I420ToNV21_wrapper}},
47     {TJSAMP_440, {&I440ToI420_wrapper, &I440ToNV21_wrapper}},
48     {TJSAMP_411, {&I411ToI420_wrapper, &I411ToNV21_wrapper}}
49 };
50 
JpegDecoderYuv()51 JpegDecoderYuv::JpegDecoderYuv()
52 {
53     static std::once_flag flag;
54     std::function<void()> func = []() {
55         JpegDecoderYuv::LoadLibYuv();
56     };
57     std::call_once(flag, func);
58 }
59 
LoadLibYuv()60 bool JpegDecoderYuv::LoadLibYuv()
61 {
62     dlHandler_ = dlopen(YUV_LIB_PATH.c_str(), RTLD_LAZY | RTLD_NODELETE);
63     if (dlHandler_ == nullptr) {
64         IMAGE_LOGE("JpegDecoderYuv LoadLibYuv, failed");
65         return false;
66     }
67     IMAGE_LOGI("JpegDecoderYuv LoadLibYuv, success");
68     libyuvFuncs_.I444ToI420 = (FUNC_I444ToI420)dlsym(dlHandler_, "I444ToI420");
69     libyuvFuncs_.I444ToNV21 = (FUNC_I444ToNV21)dlsym(dlHandler_, "I444ToNV21");
70     libyuvFuncs_.I422ToI420 = (FUNC_I422ToI420)dlsym(dlHandler_, "I422ToI420");
71     libyuvFuncs_.I422ToNV21 = (FUNC_I422ToNV21)dlsym(dlHandler_, "I422ToNV21");
72     libyuvFuncs_.I420ToNV21 = (FUNC_I420ToNV21)dlsym(dlHandler_, "I420ToNV21");
73     libyuvFuncs_.I400ToI420 = (FUNC_I400ToI420)dlsym(dlHandler_, "I400ToI420");
74     return true;
75 }
76 
UnloadLibYuv()77 void JpegDecoderYuv::UnloadLibYuv()
78 {
79     memset_s(&libyuvFuncs_, sizeof(libyuvFuncs_), 0, sizeof(libyuvFuncs_));
80     if (dlHandler_) {
81         dlclose(dlHandler_);
82         dlHandler_ = nullptr;
83     }
84 }
85 
IsSupportedSubSample(int jpegSubsamp)86 bool JpegDecoderYuv::IsSupportedSubSample(int jpegSubsamp)
87 {
88     bool ret = false;
89     switch (jpegSubsamp) {
90         case TJSAMP_444:
91         case TJSAMP_422:
92         case TJSAMP_420:
93         case TJSAMP_440:
94         case TJSAMP_411:
95         case TJSAMP_GRAY: {
96             ret = true;
97             break;
98         }
99         default: {
100             ret = false;
101             break;
102         }
103     }
104     return ret;
105 }
106 
GetScaledFactor(uint32_t jpgwidth,uint32_t jpgheight,uint32_t width,uint32_t height)107 tjscalingfactor JpegDecoderYuv::GetScaledFactor(uint32_t jpgwidth, uint32_t jpgheight, uint32_t width, uint32_t height)
108 {
109     tjscalingfactor factor = { 1, 1};
110     if (jpgwidth == 0 || jpgheight == 0) {
111         return factor;
112     }
113     if (width == 0 || height == 0) {
114         return factor;
115     }
116 
117     int NUMSF = 0;
118     tjscalingfactor* sf = tjGetScalingFactors(&NUMSF);
119     if (sf == nullptr || NUMSF == 0) {
120         return factor;
121     }
122     for (int i = 0; i < NUMSF; i++) {
123         uint32_t scaledw = static_cast<uint32_t>(TJSCALED(static_cast<int>(jpgwidth), sf[i]));
124         uint32_t scaledh = static_cast<uint32_t>(TJSCALED(static_cast<int>(jpgheight), sf[i]));
125         if ((scaledw <= width && scaledh <= height) || i == NUMSF - 1) {
126             factor.num = sf[i].num;
127             factor.denom = sf[i].denom;
128             break;
129         }
130     }
131     return factor;
132 }
133 
GetScaledSize(uint32_t jpgwidth,uint32_t jpgheight,int32_t & width,int32_t & height)134 bool JpegDecoderYuv::GetScaledSize(uint32_t jpgwidth, uint32_t jpgheight, int32_t &width, int32_t &height)
135 {
136     if (jpgwidth == 0 || jpgheight == 0) {
137         return false;
138     }
139     uint32_t reqWidth = static_cast<uint32_t>(width);
140     uint32_t reqHeight = static_cast<uint32_t>(height);
141     if (reqWidth == 0 || reqHeight == 0) {
142         width = static_cast<int32_t>(jpgwidth);
143         height = static_cast<int32_t>(jpgheight);
144         return true;
145     }
146     tjscalingfactor factor = JpegDecoderYuv::GetScaledFactor(jpgwidth, jpgheight, width, height);
147     width = TJSCALED(static_cast<int>(jpgwidth), factor);
148     height = TJSCALED(static_cast<int>(jpgheight), factor);
149     return true;
150 }
151 
JpegCalculateOutputSize(uint32_t jpgwidth,uint32_t jpgheight,uint32_t & width,uint32_t & height)152 void JpegDecoderYuv::JpegCalculateOutputSize(uint32_t jpgwidth, uint32_t jpgheight, uint32_t& width, uint32_t& height)
153 {
154     tjscalingfactor factor = JpegDecoderYuv::GetScaledFactor(jpgwidth, jpgheight, width, height);
155     jpeg_decompress_struct dinfo = { 0 };
156     dinfo.image_width = jpgwidth;
157     dinfo.image_height = jpgheight;
158     dinfo.global_state = DSTATE_READY;
159     dinfo.num_components = 0;
160     dinfo.scale_num = static_cast<unsigned int>(factor.num);
161     dinfo.scale_denom = static_cast<unsigned int>(factor.denom) ;
162     jpeg_calc_output_dimensions(&dinfo);
163     width = dinfo.output_width;
164     height = dinfo.output_height;
165 }
166 
Get420OutPlaneWidth(YuvComponentIndex com,int imageWidth)167 uint32_t JpegDecoderYuv::Get420OutPlaneWidth(YuvComponentIndex com, int imageWidth)
168 {
169     if (imageWidth == 0) {
170         return 0;
171     }
172     if (com == YCOM) {
173         return imageWidth;
174     } else {
175         return (imageWidth + 1) / AVERAGE_FACTOR;
176     }
177 }
178 
Get420OutPlaneHeight(YuvComponentIndex com,int imageHeight)179 uint32_t JpegDecoderYuv::Get420OutPlaneHeight(YuvComponentIndex com, int imageHeight)
180 {
181     if (imageHeight == 0) {
182         return 0;
183     }
184     if (com == YCOM) {
185         return imageHeight;
186     } else {
187         return (imageHeight + 1) / AVERAGE_FACTOR;
188     }
189 }
190 
Get420OutPlaneSize(YuvComponentIndex com,int imageWidth,int imageHeight)191 uint32_t JpegDecoderYuv::Get420OutPlaneSize(YuvComponentIndex com, int imageWidth, int imageHeight)
192 {
193     if (imageWidth == 0 || imageHeight == 0) {
194         return 0;
195     }
196     if (com == UVCOM) {
197         uint32_t size = Get420OutPlaneSize(UCOM, imageWidth, imageHeight);
198         size += Get420OutPlaneSize(VCOM, imageWidth, imageHeight);
199         return size;
200     } else {
201         return Get420OutPlaneWidth(com, imageWidth) * Get420OutPlaneHeight(com, imageHeight);
202     }
203 }
204 
GetYuvOutSize(uint32_t width,uint32_t height)205 uint32_t JpegDecoderYuv::GetYuvOutSize(uint32_t width, uint32_t height)
206 {
207     if (width == 0 || height == 0) {
208         return 0;
209     }
210     uint32_t size = Get420OutPlaneSize(YCOM, width, height);
211     size += Get420OutPlaneSize(UCOM, width, height);
212     size += Get420OutPlaneSize(VCOM, width, height);
213     return size;
214 }
215 
GetJpegDecompressedYuvSize(uint32_t width,uint32_t height,int subsample)216 uint32_t JpegDecoderYuv::GetJpegDecompressedYuvSize(uint32_t width, uint32_t height, int subsample)
217 {
218     if (width == 0 || height == 0) {
219         return 0;
220     }
221     uint32_t totalSizeForDecodeData = 0;
222     for (int i = 0; i < YUVCOMPONENT_MAX - 1; i++) {
223         if (subsample == TJSAMP_GRAY && i != YCOM) {
224             break;
225         }
226         unsigned long planesize = tjPlaneSizeYUV(i, width, 0, height, subsample);
227         if (planesize != (unsigned long)-1) {
228             totalSizeForDecodeData += planesize;
229         }
230     }
231     return totalSizeForDecodeData;
232 }
233 
InitYuvDataOutInfoTo420(uint32_t width,uint32_t height,YUVDataInfo & info,JpegYuvFmt fmt)234 void JpegDecoderYuv::InitYuvDataOutInfoTo420(uint32_t width, uint32_t height, YUVDataInfo &info, JpegYuvFmt fmt)
235 {
236     if (width == 0 || height == 0) {
237         return;
238     }
239     info.imageSize.width = static_cast<int32_t>(width);
240     info.imageSize.height = static_cast<int32_t>(height);
241     info.yWidth = Get420OutPlaneWidth(YCOM, width);
242     info.yHeight = Get420OutPlaneHeight(YCOM, height);
243     info.uvWidth = Get420OutPlaneWidth(UCOM, width);
244     info.uvHeight = Get420OutPlaneHeight(UCOM, height);
245     info.yStride = info.yWidth;
246     info.uStride = info.uvWidth;
247     info.vStride = info.uvWidth;
248     info.yOffset = 0;
249     if (fmt == JpegYuvFmt::OutFmt_YU12) {
250         info.uOffset = info.yHeight * info.yStride;
251         info.vOffset = info.uOffset + info.uvHeight * info.uStride;
252     } else {
253         info.vOffset = info.yHeight * info.yStride;
254         info.uOffset = info.vOffset + info.uvHeight * info.vStride;
255     }
256 }
257 
InitYuvDataOutInfoTo420NV(uint32_t width,uint32_t height,YUVDataInfo & info)258 void JpegDecoderYuv::InitYuvDataOutInfoTo420NV(uint32_t width, uint32_t height, YUVDataInfo &info)
259 {
260     if (width == 0 || height == 0) {
261         return;
262     }
263     info.imageSize.width = static_cast<int32_t>(width);
264     info.imageSize.height = static_cast<int32_t>(height);
265     info.yWidth = Get420OutPlaneWidth(YCOM, width);
266     info.yHeight = Get420OutPlaneHeight(YCOM, height);
267     info.uvWidth = Get420OutPlaneWidth(UCOM, width);
268     info.uvHeight = Get420OutPlaneHeight(UCOM, height);
269     info.yStride = info.yWidth;
270     info.uvStride = info.uvWidth + info.uvWidth;
271     info.yOffset = 0;
272     info.uvOffset = info.yHeight * info.yStride;
273 }
274 
InitYuvDataOutInfo(uint32_t width,uint32_t height,YUVDataInfo & info)275 void JpegDecoderYuv::InitYuvDataOutInfo(uint32_t width, uint32_t height, YUVDataInfo &info)
276 {
277     memset_s(&info, sizeof(info), 0, sizeof(info));
278     info.imageSize.width = static_cast<int32_t>(width);
279     info.imageSize.height = static_cast<int32_t>(height);
280 }
281 
InitPlaneOutInfoTo420(uint32_t width,uint32_t height,YuvPlaneInfo & info)282 void JpegDecoderYuv::InitPlaneOutInfoTo420(uint32_t width, uint32_t height, YuvPlaneInfo &info)
283 {
284     if (width == 0 || height == 0) {
285         return;
286     }
287     info.imageWidth = width;
288     info.imageHeight = height;
289     info.planeWidth[YCOM] = Get420OutPlaneWidth(YCOM, width);
290     info.strides[YCOM] = info.planeWidth[YCOM];
291     info.planeWidth[UCOM] = Get420OutPlaneWidth(UCOM, width);
292     info.strides[UCOM] = info.planeWidth[UCOM];
293     info.planeWidth[VCOM] = Get420OutPlaneWidth(VCOM, width);
294     info.strides[VCOM] = info.planeWidth[VCOM];
295     info.planeHeight[YCOM] = Get420OutPlaneHeight(YCOM, height);
296     info.planeHeight[UCOM] = Get420OutPlaneHeight(UCOM, height);
297     info.planeHeight[VCOM] = Get420OutPlaneHeight(VCOM, height);
298 }
299 
InitPlaneOutInfoTo420NV(uint32_t width,uint32_t height,YuvPlaneInfo & info)300 void JpegDecoderYuv::InitPlaneOutInfoTo420NV(uint32_t width, uint32_t height, YuvPlaneInfo &info)
301 {
302     if (width == 0 || height == 0) {
303         return;
304     }
305     info.imageWidth = width;
306     info.imageHeight = height;
307     info.planeWidth[YCOM] = Get420OutPlaneWidth(YCOM, width);
308     info.strides[YCOM] = info.planeWidth[YCOM];
309     info.planeHeight[YCOM] = Get420OutPlaneHeight(YCOM, height);
310     info.planeWidth[UVCOM] = Get420OutPlaneWidth(UCOM, width);
311     info.strides[UVCOM] = Get420OutPlaneWidth(UCOM, width) + Get420OutPlaneWidth(VCOM, width);
312     info.planeHeight[UVCOM] = Get420OutPlaneHeight(UCOM, height);
313 }
314 
IsYU12YV12Format(JpegYuvFmt fmt)315 bool JpegDecoderYuv::IsYU12YV12Format(JpegYuvFmt fmt)
316 {
317     if (fmt == JpegYuvFmt::OutFmt_YU12 ||
318         fmt == JpegYuvFmt::OutFmt_YV12) {
319         return true;
320     } else {
321         return false;
322     }
323 }
324 
DoDecode(DecodeContext & context,JpegDecoderYuvParameter & decodeParameter)325 int JpegDecoderYuv::DoDecode(DecodeContext &context, JpegDecoderYuvParameter &decodeParameter)
326 {
327     decodeParameter_ = decodeParameter;
328     uint32_t outwidth = decodeParameter.outwidth_;
329     uint32_t outheight = decodeParameter_.outheight_;
330     IMAGE_LOGD("JpegDecoderYuv DoDecode outFmt %{public}d, yuvBufferSize %{public}d, outSize (%{public}d, %{public}d)",
331         decodeParameter.outfmt_, decodeParameter_.yuvBufferSize_, outwidth, outheight);
332     JpegDecoderYuv::InitYuvDataOutInfo(outwidth, outheight, context.yuvInfo);
333     if (decodeParameter_.jpegBuffer_ == nullptr || decodeParameter_.yuvBuffer_ == nullptr) {
334         IMAGE_LOGE("JpegDecoderYuv DoDecode, null buffer");
335         return JpegYuvDecodeError_InvalidParameter;
336     }
337     if (outwidth == 0 || outheight == 0) {
338         IMAGE_LOGE("JpegDecoderYuv DoDecode, outSize zero");
339         return JpegYuvDecodeError_InvalidParameter;
340     }
341 
342     tjhandle dehandle = tjInitDecompress();
343     if (nullptr == dehandle) {
344         return JpegYuvDecodeError_DecodeFailed;
345     }
346     int ret = DoDecodeToYuvPlane(context, dehandle, outwidth, outheight);
347     tjDestroy(dehandle);
348     if (ret == JpegYuvDecodeError_Success) {
349         if (JpegDecoderYuv::IsYU12YV12Format(decodeParameter_.outfmt_)) {
350             JpegDecoderYuv::InitYuvDataOutInfoTo420(outwidth, outheight, context.yuvInfo, decodeParameter_.outfmt_);
351         } else {
352             JpegDecoderYuv::InitYuvDataOutInfoTo420NV(outwidth, outheight, context.yuvInfo);
353         }
354     }
355     return ret;
356 }
357 
IsOutSizeValid(uint32_t outwidth,uint32_t outheight)358 bool JpegDecoderYuv::IsOutSizeValid(uint32_t outwidth, uint32_t outheight)
359 {
360     uint32_t jpgwidth = decodeParameter_.jpgwidth_;
361     uint32_t jpgheight = decodeParameter_.jpgheight_;
362     uint32_t caledOutputWidth = outwidth;
363     uint32_t caledOutputHeight = outheight;
364     JpegCalculateOutputSize(jpgwidth, jpgheight, caledOutputWidth, caledOutputHeight);
365     if (caledOutputWidth != outwidth || caledOutputHeight != outheight) {
366         return false;
367     }
368     return true;
369 }
370 
FillJpgOutYuvInfo(YuvPlaneInfo & info,uint32_t width,uint32_t height,uint8_t * data,int samp)371 void JpegDecoderYuv::FillJpgOutYuvInfo(YuvPlaneInfo& info, uint32_t width, uint32_t height, uint8_t* data, int samp)
372 {
373     info.imageWidth = width;
374     info.imageHeight = height;
375     for (int i = 0; i < YUVCOMPONENT_MAX - 1; i++) {
376         info.planeWidth[i] = info.strides[i] = static_cast<uint32_t>(tjPlaneWidth(i, width, samp));
377         info.planeHeight[i] = static_cast<uint32_t>(tjPlaneHeight(i, height, samp));
378         if (samp == TJSAMP_GRAY && i != YCOM) {
379             break;
380         }
381     }
382     info.planes[YCOM] = data;
383     if (samp != TJSAMP_GRAY) {
384         info.planes[UCOM] = info.planes[YCOM] + info.planeWidth[YCOM] * info.planeHeight[YCOM];
385         info.planes[VCOM] = info.planes[UCOM] + info.planeWidth[UCOM] * info.planeHeight[UCOM];
386     }
387 }
388 
CanFastDecodeFrom420to420(uint32_t width,uint32_t height,uint32_t jpgYuvSizeOut,int subsamp)389 bool JpegDecoderYuv::CanFastDecodeFrom420to420(uint32_t width, uint32_t height, uint32_t jpgYuvSizeOut, int subsamp)
390 {
391     if (subsamp == TJSAMP_420 && JpegDecoderYuv::IsYU12YV12Format(decodeParameter_.outfmt_)) {
392         if (jpgYuvSizeOut == decodeParameter_.yuvBufferSize_ &&
393             Get420OutPlaneWidth(YCOM, width) == (uint32_t)tjPlaneWidth(YCOM, width, TJSAMP_420) &&
394             Get420OutPlaneHeight(YCOM, height) == (uint32_t)tjPlaneHeight(YCOM, height, TJSAMP_420)) {
395             return true;
396         }
397     }
398     return false;
399 }
400 
DecodeHeader(tjhandle dehandle,int & retSubsamp)401 int JpegDecoderYuv::DecodeHeader(tjhandle dehandle, int& retSubsamp)
402 {
403     if (nullptr == dehandle) {
404         return JpegYuvDecodeError_DecodeFailed;
405     }
406     int width = 0;
407     int height = 0;
408     int jpegSubsamp = 0;
409     int jpegColorSpace = 0;
410     int ret = tjDecompressHeader3(dehandle,
411         decodeParameter_.jpegBuffer_,
412         decodeParameter_.jpegBufferSize_, &width,
413         &height, &jpegSubsamp, &jpegColorSpace);
414     retSubsamp = jpegSubsamp;
415     decodeParameter_.jpgwidth_ = static_cast<uint32_t>(width);
416     decodeParameter_.jpgheight_ = static_cast<uint32_t>(height);
417     if (ret != 0) {
418         IMAGE_LOGE("JpegDecoderYuv tjDecompressHeader3, failed");
419         return JpegYuvDecodeError_SubSampleNotSupport;
420     }
421     if (width == 0 || height == 0) {
422         IMAGE_LOGE("JpegDecoderYuv tjDecompressHeader3, image size zero");
423         return JpegYuvDecodeError_BadImage;
424     }
425     if (!IsSupportedSubSample(jpegSubsamp)) {
426         IMAGE_LOGE("JpegDecoderYuv tjDecompressHeader3, subsample %{public}d not supported", jpegSubsamp);
427         return JpegYuvDecodeError_SubSampleNotSupport;
428     }
429     return JpegYuvDecodeError_Success;
430 }
431 
DoDecodeToYuvPlane(DecodeContext & context,tjhandle dehandle,uint32_t outw,uint32_t outh)432 int JpegDecoderYuv::DoDecodeToYuvPlane(DecodeContext &context, tjhandle dehandle, uint32_t outw, uint32_t outh)
433 {
434     int jpegSubsamp = 0;
435     int ret = DecodeHeader(dehandle, jpegSubsamp);
436     if (ret != JpegYuvDecodeError_Success) {
437         return ret;
438     }
439     if (!IsOutSizeValid(outw, outh)) {
440         IMAGE_LOGE("JpegDecoderYuv DoDecodeToYuvPlane, pre calcualted out size wrong");
441         return JpegYuvDecodeError_InvalidParameter;
442     }
443     uint32_t width = outw;
444     uint32_t height = outh;
445     uint32_t totalSizeForDecodeData = GetJpegDecompressedYuvSize(width, height, jpegSubsamp);
446     if (CanFastDecodeFrom420to420(width, height, totalSizeForDecodeData, jpegSubsamp)) {
447         return DecodeFrom420To420(context, dehandle, width, height);
448     }
449     std::unique_ptr<uint8_t[]> yuvBuffer = std::make_unique<uint8_t[]>(totalSizeForDecodeData);
450     unsigned char* data = reinterpret_cast<unsigned char*>(yuvBuffer.get());
451 
452     YuvPlaneInfo jpegOutYuvInfo = { 0 };
453     FillJpgOutYuvInfo(jpegOutYuvInfo, width, height, data, jpegSubsamp);
454     ret = tjDecompressToYUVPlanes(dehandle, decodeParameter_.jpegBuffer_, decodeParameter_.jpegBufferSize_,
455         jpegOutYuvInfo.planes, width, nullptr, height, 0);
456     if (ret != 0) {
457         IMAGE_LOGE("JpegDecoderYuv tjDecompressToYUVPlanes failed, ret %{public}d", ret);
458         return JpegYuvDecodeError_DecodeFailed;
459     }
460     if (jpegSubsamp == TJSAMP_GRAY) {
461         return ConvertFromGray(jpegOutYuvInfo);
462     }
463     ConverterPair convertFunc = { nullptr, nullptr};
464     auto iter = CONVERTER_MAP.find(jpegSubsamp);
465     if (iter != CONVERTER_MAP.end()) {
466         convertFunc = iter->second;
467     }
468     return ConvertFrom4xx(jpegOutYuvInfo, convertFunc);
469 }
470 
DecodeFrom420To420(DecodeContext & context,tjhandle dehandle,uint32_t width,uint32_t height)471 int JpegDecoderYuv::DecodeFrom420To420(DecodeContext &context, tjhandle dehandle, uint32_t width, uint32_t height)
472 {
473     uint32_t outSize = JpegDecoderYuv::GetJpegDecompressedYuvSize(width, height, TJSAMP_420);
474     if (outSize != decodeParameter_.yuvBufferSize_) {
475         IMAGE_LOGE("JpegDecoderYuv ConvertFrom4xx yuvBufferSize not correct");
476         return JpegYuvDecodeError_MemoryNotEnoughToSaveResult;
477     }
478 
479     unsigned char* dstPlanes[YUVCOMPONENT_MAX] = { 0 };
480     if (decodeParameter_.outfmt_ == JpegYuvFmt::OutFmt_YU12) {
481         dstPlanes[YCOM] = decodeParameter_.yuvBuffer_;
482         dstPlanes[UCOM] = dstPlanes[YCOM] + tjPlaneSizeYUV(YCOM, width, 0, height, TJSAMP_420);
483         dstPlanes[VCOM] = dstPlanes[UCOM] + tjPlaneSizeYUV(UCOM, width, 0, height, TJSAMP_420);
484     } else if (decodeParameter_.outfmt_ == JpegYuvFmt::OutFmt_YV12) {
485         dstPlanes[YCOM] = decodeParameter_.yuvBuffer_;
486         dstPlanes[VCOM] = dstPlanes[YCOM] + tjPlaneSizeYUV(YCOM, width, 0, height, TJSAMP_420);
487         dstPlanes[UCOM] = dstPlanes[VCOM] + tjPlaneSizeYUV(VCOM, width, 0, height, TJSAMP_420);
488     }
489     IMAGE_LOGD("JpegDecoderYuv DecodeFrom420ToYuv decode to 420 directly");
490     int ret = tjDecompressToYUVPlanes(dehandle,
491         decodeParameter_.jpegBuffer_,
492         decodeParameter_.jpegBufferSize_,
493         dstPlanes, width,
494         nullptr, height, 0);
495     if (ret != 0) {
496         IMAGE_LOGE("JpegDecoderYuv DecodeFrom420ToYuv tjDecompressToYUVPlanes failed, ret %{public}d", ret);
497     }
498     return ret != 0 ? JpegYuvDecodeError_DecodeFailed : JpegYuvDecodeError_Success;
499 }
500 
ValidateParameter(YuvPlaneInfo & srcPlaneInfo,ConverterPair & converter)501 bool JpegDecoderYuv::ValidateParameter(YuvPlaneInfo &srcPlaneInfo, ConverterPair &converter)
502 {
503     uint32_t width = srcPlaneInfo.imageWidth;
504     uint32_t height = srcPlaneInfo.imageHeight;
505     if (srcPlaneInfo.planes[YCOM] == nullptr || srcPlaneInfo.planes[UCOM] == nullptr ||
506             srcPlaneInfo.planes[VCOM] == nullptr) {
507         return false;
508     }
509     if (width == 0 || height == 0) {
510         return false;
511     }
512     if (converter.to420Func == nullptr || converter.toNV21Func == nullptr) {
513         return false;
514     }
515     if (srcPlaneInfo.planeWidth[YCOM] == 0 || srcPlaneInfo.planeWidth[UCOM] == 0 ||
516             srcPlaneInfo.planeWidth[VCOM] == 0) {
517         return false;
518     }
519     if (srcPlaneInfo.planeHeight[YCOM] == 0 || srcPlaneInfo.planeHeight[UCOM] == 0 ||
520             srcPlaneInfo.planeHeight[VCOM] == 0) {
521         return false;
522     }
523 
524     uint32_t outSize = JpegDecoderYuv::GetYuvOutSize(width, height);
525     if (outSize > decodeParameter_.yuvBufferSize_) {
526         IMAGE_LOGE("JpegDecoderYuv ValidateParameter yuvBufferSize not enough");
527         return false;
528     }
529 
530     return true;
531 }
532 
ConvertFrom4xx(YuvPlaneInfo & srcPlaneInfo,ConverterPair & converter)533 int JpegDecoderYuv::ConvertFrom4xx(YuvPlaneInfo &srcPlaneInfo, ConverterPair &converter)
534 {
535     if (!ValidateParameter(srcPlaneInfo, converter)) {
536         return JpegYuvDecodeError_ConvertError;
537     }
538     uint32_t width = srcPlaneInfo.imageWidth;
539     uint32_t height = srcPlaneInfo.imageHeight;
540     unsigned char* outYData = decodeParameter_.yuvBuffer_;
541     unsigned char* outUData = outYData + Get420OutPlaneSize(YCOM, width, height);
542     unsigned char* outVData = outUData + Get420OutPlaneSize(UCOM, width, height);
543     unsigned char* outUVData = outUData;
544     YuvPlaneInfo dest = { 0 };
545     int ret = JpegYuvDecodeError_ConvertError;
546     switch (decodeParameter_.outfmt_) {
547         case JpegYuvFmt::OutFmt_YU12:
548         case JpegYuvFmt::OutFmt_YV12: {
549             JpegDecoderYuv::InitPlaneOutInfoTo420(width, height, dest);
550             dest.planes[YCOM] = outYData;
551             if (decodeParameter_.outfmt_ == JpegYuvFmt::OutFmt_YU12) {
552                 dest.planes[UCOM] = outUData;
553                 dest.planes[VCOM] = outVData;
554             } else {
555                 dest.planes[UCOM] = outVData;
556                 dest.planes[VCOM] = outUData;
557             }
558             ret = converter.to420Func(srcPlaneInfo, dest);
559             break;
560         }
561         case JpegYuvFmt::OutFmt_NV12: {
562             YuvPlaneInfo srcYVU = srcPlaneInfo;
563             srcYVU.planes[UCOM] = srcPlaneInfo.planes[VCOM];
564             srcYVU.planes[VCOM] = srcPlaneInfo.planes[UCOM];
565             JpegDecoderYuv::InitPlaneOutInfoTo420NV(width, height, dest);
566             dest.planes[YCOM] = outYData;
567             dest.planes[UVCOM] = outUVData;
568             ret = converter.toNV21Func(srcYVU, dest);
569             break;
570         }
571         case JpegYuvFmt::OutFmt_NV21: {
572             JpegDecoderYuv::InitPlaneOutInfoTo420NV(width, height, dest);
573             dest.planes[YCOM] = outYData;
574             dest.planes[UVCOM] = outUVData;
575             ret = converter.toNV21Func(srcPlaneInfo, dest);
576             break;
577         }
578     }
579     return ret == 0 ? JpegYuvDecodeError_Success : JpegYuvDecodeError_ConvertError;
580 }
581 
ConvertFromGray(YuvPlaneInfo & srcPlaneInfo)582 int JpegDecoderYuv::ConvertFromGray(YuvPlaneInfo &srcPlaneInfo)
583 {
584     uint32_t width = srcPlaneInfo.imageWidth;
585     uint32_t height = srcPlaneInfo.imageHeight;
586     if (srcPlaneInfo.planes[YCOM] == nullptr) {
587         return JpegYuvDecodeError_ConvertError;
588     }
589     if (width == 0 || height == 0) {
590         return JpegYuvDecodeError_ConvertError;
591     }
592     if (srcPlaneInfo.planeWidth[YCOM] == 0 || srcPlaneInfo.planeHeight[YCOM] == 0) {
593         return JpegYuvDecodeError_ConvertError;
594     }
595     uint32_t outSize = JpegDecoderYuv::GetYuvOutSize(width, height);
596     if (outSize > decodeParameter_.yuvBufferSize_) {
597         IMAGE_LOGE("JpegDecoderYuv ConvertFromGray yuvBufferSize not enough %{public}d", outSize);
598         return JpegYuvDecodeError_MemoryNotEnoughToSaveResult;
599     }
600 
601     unsigned char* outYData = decodeParameter_.yuvBuffer_;
602     unsigned char* outUData = outYData + Get420OutPlaneSize(YCOM, width, height);
603     unsigned char* outVData = outUData + Get420OutPlaneSize(UCOM, width, height);
604     YuvPlaneInfo dest = { 0 };
605     JpegDecoderYuv::InitPlaneOutInfoTo420(width, height, dest);
606     dest.planes[YCOM] = outYData;
607     dest.planes[UCOM] = outUData;
608     dest.planes[VCOM] = outVData;
609     int ret = I400ToI420_wrapper(srcPlaneInfo, dest);
610     return ret == 0 ? JpegYuvDecodeError_Success : JpegYuvDecodeError_ConvertError;
611 }
612 
613 }
614 }
615 
616