• 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, const DecodeContext &context)
261 {
262     if (width == 0 || height == 0) {
263         return;
264     }
265     info.imageSize.width = static_cast<int32_t>(width);
266     info.imageSize.height = static_cast<int32_t>(height);
267     info.yWidth = Get420OutPlaneWidth(YCOM, width);
268     info.yHeight = Get420OutPlaneHeight(YCOM, height);
269     info.uvWidth = Get420OutPlaneWidth(UCOM, width);
270     info.uvHeight = Get420OutPlaneHeight(UCOM, height);
271     info.yStride = info.yWidth;
272     info.uvStride = info.uvWidth + info.uvWidth;
273     if (context.allocatorType == OHOS::Media::AllocatorType::DMA_ALLOC) {
274         SurfaceBuffer* sbBuffer = reinterpret_cast<SurfaceBuffer *>(context.pixelsBuffer.context);
275         int32_t stride = sbBuffer->GetStride();
276         info.yStride = stride;
277         info.uvStride = stride;
278     }
279     info.yOffset = 0;
280     info.uvOffset = info.yHeight * info.yStride;
281 }
282 
InitYuvDataOutInfo(uint32_t width,uint32_t height,YUVDataInfo & info)283 void JpegDecoderYuv::InitYuvDataOutInfo(uint32_t width, uint32_t height, YUVDataInfo &info)
284 {
285     memset_s(&info, sizeof(info), 0, sizeof(info));
286     info.imageSize.width = static_cast<int32_t>(width);
287     info.imageSize.height = static_cast<int32_t>(height);
288 }
289 
InitPlaneOutInfoTo420(uint32_t width,uint32_t height,YuvPlaneInfo & info)290 void JpegDecoderYuv::InitPlaneOutInfoTo420(uint32_t width, uint32_t height, YuvPlaneInfo &info)
291 {
292     if (width == 0 || height == 0) {
293         return;
294     }
295     info.imageWidth = width;
296     info.imageHeight = height;
297     info.planeWidth[YCOM] = Get420OutPlaneWidth(YCOM, width);
298     info.strides[YCOM] = info.planeWidth[YCOM];
299     info.planeWidth[UCOM] = Get420OutPlaneWidth(UCOM, width);
300     info.strides[UCOM] = info.planeWidth[UCOM];
301     info.planeWidth[VCOM] = Get420OutPlaneWidth(VCOM, width);
302     info.strides[VCOM] = info.planeWidth[VCOM];
303     info.planeHeight[YCOM] = Get420OutPlaneHeight(YCOM, height);
304     info.planeHeight[UCOM] = Get420OutPlaneHeight(UCOM, height);
305     info.planeHeight[VCOM] = Get420OutPlaneHeight(VCOM, height);
306 }
307 
InitPlaneOutInfoTo420NV(uint32_t width,uint32_t height,YuvPlaneInfo & info)308 void JpegDecoderYuv::InitPlaneOutInfoTo420NV(uint32_t width, uint32_t height, YuvPlaneInfo &info)
309 {
310     if (width == 0 || height == 0) {
311         return;
312     }
313     info.imageWidth = width;
314     info.imageHeight = height;
315     info.planeWidth[YCOM] = Get420OutPlaneWidth(YCOM, width);
316     info.strides[YCOM] = info.planeWidth[YCOM];
317     info.planeHeight[YCOM] = Get420OutPlaneHeight(YCOM, height);
318     info.planeWidth[UVCOM] = Get420OutPlaneWidth(UCOM, width);
319     info.strides[UVCOM] = Get420OutPlaneWidth(UCOM, width) + Get420OutPlaneWidth(VCOM, width);
320     info.planeHeight[UVCOM] = Get420OutPlaneHeight(UCOM, height);
321 }
322 
IsYU12YV12Format(JpegYuvFmt fmt)323 bool JpegDecoderYuv::IsYU12YV12Format(JpegYuvFmt fmt)
324 {
325     if (fmt == JpegYuvFmt::OutFmt_YU12 ||
326         fmt == JpegYuvFmt::OutFmt_YV12) {
327         return true;
328     } else {
329         return false;
330     }
331 }
332 
DoDecode(DecodeContext & context,JpegDecoderYuvParameter & decodeParameter)333 int JpegDecoderYuv::DoDecode(DecodeContext &context, JpegDecoderYuvParameter &decodeParameter)
334 {
335     decodeParameter_ = decodeParameter;
336     uint32_t outwidth = decodeParameter.outwidth_;
337     uint32_t outheight = decodeParameter_.outheight_;
338     IMAGE_LOGD("JpegDecoderYuv DoDecode outFmt %{public}d, yuvBufferSize %{public}d, outSize (%{public}d, %{public}d)",
339         decodeParameter.outfmt_, decodeParameter_.yuvBufferSize_, outwidth, outheight);
340     JpegDecoderYuv::InitYuvDataOutInfo(outwidth, outheight, context.yuvInfo);
341     if (decodeParameter_.jpegBuffer_ == nullptr || decodeParameter_.yuvBuffer_ == nullptr) {
342         IMAGE_LOGE("JpegDecoderYuv DoDecode, null buffer");
343         return JpegYuvDecodeError_InvalidParameter;
344     }
345     if (outwidth == 0 || outheight == 0) {
346         IMAGE_LOGE("JpegDecoderYuv DoDecode, outSize zero");
347         return JpegYuvDecodeError_InvalidParameter;
348     }
349 
350     tjhandle dehandle = tjInitDecompress();
351     if (nullptr == dehandle) {
352         return JpegYuvDecodeError_DecodeFailed;
353     }
354     int ret = DoDecodeToYuvPlane(context, dehandle, outwidth, outheight);
355     tjDestroy(dehandle);
356     if (ret == JpegYuvDecodeError_Success) {
357         if (JpegDecoderYuv::IsYU12YV12Format(decodeParameter_.outfmt_)) {
358             JpegDecoderYuv::InitYuvDataOutInfoTo420(outwidth, outheight, context.yuvInfo, decodeParameter_.outfmt_);
359         } else {
360             JpegDecoderYuv::InitYuvDataOutInfoTo420NV(outwidth, outheight, context.yuvInfo, context);
361         }
362     }
363     return ret;
364 }
365 
IsOutSizeValid(uint32_t outwidth,uint32_t outheight)366 bool JpegDecoderYuv::IsOutSizeValid(uint32_t outwidth, uint32_t outheight)
367 {
368     uint32_t jpgwidth = decodeParameter_.jpgwidth_;
369     uint32_t jpgheight = decodeParameter_.jpgheight_;
370     uint32_t caledOutputWidth = outwidth;
371     uint32_t caledOutputHeight = outheight;
372     JpegCalculateOutputSize(jpgwidth, jpgheight, caledOutputWidth, caledOutputHeight);
373     if (caledOutputWidth != outwidth || caledOutputHeight != outheight) {
374         return false;
375     }
376     return true;
377 }
378 
FillJpgOutYuvInfo(YuvPlaneInfo & info,uint32_t width,uint32_t height,uint8_t * data,int samp)379 void JpegDecoderYuv::FillJpgOutYuvInfo(YuvPlaneInfo& info, uint32_t width, uint32_t height, uint8_t* data, int samp)
380 {
381     info.imageWidth = width;
382     info.imageHeight = height;
383     for (int i = 0; i < YUVCOMPONENT_MAX - 1; i++) {
384         info.planeWidth[i] = info.strides[i] = static_cast<uint32_t>(tjPlaneWidth(i, width, samp));
385         info.planeHeight[i] = static_cast<uint32_t>(tjPlaneHeight(i, height, samp));
386         if (samp == TJSAMP_GRAY && i != YCOM) {
387             break;
388         }
389     }
390     info.planes[YCOM] = data;
391     if (samp != TJSAMP_GRAY) {
392         info.planes[UCOM] = info.planes[YCOM] + info.planeWidth[YCOM] * info.planeHeight[YCOM];
393         info.planes[VCOM] = info.planes[UCOM] + info.planeWidth[UCOM] * info.planeHeight[UCOM];
394     }
395 }
396 
CanFastDecodeFrom420to420(uint32_t width,uint32_t height,uint32_t jpgYuvSizeOut,int subsamp)397 bool JpegDecoderYuv::CanFastDecodeFrom420to420(uint32_t width, uint32_t height, uint32_t jpgYuvSizeOut, int subsamp)
398 {
399     if (subsamp == TJSAMP_420 && JpegDecoderYuv::IsYU12YV12Format(decodeParameter_.outfmt_)) {
400         if (jpgYuvSizeOut == decodeParameter_.yuvBufferSize_ &&
401             Get420OutPlaneWidth(YCOM, width) == (uint32_t)tjPlaneWidth(YCOM, width, TJSAMP_420) &&
402             Get420OutPlaneHeight(YCOM, height) == (uint32_t)tjPlaneHeight(YCOM, height, TJSAMP_420)) {
403             return true;
404         }
405     }
406     return false;
407 }
408 
DecodeHeader(tjhandle dehandle,int & retSubsamp)409 int JpegDecoderYuv::DecodeHeader(tjhandle dehandle, int& retSubsamp)
410 {
411     if (nullptr == dehandle) {
412         return JpegYuvDecodeError_DecodeFailed;
413     }
414     int width = 0;
415     int height = 0;
416     int jpegSubsamp = 0;
417     int jpegColorSpace = 0;
418     int ret = tjDecompressHeader3(dehandle,
419         decodeParameter_.jpegBuffer_,
420         decodeParameter_.jpegBufferSize_, &width,
421         &height, &jpegSubsamp, &jpegColorSpace);
422     retSubsamp = jpegSubsamp;
423     decodeParameter_.jpgwidth_ = static_cast<uint32_t>(width);
424     decodeParameter_.jpgheight_ = static_cast<uint32_t>(height);
425     if (ret != 0) {
426         IMAGE_LOGE("JpegDecoderYuv tjDecompressHeader3, failed");
427         return JpegYuvDecodeError_SubSampleNotSupport;
428     }
429     if (width == 0 || height == 0) {
430         IMAGE_LOGE("JpegDecoderYuv tjDecompressHeader3, image size zero");
431         return JpegYuvDecodeError_BadImage;
432     }
433     if (!IsSupportedSubSample(jpegSubsamp)) {
434         IMAGE_LOGE("JpegDecoderYuv tjDecompressHeader3, subsample %{public}d not supported", jpegSubsamp);
435         return JpegYuvDecodeError_SubSampleNotSupport;
436     }
437     return JpegYuvDecodeError_Success;
438 }
439 
DoDecodeToYuvPlane(DecodeContext & context,tjhandle dehandle,uint32_t outw,uint32_t outh)440 int JpegDecoderYuv::DoDecodeToYuvPlane(DecodeContext &context, tjhandle dehandle, uint32_t outw, uint32_t outh)
441 {
442     int jpegSubsamp = 0;
443     int ret = DecodeHeader(dehandle, jpegSubsamp);
444     if (ret != JpegYuvDecodeError_Success) {
445         return ret;
446     }
447     if (!IsOutSizeValid(outw, outh)) {
448         IMAGE_LOGE("JpegDecoderYuv DoDecodeToYuvPlane, pre calcualted out size wrong");
449         return JpegYuvDecodeError_InvalidParameter;
450     }
451     uint32_t width = outw;
452     uint32_t height = outh;
453     uint32_t totalSizeForDecodeData = GetJpegDecompressedYuvSize(width, height, jpegSubsamp);
454     if (CanFastDecodeFrom420to420(width, height, totalSizeForDecodeData, jpegSubsamp)) {
455         return DecodeFrom420To420(context, dehandle, width, height);
456     }
457     std::unique_ptr<uint8_t[]> yuvBuffer = std::make_unique<uint8_t[]>(totalSizeForDecodeData);
458     unsigned char* data = reinterpret_cast<unsigned char*>(yuvBuffer.get());
459 
460     YuvPlaneInfo jpegOutYuvInfo = { 0 };
461     FillJpgOutYuvInfo(jpegOutYuvInfo, width, height, data, jpegSubsamp);
462     ret = tjDecompressToYUVPlanes(dehandle, decodeParameter_.jpegBuffer_, decodeParameter_.jpegBufferSize_,
463         jpegOutYuvInfo.planes, width, nullptr, height, 0);
464     if (ret != 0) {
465         IMAGE_LOGE("JpegDecoderYuv tjDecompressToYUVPlanes failed, ret %{public}d", ret);
466         return JpegYuvDecodeError_DecodeFailed;
467     }
468     if (jpegSubsamp == TJSAMP_GRAY) {
469         return ConvertFromGray(jpegOutYuvInfo);
470     }
471     ConverterPair convertFunc = { nullptr, nullptr};
472     auto iter = CONVERTER_MAP.find(jpegSubsamp);
473     if (iter != CONVERTER_MAP.end()) {
474         convertFunc = iter->second;
475     }
476     return ConvertFrom4xx(jpegOutYuvInfo, convertFunc, context);
477 }
478 
DecodeFrom420To420(DecodeContext & context,tjhandle dehandle,uint32_t width,uint32_t height)479 int JpegDecoderYuv::DecodeFrom420To420(DecodeContext &context, tjhandle dehandle, uint32_t width, uint32_t height)
480 {
481     uint32_t outSize = JpegDecoderYuv::GetJpegDecompressedYuvSize(width, height, TJSAMP_420);
482     if (outSize != decodeParameter_.yuvBufferSize_) {
483         IMAGE_LOGE("JpegDecoderYuv ConvertFrom4xx yuvBufferSize not correct");
484         return JpegYuvDecodeError_MemoryNotEnoughToSaveResult;
485     }
486 
487     unsigned char* dstPlanes[YUVCOMPONENT_MAX] = { 0 };
488     if (decodeParameter_.outfmt_ == JpegYuvFmt::OutFmt_YU12) {
489         dstPlanes[YCOM] = decodeParameter_.yuvBuffer_;
490         dstPlanes[UCOM] = dstPlanes[YCOM] + tjPlaneSizeYUV(YCOM, width, 0, height, TJSAMP_420);
491         dstPlanes[VCOM] = dstPlanes[UCOM] + tjPlaneSizeYUV(UCOM, width, 0, height, TJSAMP_420);
492     } else if (decodeParameter_.outfmt_ == JpegYuvFmt::OutFmt_YV12) {
493         dstPlanes[YCOM] = decodeParameter_.yuvBuffer_;
494         dstPlanes[VCOM] = dstPlanes[YCOM] + tjPlaneSizeYUV(YCOM, width, 0, height, TJSAMP_420);
495         dstPlanes[UCOM] = dstPlanes[VCOM] + tjPlaneSizeYUV(VCOM, width, 0, height, TJSAMP_420);
496     }
497     IMAGE_LOGD("JpegDecoderYuv DecodeFrom420ToYuv decode to 420 directly");
498     int ret = tjDecompressToYUVPlanes(dehandle,
499         decodeParameter_.jpegBuffer_,
500         decodeParameter_.jpegBufferSize_,
501         dstPlanes, width,
502         nullptr, height, 0);
503     if (ret != 0) {
504         IMAGE_LOGE("JpegDecoderYuv DecodeFrom420ToYuv tjDecompressToYUVPlanes failed, ret %{public}d", ret);
505     }
506     return ret != 0 ? JpegYuvDecodeError_DecodeFailed : JpegYuvDecodeError_Success;
507 }
508 
ValidateParameter(YuvPlaneInfo & srcPlaneInfo,ConverterPair & converter)509 bool JpegDecoderYuv::ValidateParameter(YuvPlaneInfo &srcPlaneInfo, ConverterPair &converter)
510 {
511     uint32_t width = srcPlaneInfo.imageWidth;
512     uint32_t height = srcPlaneInfo.imageHeight;
513     if (srcPlaneInfo.planes[YCOM] == nullptr || srcPlaneInfo.planes[UCOM] == nullptr ||
514             srcPlaneInfo.planes[VCOM] == nullptr) {
515         return false;
516     }
517     if (width == 0 || height == 0) {
518         return false;
519     }
520     if (converter.to420Func == nullptr || converter.toNV21Func == nullptr) {
521         return false;
522     }
523     if (srcPlaneInfo.planeWidth[YCOM] == 0 || srcPlaneInfo.planeWidth[UCOM] == 0 ||
524             srcPlaneInfo.planeWidth[VCOM] == 0) {
525         return false;
526     }
527     if (srcPlaneInfo.planeHeight[YCOM] == 0 || srcPlaneInfo.planeHeight[UCOM] == 0 ||
528             srcPlaneInfo.planeHeight[VCOM] == 0) {
529         return false;
530     }
531 
532     uint32_t outSize = JpegDecoderYuv::GetYuvOutSize(width, height);
533     if (outSize > decodeParameter_.yuvBufferSize_) {
534         IMAGE_LOGE("JpegDecoderYuv ValidateParameter yuvBufferSize not enough");
535         return false;
536     }
537 
538     return true;
539 }
540 
ConvertFrom4xx(YuvPlaneInfo & srcPlaneInfo,ConverterPair & converter,const DecodeContext & context)541 int JpegDecoderYuv::ConvertFrom4xx(YuvPlaneInfo &srcPlaneInfo, ConverterPair &converter, const DecodeContext &context)
542 {
543     if (!ValidateParameter(srcPlaneInfo, converter)) {
544         return JpegYuvDecodeError_ConvertError;
545     }
546     uint32_t width = srcPlaneInfo.imageWidth;
547     uint32_t height = srcPlaneInfo.imageHeight;
548     unsigned char* outYData = decodeParameter_.yuvBuffer_;
549     unsigned char* outUData = outYData + Get420OutPlaneSize(YCOM, width, height);
550     unsigned char* outVData = outUData + Get420OutPlaneSize(UCOM, width, height);
551     unsigned char* outUVData = outUData;
552     YuvPlaneInfo dest = { 0 };
553     int ret = JpegYuvDecodeError_ConvertError;
554     switch (decodeParameter_.outfmt_) {
555         case JpegYuvFmt::OutFmt_YU12:
556         case JpegYuvFmt::OutFmt_YV12: {
557             JpegDecoderYuv::InitPlaneOutInfoTo420(width, height, dest);
558             dest.planes[YCOM] = outYData;
559             if (decodeParameter_.outfmt_ == JpegYuvFmt::OutFmt_YU12) {
560                 dest.planes[UCOM] = outUData;
561                 dest.planes[VCOM] = outVData;
562             } else {
563                 dest.planes[UCOM] = outVData;
564                 dest.planes[VCOM] = outUData;
565             }
566             ret = converter.to420Func(srcPlaneInfo, dest);
567             break;
568         }
569         case JpegYuvFmt::OutFmt_NV12: {
570             YuvPlaneInfo srcYVU = srcPlaneInfo;
571             srcYVU.planes[UCOM] = srcPlaneInfo.planes[VCOM];
572             srcYVU.planes[VCOM] = srcPlaneInfo.planes[UCOM];
573             JpegDecoderYuv::InitPlaneOutInfoTo420NV(width, height, dest);
574             dest.planes[YCOM] = outYData;
575             dest.planes[UVCOM] = outUVData;
576             if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
577                 auto surfaceBuffer = reinterpret_cast<SurfaceBuffer *>(context.pixelsBuffer.context);
578                 dest.planes[UVCOM] = outYData + surfaceBuffer->GetStride() * height;
579                 dest.strides[YCOM] = surfaceBuffer->GetStride();
580                 dest.strides[UCOM] = surfaceBuffer->GetStride() / STRIDE_DIVISOR;
581                 dest.strides[VCOM] = surfaceBuffer->GetStride() / STRIDE_DIVISOR;
582                 dest.strides[UVCOM] = surfaceBuffer->GetStride();
583             }
584             ret = converter.toNV21Func(srcYVU, dest);
585             break;
586         }
587         case JpegYuvFmt::OutFmt_NV21: {
588             JpegDecoderYuv::InitPlaneOutInfoTo420NV(width, height, dest);
589             dest.planes[YCOM] = outYData;
590             dest.planes[UVCOM] = outUVData;
591             if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
592                 auto surfaceBuffer = reinterpret_cast<SurfaceBuffer *>(context.pixelsBuffer.context);
593                 dest.planes[UVCOM] = outYData + surfaceBuffer->GetStride() * height;
594                 dest.strides[YCOM] = surfaceBuffer->GetStride();
595                 dest.strides[UCOM] = surfaceBuffer->GetStride() / STRIDE_DIVISOR;
596                 dest.strides[VCOM] = surfaceBuffer->GetStride() / STRIDE_DIVISOR;
597                 dest.strides[UVCOM] = surfaceBuffer->GetStride();
598             }
599             ret = converter.toNV21Func(srcPlaneInfo, dest);
600             break;
601         }
602     }
603     return ret == 0 ? JpegYuvDecodeError_Success : JpegYuvDecodeError_ConvertError;
604 }
605 
ConvertFromGray(YuvPlaneInfo & srcPlaneInfo)606 int JpegDecoderYuv::ConvertFromGray(YuvPlaneInfo &srcPlaneInfo)
607 {
608     uint32_t width = srcPlaneInfo.imageWidth;
609     uint32_t height = srcPlaneInfo.imageHeight;
610     if (srcPlaneInfo.planes[YCOM] == nullptr) {
611         return JpegYuvDecodeError_ConvertError;
612     }
613     if (width == 0 || height == 0) {
614         return JpegYuvDecodeError_ConvertError;
615     }
616     if (srcPlaneInfo.planeWidth[YCOM] == 0 || srcPlaneInfo.planeHeight[YCOM] == 0) {
617         return JpegYuvDecodeError_ConvertError;
618     }
619     uint32_t outSize = JpegDecoderYuv::GetYuvOutSize(width, height);
620     if (outSize > decodeParameter_.yuvBufferSize_) {
621         IMAGE_LOGE("JpegDecoderYuv ConvertFromGray yuvBufferSize not enough %{public}d", outSize);
622         return JpegYuvDecodeError_MemoryNotEnoughToSaveResult;
623     }
624 
625     unsigned char* outYData = decodeParameter_.yuvBuffer_;
626     unsigned char* outUData = outYData + Get420OutPlaneSize(YCOM, width, height);
627     unsigned char* outVData = outUData + Get420OutPlaneSize(UCOM, width, height);
628     YuvPlaneInfo dest = { 0 };
629     JpegDecoderYuv::InitPlaneOutInfoTo420(width, height, dest);
630     dest.planes[YCOM] = outYData;
631     dest.planes[UCOM] = outUData;
632     dest.planes[VCOM] = outVData;
633     int ret = I400ToI420_wrapper(srcPlaneInfo, dest);
634     return ret == 0 ? JpegYuvDecodeError_Success : JpegYuvDecodeError_ConvertError;
635 }
636 
637 }
638 }
639 
640