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