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