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