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