1 /*
2 * Copyright (C) 2021 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 "post_proc.h"
17
18 #include <unistd.h>
19
20 #include "basic_transformer.h"
21 #include "image_log.h"
22 #include "image_system_properties.h"
23 #include "image_trace.h"
24 #include "image_utils.h"
25 #include "media_errors.h"
26 #include "memory_manager.h"
27 #include "pixel_convert_adapter.h"
28 #ifndef _WIN32
29 #include "securec.h"
30 #else
31 #include "memory.h"
32 #endif
33
34 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
35 #include <sys/mman.h>
36 #include "ashmem.h"
37 #include "surface_buffer.h"
38 #include "vpe_utils.h"
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 #include "libswscale/swscale.h"
44 #ifdef __cplusplus
45 };
46 #endif
47 #endif
48
49 #undef LOG_DOMAIN
50 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
51
52 #undef LOG_TAG
53 #define LOG_TAG "PostProc"
54
55 namespace OHOS {
56 namespace Media {
57 using namespace std;
58 constexpr uint32_t NEED_NEXT = 1;
59 constexpr float EPSILON = 1e-6;
60 constexpr uint8_t HALF = 2;
61 constexpr float HALF_F = 2;
62 constexpr int FFMPEG_NUM = 8;
63 constexpr int SLR_CACHE_CAPACITY = 256;
64
65 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
66 static const map<PixelFormat, AVPixelFormat> PIXEL_FORMAT_MAP = {
67 { PixelFormat::ALPHA_8, AVPixelFormat::AV_PIX_FMT_GRAY8 },
68 { PixelFormat::RGB_565, AVPixelFormat::AV_PIX_FMT_RGB565BE },
69 { PixelFormat::RGB_888, AVPixelFormat::AV_PIX_FMT_RGB24 },
70 { PixelFormat::RGBA_8888, AVPixelFormat::AV_PIX_FMT_RGBA },
71 { PixelFormat::ARGB_8888, AVPixelFormat::AV_PIX_FMT_ARGB },
72 { PixelFormat::BGRA_8888, AVPixelFormat::AV_PIX_FMT_BGRA },
73 { PixelFormat::RGBA_F16, AVPixelFormat::AV_PIX_FMT_RGBA64BE },
74 };
75 #endif
76
DecodePostProc(const DecodeOptions & opts,PixelMap & pixelMap,FinalOutputStep finalOutputStep)77 uint32_t PostProc::DecodePostProc(const DecodeOptions &opts, PixelMap &pixelMap, FinalOutputStep finalOutputStep)
78 {
79 ImageInfo srcImageInfo;
80 pixelMap.GetImageInfo(srcImageInfo);
81 ImageInfo dstImageInfo;
82 GetDstImageInfo(opts, pixelMap, srcImageInfo, dstImageInfo);
83 uint32_t errorCode = ConvertProc(opts.CropRect, dstImageInfo, pixelMap, srcImageInfo);
84 if (errorCode != SUCCESS) {
85 IMAGE_LOGE("[PostProc]crop pixel map failed, errcode:%{public}u", errorCode);
86 return errorCode;
87 }
88 decodeOpts_.allocatorType = opts.allocatorType;
89 bool isNeedRotate = !ImageUtils::FloatCompareZero(opts.rotateDegrees);
90 if (isNeedRotate) {
91 if (!RotatePixelMap(opts.rotateDegrees, pixelMap)) {
92 IMAGE_LOGE("[PostProc]rotate:transform pixel map failed");
93 return ERR_IMAGE_TRANSFORM;
94 }
95 }
96 decodeOpts_.allocatorType = opts.allocatorType;
97 if (opts.desiredSize.height > 0 && opts.desiredSize.width > 0) {
98 if (!ScalePixelMap(opts.desiredSize, pixelMap)) {
99 IMAGE_LOGE("[PostProc]scale:transform pixel map failed");
100 return ERR_IMAGE_TRANSFORM;
101 }
102 } else {
103 ImageInfo info;
104 pixelMap.GetImageInfo(info);
105 if ((finalOutputStep == FinalOutputStep::DENSITY_CHANGE) && (info.baseDensity != 0)) {
106 int targetWidth = (pixelMap.GetWidth() * opts.fitDensity + (info.baseDensity >> 1)) / info.baseDensity;
107 int targetHeight = (pixelMap.GetHeight() * opts.fitDensity + (info.baseDensity >> 1)) / info.baseDensity;
108 Size size;
109 size.height = targetHeight;
110 size.width = targetWidth;
111 if (!ScalePixelMap(size, pixelMap)) {
112 IMAGE_LOGE("[PostProc]density scale:transform pixel map failed");
113 return ERR_IMAGE_TRANSFORM;
114 }
115 info.baseDensity = opts.fitDensity;
116 pixelMap.SetImageInfo(info, true);
117 }
118 }
119 return SUCCESS;
120 }
121
GetDstImageInfo(const DecodeOptions & opts,PixelMap & pixelMap,ImageInfo srcImageInfo,ImageInfo & dstImageInfo)122 void PostProc::GetDstImageInfo(const DecodeOptions &opts, PixelMap &pixelMap,
123 ImageInfo srcImageInfo, ImageInfo &dstImageInfo)
124 {
125 dstImageInfo.size = opts.desiredSize;
126 dstImageInfo.pixelFormat = opts.desiredPixelFormat;
127 dstImageInfo.baseDensity = srcImageInfo.baseDensity;
128 decodeOpts_ = opts;
129 if (opts.desiredPixelFormat == PixelFormat::UNKNOWN) {
130 if (opts.preference == MemoryUsagePreference::LOW_RAM &&
131 srcImageInfo.alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
132 dstImageInfo.pixelFormat = PixelFormat::RGB_565;
133 } else {
134 dstImageInfo.pixelFormat = PixelFormat::RGBA_8888;
135 }
136 }
137 // decode use, this value may be changed by real pixelFormat
138 if (pixelMap.GetAlphaType() == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) {
139 dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
140 } else {
141 dstImageInfo.alphaType = pixelMap.GetAlphaType();
142 }
143 }
144
CenterScale(const Size & size,PixelMap & pixelMap)145 bool PostProc::CenterScale(const Size &size, PixelMap &pixelMap)
146 {
147 int32_t srcWidth = pixelMap.GetWidth();
148 int32_t srcHeight = pixelMap.GetHeight();
149 int32_t targetWidth = size.width;
150 int32_t targetHeight = size.height;
151 if (targetWidth <= 0 || targetHeight <= 0 || srcWidth <= 0 || srcHeight <= 0) {
152 IMAGE_LOGE("[PostProc]params invalid, targetWidth:%{public}d, targetHeight:%{public}d, "
153 "srcWidth:%{public}d, srcHeight:%{public}d", targetWidth, targetHeight, srcWidth, srcHeight);
154 return false;
155 }
156 float widthScale = static_cast<float>(targetWidth) / static_cast<float>(srcWidth);
157 float heightScale = static_cast<float>(targetHeight) / static_cast<float>(srcHeight);
158 float scale = max(widthScale, heightScale);
159 if (pixelMap.IsAstc() && scale > 0) {
160 TransformData transformData;
161 pixelMap.GetTransformData(transformData);
162 transformData.scaleX *= scale;
163 transformData.scaleY *= scale;
164 transformData.cropLeft = (srcWidth - targetWidth / scale) / HALF_F;
165 transformData.cropTop = (srcHeight - targetHeight / scale) / HALF_F;
166 transformData.cropWidth = targetWidth / scale;
167 transformData.cropHeight = targetHeight / scale;
168 pixelMap.SetTransformData(transformData);
169 ImageInfo imageInfo;
170 pixelMap.GetImageInfo(imageInfo);
171 imageInfo.size.width = targetWidth;
172 imageInfo.size.height = targetHeight;
173 pixelMap.SetImageInfo(imageInfo, true);
174 return true;
175 }
176 if (!ScalePixelMap(scale, scale, pixelMap)) {
177 IMAGE_LOGE("[PostProc]center scale pixelmap %{public}f fail", scale);
178 return false;
179 }
180 srcWidth = pixelMap.GetWidth();
181 srcHeight = pixelMap.GetHeight();
182 if (srcWidth == targetWidth && srcHeight == targetHeight) {
183 return true;
184 }
185 if (srcWidth < targetWidth || srcHeight < targetHeight) {
186 IMAGE_LOGE("[PostProc]src size [%{public}d, %{public}d] must less than dst size [%{public}d,"
187 "%{public}d]", srcWidth, srcHeight, targetWidth, targetHeight);
188 return false;
189 }
190
191 return CenterDisplay(pixelMap, srcWidth, srcHeight, targetWidth, targetHeight);
192 }
193
CopyPixels(PixelMap & pixelMap,uint8_t * dstPixels,const Size & dstSize,const int32_t srcWidth,const int32_t srcHeight,int32_t srcRowStride,int32_t targetRowStride)194 bool PostProc::CopyPixels(PixelMap& pixelMap, uint8_t* dstPixels, const Size& dstSize,
195 const int32_t srcWidth, const int32_t srcHeight,
196 int32_t srcRowStride, int32_t targetRowStride)
197 {
198 int32_t targetWidth = dstSize.width;
199 int32_t targetHeight = dstSize.height;
200 int32_t left = max(0, srcWidth - targetWidth) / HALF;
201 int32_t top = max(0, srcHeight - targetHeight) / HALF;
202 int32_t pixelBytes = pixelMap.GetPixelBytes();
203 uint8_t *dstStartPixel = nullptr;
204 uint8_t *srcStartPixel = nullptr;
205 int32_t targetRowBytes = targetWidth * pixelBytes;
206 if (targetRowStride <= 0) {
207 targetRowStride = targetRowBytes;
208 }
209 int32_t srcRowBytes = srcWidth * pixelBytes;
210 if (srcRowStride <= 0) {
211 srcRowStride = srcRowBytes;
212 }
213 uint8_t *srcPixels = const_cast<uint8_t *>(pixelMap.GetPixels()) + top * srcRowStride + left * pixelBytes;
214 if (std::min(srcWidth, targetWidth) != 0 &&
215 ImageUtils::CheckMulOverflow(std::min(srcWidth, targetWidth), pixelBytes)) {
216 IMAGE_LOGE("[PostProc]invalid params, srcWidth:%{public}d, targetWidth:%{public}d, pixelBytes:%{public}d",
217 srcWidth, targetWidth, pixelBytes);
218 return false;
219 }
220 uint32_t copyRowBytes = static_cast<uint32_t>(std::min(srcWidth, targetWidth) * pixelBytes);
221 for (int32_t scanLine = 0; scanLine < std::min(srcHeight, targetHeight); scanLine++) {
222 dstStartPixel = dstPixels + scanLine * targetRowStride;
223 srcStartPixel = srcPixels + scanLine * srcRowStride;
224 errno_t errRet = memcpy_s(dstStartPixel, static_cast<size_t>(targetRowBytes), srcStartPixel, copyRowBytes);
225 if (errRet != EOK) {
226 IMAGE_LOGE("[PostProc]memcpy scanline %{public}d fail, errorCode = %{public}d", scanLine, errRet);
227 return false;
228 }
229 }
230 return true;
231 }
232
CenterDisplay(PixelMap & pixelMap,int32_t srcWidth,int32_t srcHeight,int32_t targetWidth,int32_t targetHeight)233 bool PostProc::CenterDisplay(PixelMap &pixelMap, int32_t srcWidth, int32_t srcHeight, int32_t targetWidth,
234 int32_t targetHeight)
235 {
236 ImageInfo dstImageInfo;
237 pixelMap.GetImageInfo(dstImageInfo);
238 int32_t srcRowStride = pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC ? pixelMap.GetRowStride() : 0;
239 dstImageInfo.size.width = targetWidth;
240 dstImageInfo.size.height = targetHeight;
241 if (pixelMap.SetImageInfo(dstImageInfo, true) != SUCCESS) {
242 IMAGE_LOGE("update ImageInfo failed");
243 return false;
244 }
245 int32_t bufferSize = pixelMap.GetByteCount();
246 uint8_t *dstPixels = nullptr;
247 void *nativeBuffer = nullptr;
248 int fd = 0;
249 int targetRowStride = 0;
250 if (pixelMap.GetAllocatorType() == AllocatorType::HEAP_ALLOC) {
251 if (!AllocHeapBuffer(bufferSize, &dstPixels)) {
252 return false;
253 }
254 } else if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
255 dstPixels = AllocDmaMemory(dstImageInfo, bufferSize, &nativeBuffer, targetRowStride);
256 } else {
257 dstPixels = AllocSharedMemory(dstImageInfo.size, bufferSize, fd, pixelMap.GetUniqueId());
258 }
259 if (dstPixels == nullptr) {
260 IMAGE_LOGE("[PostProc]CenterDisplay AllocMemory[%{public}d] failed", pixelMap.GetAllocatorType());
261 return false;
262 }
263 if (!CopyPixels(pixelMap, dstPixels, dstImageInfo.size, srcWidth, srcHeight, srcRowStride, targetRowStride)) {
264 IMAGE_LOGE("[PostProc]CopyPixels failed");
265 ReleaseBuffer(pixelMap.GetAllocatorType(), fd, bufferSize, &dstPixels, nativeBuffer);
266 return false;
267 }
268 void *fdBuffer = nullptr;
269 if (pixelMap.GetAllocatorType() == AllocatorType::HEAP_ALLOC) {
270 pixelMap.SetPixelsAddr(dstPixels, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr);
271 } else if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
272 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
273 sptr<SurfaceBuffer> sourceSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (pixelMap.GetFd()));
274 sptr<SurfaceBuffer> dstSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (nativeBuffer));
275 VpeUtils::CopySurfaceBufferInfo(sourceSurfaceBuffer, dstSurfaceBuffer);
276 #endif
277 pixelMap.SetPixelsAddr(dstPixels, nativeBuffer, bufferSize, AllocatorType::DMA_ALLOC, nullptr);
278 } else {
279 fdBuffer = new int32_t();
280 *static_cast<int32_t *>(fdBuffer) = fd;
281 pixelMap.SetPixelsAddr(dstPixels, fdBuffer, bufferSize, AllocatorType::SHARE_MEM_ALLOC, nullptr);
282 }
283 return true;
284 }
285
ProcessScanlineFilter(ScanlineFilter & scanlineFilter,const Rect & cropRect,PixelMap & pixelMap,uint8_t * resultData,uint32_t rowBytes)286 bool PostProc::ProcessScanlineFilter(ScanlineFilter &scanlineFilter, const Rect &cropRect, PixelMap &pixelMap,
287 uint8_t *resultData, uint32_t rowBytes)
288 {
289 auto srcData = pixelMap.GetPixels();
290 int32_t scanLine = 0;
291 while (scanLine < pixelMap.GetHeight()) {
292 FilterRowType filterRow = scanlineFilter.GetFilterRowType(scanLine);
293 if (filterRow == FilterRowType::NON_REFERENCE_ROW) {
294 scanLine++;
295 continue;
296 }
297 if (filterRow == FilterRowType::LAST_REFERENCE_ROW) {
298 break;
299 }
300 uint32_t ret = scanlineFilter.FilterLine(resultData + ((scanLine - cropRect.top) * rowBytes), rowBytes,
301 srcData + (scanLine * pixelMap.GetRowBytes()));
302 if (ret != SUCCESS) {
303 IMAGE_LOGE("[PostProc]scan line failed, ret:%{public}u", ret);
304 return false;
305 }
306 scanLine++;
307 }
308 return true;
309 }
310
CheckScanlineFilter(const Rect & cropRect,ImageInfo & dstImageInfo,PixelMap & pixelMap,int32_t pixelBytes,ScanlineFilter & scanlineFilter)311 uint32_t PostProc::CheckScanlineFilter(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap,
312 int32_t pixelBytes, ScanlineFilter &scanlineFilter)
313 {
314 if (ImageUtils::CheckMulOverflow(dstImageInfo.size.width, dstImageInfo.size.height, pixelBytes)) {
315 IMAGE_LOGE("[PostProc]size is too large, width:%{public}d, height:%{public}d",
316 dstImageInfo.size.width, dstImageInfo.size.height);
317 return ERR_IMAGE_CROP;
318 }
319 uint64_t bufferSize = static_cast<uint64_t>(dstImageInfo.size.width) *
320 static_cast<uint64_t>(dstImageInfo.size.height) *
321 static_cast<uint64_t>(pixelBytes);
322 uint8_t *resultData = nullptr;
323 int fd = 0;
324 if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
325 resultData = AllocSharedMemory(dstImageInfo.size, bufferSize, fd, pixelMap.GetUniqueId());
326 if (resultData == nullptr) {
327 IMAGE_LOGE("[PostProc]AllocSharedMemory failed");
328 return ERR_IMAGE_CROP;
329 }
330 } else {
331 if (!AllocHeapBuffer(bufferSize, &resultData)) {
332 return ERR_IMAGE_CROP;
333 }
334 }
335 if (ImageUtils::CheckMulOverflow(dstImageInfo.size.width, pixelBytes)) {
336 IMAGE_LOGE("[PostProc]size.width:%{public}d, is too large",
337 dstImageInfo.size.width);
338 ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
339 return ERR_IMAGE_CROP;
340 }
341 uint32_t rowBytes = pixelBytes * dstImageInfo.size.width;
342 if (!ProcessScanlineFilter(scanlineFilter, cropRect, pixelMap, resultData, rowBytes)) {
343 IMAGE_LOGE("[PostProc]ProcessScanlineFilter failed");
344 ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
345 return ERR_IMAGE_CROP;
346 }
347 uint32_t result = pixelMap.SetImageInfo(dstImageInfo);
348 if (result != SUCCESS) {
349 ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
350 return result;
351 }
352
353 if (decodeOpts_.allocatorType == AllocatorType::HEAP_ALLOC) {
354 pixelMap.SetPixelsAddr(resultData, nullptr, bufferSize, decodeOpts_.allocatorType, nullptr);
355 return result;
356 }
357 void *fdBuffer = new int32_t();
358 *static_cast<int32_t *>(fdBuffer) = fd;
359 pixelMap.SetPixelsAddr(resultData, fdBuffer, bufferSize, decodeOpts_.allocatorType, nullptr);
360 return result;
361 }
362
ConvertProc(const Rect & cropRect,ImageInfo & dstImageInfo,PixelMap & pixelMap,ImageInfo & srcImageInfo)363 uint32_t PostProc::ConvertProc(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap,
364 ImageInfo &srcImageInfo)
365 {
366 bool hasPixelConvert = HasPixelConvert(srcImageInfo, dstImageInfo);
367 uint32_t ret = NeedScanlineFilter(cropRect, srcImageInfo.size, hasPixelConvert);
368 if (ret != NEED_NEXT) {
369 return ret;
370 }
371
372 // we suppose a quick method to scanline in mostly seen cases: NO CROP && hasPixelConvert
373 if (GetCropValue(cropRect, srcImageInfo.size) == CropValue::NOCROP &&
374 dstImageInfo.pixelFormat == PixelFormat::ARGB_8888 && hasPixelConvert) {
375 IMAGE_LOGI("[PostProc]no need crop, only pixel convert.");
376 return PixelConvertProc(dstImageInfo, pixelMap, srcImageInfo);
377 }
378
379 ScanlineFilter scanlineFilter(srcImageInfo.pixelFormat);
380 // this method maybe update dst image size to crop size
381 SetScanlineCropAndConvert(cropRect, dstImageInfo, srcImageInfo, scanlineFilter, hasPixelConvert);
382
383 int32_t pixelBytes = ImageUtils::GetPixelBytes(dstImageInfo.pixelFormat);
384 if (pixelBytes == 0) {
385 return ERR_IMAGE_CROP;
386 }
387 if (ImageUtils::CheckMulOverflow(dstImageInfo.size.width, dstImageInfo.size.height, pixelBytes)) {
388 IMAGE_LOGE("[PostProc]size.width:%{public}d, size.height:%{public}d is too large",
389 dstImageInfo.size.width, dstImageInfo.size.height);
390 return ERR_IMAGE_CROP;
391 }
392 return CheckScanlineFilter(cropRect, dstImageInfo, pixelMap, pixelBytes, scanlineFilter);
393 }
394
PixelConvertProc(ImageInfo & dstImageInfo,PixelMap & pixelMap,ImageInfo & srcImageInfo)395 uint32_t PostProc::PixelConvertProc(ImageInfo &dstImageInfo, PixelMap &pixelMap,
396 ImageInfo &srcImageInfo)
397 {
398 uint32_t ret;
399 int fd = 0;
400 uint64_t bufferSize = 0;
401 uint8_t *resultData = nullptr;
402
403 // as no crop, the size is same as src
404 dstImageInfo.size = srcImageInfo.size;
405 if (AllocBuffer(dstImageInfo, &resultData, bufferSize, fd, pixelMap.GetUniqueId()) != SUCCESS) {
406 ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
407 return ERR_IMAGE_CROP;
408 }
409
410 int32_t pixelBytes = ImageUtils::GetPixelBytes(srcImageInfo.pixelFormat);
411 if (pixelBytes == 0) {
412 ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
413 return ERR_IMAGE_CROP;
414 }
415
416 ret = pixelMap.SetImageInfo(dstImageInfo);
417 if (ret != SUCCESS) {
418 ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
419 return ret;
420 }
421
422 if (decodeOpts_.allocatorType == AllocatorType::HEAP_ALLOC) {
423 pixelMap.SetPixelsAddr(resultData, nullptr, bufferSize, decodeOpts_.allocatorType, nullptr);
424 return ret;
425 }
426
427 void *fdBuffer = new int32_t();
428 *static_cast<int32_t *>(fdBuffer) = fd;
429 pixelMap.SetPixelsAddr(resultData, fdBuffer, bufferSize, decodeOpts_.allocatorType, nullptr);
430 return ret;
431 }
432
AllocBuffer(ImageInfo imageInfo,uint8_t ** resultData,uint64_t & bufferSize,int & fd,uint32_t id)433 uint32_t PostProc::AllocBuffer(ImageInfo imageInfo, uint8_t **resultData, uint64_t &bufferSize, int &fd, uint32_t id)
434 {
435 int32_t pixelBytes = ImageUtils::GetPixelBytes(imageInfo.pixelFormat);
436 if (pixelBytes == 0) {
437 return ERR_IMAGE_CROP;
438 }
439 if (ImageUtils::CheckMulOverflow(imageInfo.size.width, imageInfo.size.height, pixelBytes)) {
440 IMAGE_LOGE("[PostProc]size.width:%{public}d, size.height:%{public}d is too large",
441 imageInfo.size.width, imageInfo.size.height);
442 return ERR_IMAGE_CROP;
443 }
444 bufferSize = static_cast<uint64_t>(imageInfo.size.width) *
445 static_cast<uint64_t>(imageInfo.size.height) *
446 static_cast<uint64_t>(pixelBytes);
447 IMAGE_LOGD("[PostProc]size.width:%{public}d, size.height:%{public}d, bufferSize:%{public}lld",
448 imageInfo.size.width, imageInfo.size.height, static_cast<long long>(bufferSize));
449 if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
450 *resultData = AllocSharedMemory(imageInfo.size, bufferSize, fd, id);
451 if (*resultData == nullptr) {
452 IMAGE_LOGE("[PostProc]AllocSharedMemory failed");
453 return ERR_IMAGE_CROP;
454 }
455 } else {
456 if (!AllocHeapBuffer(bufferSize, resultData)) {
457 return ERR_IMAGE_CROP;
458 }
459 }
460 return SUCCESS;
461 }
462
AllocHeapBuffer(uint64_t bufferSize,uint8_t ** buffer)463 bool PostProc::AllocHeapBuffer(uint64_t bufferSize, uint8_t **buffer)
464 {
465 if (bufferSize == 0 || bufferSize > MALLOC_MAX_LENTH) {
466 IMAGE_LOGE("[PostProc]Invalid value of bufferSize");
467 return false;
468 }
469 *buffer = static_cast<uint8_t *>(malloc(bufferSize));
470 if (*buffer == nullptr) {
471 IMAGE_LOGE("[PostProc]alloc covert color buffersize[%{public}llu] failed.",
472 static_cast<unsigned long long>(bufferSize));
473 return false;
474 }
475 #ifdef _WIN32
476 errno_t backRet = memset_s(*buffer, 0, bufferSize);
477 if (backRet != EOK) {
478 IMAGE_LOGE("[PostProc]memset convertData fail, errorCode = %{public}d", backRet);
479 ReleaseBuffer(AllocatorType::HEAP_ALLOC, 0, 0, buffer);
480 return false;
481 }
482 return true;
483 #else
484 errno_t errRet = memset_s(*buffer, bufferSize, 0, bufferSize);
485 if (errRet != EOK) {
486 IMAGE_LOGE("[PostProc]memset convertData fail, errorCode = %{public}d", errRet);
487 ReleaseBuffer(AllocatorType::HEAP_ALLOC, 0, 0, buffer);
488 return false;
489 }
490 return true;
491 #endif
492 }
493
AllocSharedMemory(const Size & size,const uint64_t bufferSize,int & fd,uint32_t uniqueId)494 uint8_t *PostProc::AllocSharedMemory(const Size &size, const uint64_t bufferSize, int &fd, uint32_t uniqueId)
495 {
496 #if defined(_WIN32) || defined(_APPLE) || defined(IOS_PLATFORM) || defined(ANDROID_PLATFORM)
497 return nullptr;
498 #else
499 std::string name = "Parcel RawData, uniqueId: " + std::to_string(getpid()) + '_' + std::to_string(uniqueId);
500 fd = AshmemCreate(name.c_str(), bufferSize);
501 if (fd < 0) {
502 IMAGE_LOGE("[PostProc]AllocSharedMemory fd error, bufferSize %{public}lld",
503 static_cast<long long>(bufferSize));
504 return nullptr;
505 }
506 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
507 if (result < 0) {
508 IMAGE_LOGE("[PostProc]AshmemSetProt error");
509 ::close(fd);
510 return nullptr;
511 }
512 void* ptr = ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
513 if (ptr == MAP_FAILED) {
514 IMAGE_LOGE("[PostProc]mmap error, errno: %{public}s, fd %{public}d, bufferSize %{public}lld",
515 strerror(errno), fd, (long long)bufferSize);
516 ::close(fd);
517 return nullptr;
518 }
519 return reinterpret_cast<uint8_t *>(ptr);
520 #endif
521 }
522
AllocDmaMemory(ImageInfo info,const uint64_t bufferSize,void ** nativeBuffer,int & targetRowStride)523 uint8_t *PostProc::AllocDmaMemory(ImageInfo info, const uint64_t bufferSize,
524 void **nativeBuffer, int &targetRowStride)
525 {
526 #if defined(_WIN32) || defined(_APPLE) || defined(IOS_PLATFORM) || defined(ANDROID_PLATFORM)
527 return nullptr;
528 #else
529 MemoryData memoryData = {nullptr, (uint32_t)bufferSize, "PostProc", {info.size.width, info.size.height}};
530 memoryData.format = info.pixelFormat;
531 auto dstMemory = MemoryManager::CreateMemory(AllocatorType::DMA_ALLOC, memoryData);
532 if (dstMemory == nullptr) {
533 return nullptr;
534 }
535 *nativeBuffer = dstMemory->extend.data;
536 auto sbBuffer = reinterpret_cast<SurfaceBuffer *>(dstMemory->extend.data);
537 targetRowStride = sbBuffer->GetStride();
538 return (uint8_t *)dstMemory->data.data;
539 #endif
540 }
541
ReleaseBuffer(AllocatorType allocatorType,int fd,uint64_t dataSize,uint8_t ** buffer,void * nativeBuffer)542 void PostProc::ReleaseBuffer(AllocatorType allocatorType, int fd,
543 uint64_t dataSize, uint8_t **buffer, void *nativeBuffer)
544 {
545 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
546 if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
547 if (*buffer != nullptr) {
548 ::munmap(*buffer, dataSize);
549 ::close(fd);
550 }
551 return;
552 }
553 if (allocatorType == AllocatorType::DMA_ALLOC) {
554 if (nativeBuffer != nullptr) {
555 int32_t err = ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer*>(nativeBuffer));
556 if (err != OHOS::GSERROR_OK) {
557 IMAGE_LOGE("PostProc NativeBufferReference failed");
558 }
559 }
560 return;
561 }
562 #endif
563
564 if (allocatorType == AllocatorType::HEAP_ALLOC) {
565 if (*buffer != nullptr) {
566 free(*buffer);
567 *buffer = nullptr;
568 }
569 return;
570 }
571 }
572
NeedScanlineFilter(const Rect & cropRect,const Size & srcSize,const bool & hasPixelConvert)573 uint32_t PostProc::NeedScanlineFilter(const Rect &cropRect, const Size &srcSize, const bool &hasPixelConvert)
574 {
575 CropValue value = GetCropValue(cropRect, srcSize);
576 if (value == CropValue::NOCROP && !hasPixelConvert) {
577 IMAGE_LOGI("[PostProc]no need crop and pixel convert.");
578 return SUCCESS;
579 } else if (value == CropValue::INVALID) {
580 IMAGE_LOGE("[PostProc]invalid corp region, top:%{public}d, left:%{public}d, "
581 "width:%{public}d, height:%{public}d", cropRect.top, cropRect.left, cropRect.width, cropRect.height);
582 return ERR_IMAGE_CROP;
583 }
584 return NEED_NEXT;
585 }
586
ConvertPixelMapToPixmapInfo(PixelMap & pixelMap,PixmapInfo & pixmapInfo)587 void PostProc::ConvertPixelMapToPixmapInfo(PixelMap &pixelMap, PixmapInfo &pixmapInfo)
588 {
589 pixmapInfo.imageInfo.size.width = pixelMap.GetWidth();
590 pixmapInfo.imageInfo.size.height = pixelMap.GetHeight();
591 pixmapInfo.imageInfo.pixelFormat = pixelMap.GetPixelFormat();
592 pixmapInfo.imageInfo.colorSpace = pixelMap.GetColorSpace();
593 pixmapInfo.imageInfo.alphaType = pixelMap.GetAlphaType();
594 pixmapInfo.imageInfo.baseDensity = pixelMap.GetBaseDensity();
595 pixmapInfo.data = const_cast<uint8_t *>(pixelMap.GetPixels());
596 pixmapInfo.bufferSize = pixelMap.GetByteCount();
597 }
598
RotatePixelMap(float rotateDegrees,PixelMap & pixelMap)599 bool PostProc::RotatePixelMap(float rotateDegrees, PixelMap &pixelMap)
600 {
601 BasicTransformer trans;
602 PixmapInfo input(false);
603 ConvertPixelMapToPixmapInfo(pixelMap, input);
604 // Default rotation at the center of the image, so divide 2
605 trans.SetRotateParam(rotateDegrees, static_cast<float>(input.imageInfo.size.width) * FHALF,
606 static_cast<float>(input.imageInfo.size.height) * FHALF);
607 return Transform(trans, input, pixelMap);
608 }
609
ScalePixelMap(const Size & size,PixelMap & pixelMap)610 bool PostProc::ScalePixelMap(const Size &size, PixelMap &pixelMap)
611 {
612 int32_t srcWidth = pixelMap.GetWidth();
613 int32_t srcHeight = pixelMap.GetHeight();
614 if (srcWidth <= 0 || srcHeight <= 0) {
615 IMAGE_LOGE("[PostProc]src width:%{public}d, height:%{public}d is invalid.", srcWidth, srcHeight);
616 return false;
617 }
618 float scaleX = static_cast<float>(size.width) / static_cast<float>(srcWidth);
619 float scaleY = static_cast<float>(size.height) / static_cast<float>(srcHeight);
620 return ScalePixelMap(scaleX, scaleY, pixelMap);
621 }
622
ScalePixelMap(float scaleX,float scaleY,PixelMap & pixelMap)623 bool PostProc::ScalePixelMap(float scaleX, float scaleY, PixelMap &pixelMap)
624 {
625 // returns directly with a scale of 1.0
626 if ((fabs(scaleX - 1.0f) < EPSILON) && (fabs(scaleY - 1.0f) < EPSILON)) {
627 return true;
628 }
629 return pixelMap.resize(scaleX, scaleY);
630 }
TranslatePixelMap(float tX,float tY,PixelMap & pixelMap)631 bool PostProc::TranslatePixelMap(float tX, float tY, PixelMap &pixelMap)
632 {
633 BasicTransformer trans;
634 PixmapInfo input(false);
635 ConvertPixelMapToPixmapInfo(pixelMap, input);
636
637 trans.SetTranslateParam(tX, tY);
638 return Transform(trans, input, pixelMap);
639 }
640
Transform(BasicTransformer & trans,const PixmapInfo & input,PixelMap & pixelMap)641 bool PostProc::Transform(BasicTransformer &trans, const PixmapInfo &input, PixelMap &pixelMap)
642 {
643 if (pixelMap.IsTransformered()) {
644 IMAGE_LOGE("[PostProc]Transform pixelmap is transforming");
645 return false;
646 }
647 pixelMap.SetTransformered(true);
648 PixmapInfo output(false);
649 output.uniqueId = pixelMap.GetUniqueId();
650 uint32_t ret;
651 if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
652 typedef uint8_t *(*AllocMemory)(const Size &size, const uint64_t bufferSize, int &fd, uint32_t uniqueId);
653 AllocMemory allcFunc = AllocSharedMemory;
654 ret = trans.TransformPixmap(input, output, allcFunc);
655 } else {
656 ret = trans.TransformPixmap(input, output);
657 }
658 if (ret != IMAGE_SUCCESS) {
659 output.Destroy();
660 return false;
661 }
662
663 if (pixelMap.SetImageInfo(output.imageInfo) != SUCCESS) {
664 output.Destroy();
665 return false;
666 }
667 pixelMap.SetPixelsAddr(output.data, output.context, output.bufferSize, decodeOpts_.allocatorType, nullptr);
668 pixelMap.SetTransformered(false);
669 return true;
670 }
671
GetCropValue(const Rect & rect,const Size & size)672 CropValue PostProc::GetCropValue(const Rect &rect, const Size &size)
673 {
674 bool isSameSize = (rect.top == 0 && rect.left == 0 && rect.height == size.height && rect.width == size.width);
675 if (!IsHasCrop(rect) || isSameSize) {
676 return CropValue::NOCROP;
677 }
678 bool isValid = ((rect.top >= 0 && rect.width > 0 && rect.left >= 0 && rect.height > 0) &&
679 (rect.top + rect.height <= size.height) && (rect.left + rect.width <= size.width));
680 if (!isValid) {
681 return CropValue::INVALID;
682 }
683 return CropValue::VALID;
684 }
685
ValidCropValue(Rect & rect,const Size & size)686 CropValue PostProc::ValidCropValue(Rect &rect, const Size &size)
687 {
688 CropValue res = GetCropValue(rect, size);
689 if (res == CropValue::INVALID) {
690 if (rect.top + rect.height > size.height) {
691 rect.height = size.height - rect.top;
692 }
693 if (rect.left + rect.width > size.width) {
694 rect.width = size.width - rect.left;
695 }
696 res = GetCropValue(rect, size);
697 }
698 return res;
699 }
700
IsHasCrop(const Rect & rect)701 bool PostProc::IsHasCrop(const Rect &rect)
702 {
703 return (rect.top != 0 || rect.left != 0 || rect.width != 0 || rect.height != 0);
704 }
705
HasPixelConvert(const ImageInfo & srcImageInfo,ImageInfo & dstImageInfo)706 bool PostProc::HasPixelConvert(const ImageInfo &srcImageInfo, ImageInfo &dstImageInfo)
707 {
708 dstImageInfo.alphaType = ImageUtils::GetValidAlphaTypeByFormat(dstImageInfo.alphaType, dstImageInfo.pixelFormat);
709 return (dstImageInfo.pixelFormat != srcImageInfo.pixelFormat || dstImageInfo.alphaType != srcImageInfo.alphaType);
710 }
711
SetScanlineCropAndConvert(const Rect & cropRect,ImageInfo & dstImageInfo,ImageInfo & srcImageInfo,ScanlineFilter & scanlineFilter,bool hasPixelConvert)712 void PostProc::SetScanlineCropAndConvert(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo,
713 ScanlineFilter &scanlineFilter, bool hasPixelConvert)
714 {
715 if (hasPixelConvert) {
716 scanlineFilter.SetPixelConvert(srcImageInfo, dstImageInfo);
717 }
718
719 Rect srcRect = cropRect;
720 if (IsHasCrop(cropRect)) {
721 dstImageInfo.size.width = cropRect.width;
722 dstImageInfo.size.height = cropRect.height;
723 } else {
724 srcRect = { 0, 0, srcImageInfo.size.width, srcImageInfo.size.height };
725 dstImageInfo.size = srcImageInfo.size;
726 }
727 scanlineFilter.SetSrcRegion(srcRect);
728 }
729
730 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
GetScaleFormat(const PixelFormat & format,AVPixelFormat & pixelFormat)731 bool GetScaleFormat(const PixelFormat &format, AVPixelFormat &pixelFormat)
732 {
733 if (format != PixelFormat::UNKNOWN) {
734 auto formatPair = PIXEL_FORMAT_MAP.find(format);
735 if (formatPair != PIXEL_FORMAT_MAP.end() && formatPair->second != 0) {
736 pixelFormat = formatPair->second;
737 return true;
738 }
739 }
740 return false;
741 }
742
GetInterpolation(const AntiAliasingOption & option)743 int GetInterpolation(const AntiAliasingOption &option)
744 {
745 switch (option) {
746 case AntiAliasingOption::NONE:
747 return SWS_POINT;
748 case AntiAliasingOption::LOW:
749 return SWS_BILINEAR;
750 case AntiAliasingOption::MEDIUM:
751 return SWS_BICUBIC;
752 case AntiAliasingOption::HIGH:
753 return SWS_AREA;
754 case AntiAliasingOption::FAST_BILINEAER:
755 return SWS_FAST_BILINEAR;
756 case AntiAliasingOption::BICUBLIN:
757 return SWS_BICUBLIN;
758 case AntiAliasingOption::GAUSS:
759 return SWS_GAUSS;
760 case AntiAliasingOption::SINC:
761 return SWS_SINC;
762 case AntiAliasingOption::LANCZOS:
763 return SWS_LANCZOS;
764 case AntiAliasingOption::SPLINE:
765 return SWS_SPLINE;
766 default:
767 return SWS_POINT;
768 }
769 }
770
GetNewSkSLRCacheMgr()771 static SkSLRCacheMgr GetNewSkSLRCacheMgr()
772 {
773 static SkMutex slrMutex;
774 static SLRLRUCache slrCache(SLR_CACHE_CAPACITY);
775 return SkSLRCacheMgr(slrCache, slrMutex);
776 }
777
initSLRFactor(Size srcSize,Size dstSize)778 std::shared_ptr<SLRWeightTuple> PostProc::initSLRFactor(Size srcSize, Size dstSize)
779 {
780 if (srcSize.width == 0 || srcSize.height == 0 || dstSize.width == 0 || dstSize.height == 0) {
781 IMAGE_LOGE("initSLRFactor invalid size, %{public}d, %{public}d, %{public}d, %{public}d",
782 srcSize.width, srcSize.height, dstSize.width, dstSize.height);
783 return nullptr;
784 }
785 SkSLRCacheMgr cacheMgr = GetNewSkSLRCacheMgr();
786 SLRWeightKey key(srcSize, dstSize);
787 std::shared_ptr<SLRWeightTuple> weightTuplePtr = cacheMgr.find(key.fKey);
788 if (weightTuplePtr == nullptr) {
789 SLRWeightMat slrWeightX = SLRProc::GetWeights(static_cast<float>(dstSize.width) / srcSize.width,
790 static_cast<int>(dstSize.width));
791 SLRWeightMat slrWeightY = SLRProc::GetWeights(static_cast<float>(dstSize.height) / srcSize.height,
792 static_cast<int>(dstSize.height));
793 SLRWeightTuple value{slrWeightX, slrWeightY, key};
794 std::shared_ptr<SLRWeightTuple> weightPtr = std::make_shared<SLRWeightTuple>(value);
795 cacheMgr.insert(key.fKey, weightPtr);
796 IMAGE_LOGI("initSLRFactor insert:%{public}d", key.fKey);
797 return weightPtr;
798 }
799 return weightTuplePtr;
800 }
801
CheckPixelMapSLR(const Size & desiredSize,PixelMap & pixelMap)802 bool CheckPixelMapSLR(const Size &desiredSize, PixelMap &pixelMap)
803 {
804 ImageInfo imgInfo;
805 pixelMap.GetImageInfo(imgInfo);
806 if (imgInfo.pixelFormat != PixelFormat::RGBA_8888) {
807 IMAGE_LOGE("CheckPixelMapSLR only support RGBA_8888 format");
808 return false;
809 }
810 int32_t srcWidth = pixelMap.GetWidth();
811 int32_t srcHeight = pixelMap.GetHeight();
812 if (srcWidth <= 0 || srcHeight <= 0 || !pixelMap.GetWritablePixels()) {
813 IMAGE_LOGE("CheckPixelMapSLR invalid src size, %{public}d, %{public}d", srcWidth, srcHeight);
814 return false;
815 }
816 if (desiredSize.width <= 0 || desiredSize.height <= 0) {
817 IMAGE_LOGE("CheckPixelMapSLR invalid desired size, %{public}d, %{public}d",
818 desiredSize.width, desiredSize.height);
819 return false;
820 }
821 if (desiredSize.width == srcWidth && desiredSize.height == srcHeight) {
822 IMAGE_LOGE("CheckPixelMapSLR same source and desired size, %{public}d, %{public}d",
823 desiredSize.width, desiredSize.height);
824 return false;
825 }
826 int32_t pixelBytes = pixelMap.GetPixelBytes();
827 if (pixelBytes <= 0) {
828 IMAGE_LOGE("CheckPixelMapSLR invalid pixel bytes, %{public}d", pixelBytes);
829 return false;
830 }
831 uint64_t dstSizeOverflow =
832 static_cast<uint64_t>(desiredSize.width) * static_cast<uint64_t>(desiredSize.height) *
833 static_cast<uint64_t>(pixelBytes);
834 if (dstSizeOverflow > UINT_MAX) {
835 IMAGE_LOGE("ScalePixelMapWithSLR desired size overflow");
836 return false;
837 }
838 return true;
839 }
840
ScalePixelMapWithSLR(const Size & desiredSize,PixelMap & pixelMap)841 bool PostProc::ScalePixelMapWithSLR(const Size &desiredSize, PixelMap &pixelMap)
842 {
843 ImageInfo imgInfo;
844 pixelMap.GetImageInfo(imgInfo);
845 if (!CheckPixelMapSLR(desiredSize, pixelMap)) {
846 return false;
847 }
848 ImageTrace imageTrace("ScalePixelMapWithSLR");
849 std::shared_ptr<SLRWeightTuple> weightTuplePtr = initSLRFactor(imgInfo.size, desiredSize);
850 if (weightTuplePtr == nullptr) {
851 IMAGE_LOGE("ScalePixelMapWithSLR init failed");
852 return false;
853 }
854 int32_t pixelBytes = pixelMap.GetPixelBytes();
855 SLRMat src(imgInfo.size, imgInfo.pixelFormat, pixelMap.GetWritablePixels(), pixelMap.GetRowStride() / pixelBytes);
856 uint32_t dstBufferSize = desiredSize.height * desiredSize.width * pixelBytes;
857 MemoryData memoryData = {nullptr, dstBufferSize, "ScalePixelMapWithSLR ImageData", desiredSize,
858 pixelMap.GetPixelFormat()};
859 auto m = MemoryManager::CreateMemory(pixelMap.GetAllocatorType(), memoryData);
860 if (m == nullptr) {
861 IMAGE_LOGE("ScalePixelMapWithSLR create memory failed");
862 return false;
863 }
864 size_t rowStride;
865 if (m->GetType() == AllocatorType::DMA_ALLOC) {
866 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
867 rowStride = reinterpret_cast<SurfaceBuffer*>(m->extend.data)->GetStride();
868 #endif
869 } else {
870 rowStride = desiredSize.width * pixelBytes;
871 }
872 SLRMat dst({desiredSize.width, desiredSize.height}, imgInfo.pixelFormat, m->data.data, rowStride / pixelBytes);
873 SLRWeightMat slrWeightX = std::get<0>(*weightTuplePtr);
874 SLRWeightMat slrWeightY = std::get<1>(*weightTuplePtr);
875 if (ImageSystemProperties::GetSLRParallelEnabled()) {
876 SLRProc::Parallel(src, dst, slrWeightX, slrWeightY);
877 } else {
878 SLRProc::Serial(src, dst, slrWeightX, slrWeightY);
879 }
880 pixelMap.SetPixelsAddr(m->data.data, m->extend.data, dstBufferSize, m->GetType(), nullptr);
881 imgInfo.size = desiredSize;
882 pixelMap.SetImageInfo(imgInfo, true);
883 if (m->GetType() == AllocatorType::DMA_ALLOC) {
884 ImageUtils::FlushSurfaceBuffer(&pixelMap);
885 }
886 return true;
887 }
888
ScalePixelMapEx(const Size & desiredSize,PixelMap & pixelMap,const AntiAliasingOption & option)889 bool PostProc::ScalePixelMapEx(const Size &desiredSize, PixelMap &pixelMap, const AntiAliasingOption &option)
890 {
891 ImageTrace imageTrace("PixelMap ScalePixelMapEx");
892 IMAGE_LOGD("ScalePixelMapEx pixelMap: width = %{public}d, height = %{public}d, pixelFormat = %{public}d, "
893 "allocatorType = %{public}d; desiredSize: width = %{public}d, height = %{public}d",
894 pixelMap.GetWidth(), pixelMap.GetHeight(), pixelMap.GetPixelFormat(),
895 pixelMap.GetAllocatorType(), desiredSize.width, desiredSize.height);
896
897 ImageInfo imgInfo;
898 pixelMap.GetImageInfo(imgInfo);
899 int32_t srcWidth = pixelMap.GetWidth();
900 int32_t srcHeight = pixelMap.GetHeight();
901 if (srcWidth <= 0 || srcHeight <= 0 || !pixelMap.GetWritablePixels()) {
902 IMAGE_LOGE("pixelMap param is invalid, src width:%{public}d, height:%{public}d", srcWidth, srcHeight);
903 return false;
904 }
905 AVPixelFormat pixelFormat;
906 if (!GetScaleFormat(imgInfo.pixelFormat, pixelFormat)) {
907 IMAGE_LOGE("pixelMap format is invalid, format: %{public}d", imgInfo.pixelFormat);
908 return false;
909 }
910 uint64_t dstBufferSizeOverflow =
911 static_cast<uint64_t>(desiredSize.width) * static_cast<uint64_t>(desiredSize.height) *
912 static_cast<uint64_t>(ImageUtils::GetPixelBytes(imgInfo.pixelFormat));
913 if (dstBufferSizeOverflow > UINT_MAX) {
914 IMAGE_LOGE("ScalePixelMapEx target size too large");
915 return false;
916 }
917 uint32_t dstBufferSize = static_cast<uint32_t>(dstBufferSizeOverflow);
918 MemoryData memoryData = {nullptr, dstBufferSize, "ScalePixelMapEx ImageData", desiredSize};
919
920 auto mem = MemoryManager::CreateMemory(pixelMap.GetAllocatorType() == AllocatorType::CUSTOM_ALLOC ?
921 AllocatorType::DEFAULT : pixelMap.GetAllocatorType(), memoryData);
922 if (mem == nullptr) {
923 IMAGE_LOGE("ScalePixelMapEx CreateMemory failed");
924 return false;
925 }
926
927 const uint8_t *srcPixels[FFMPEG_NUM] = {};
928 uint8_t *dstPixels[FFMPEG_NUM] = {};
929 srcPixels[0] = pixelMap.GetPixels();
930 dstPixels[0] = reinterpret_cast<uint8_t *>(mem->data.data);
931 int srcRowStride[FFMPEG_NUM] = {};
932 int dstRowStride[FFMPEG_NUM] = {};
933 srcRowStride[0] = pixelMap.GetRowStride();
934 dstRowStride[0] = (mem->GetType() == AllocatorType::DMA_ALLOC) ?
935 reinterpret_cast<SurfaceBuffer*>(mem->extend.data)->GetStride() :
936 desiredSize.width * ImageUtils::GetPixelBytes(imgInfo.pixelFormat);
937
938 void *inBuf = nullptr;
939 if (srcWidth % HALF != 0 && pixelMap.GetAllocatorType() == AllocatorType::SHARE_MEM_ALLOC) {
940 // Workaround for crash on odd number width, caused by FFmpeg 5.0 upgrade
941 uint64_t byteCount = static_cast<uint64_t>(srcRowStride[0]) * static_cast<uint64_t>(srcHeight);
942 uint64_t allocSize = static_cast<uint64_t>(srcWidth + 1) * static_cast<uint64_t>(srcHeight) *
943 static_cast<uint64_t>(ImageUtils::GetPixelBytes(imgInfo.pixelFormat));
944 if (srcRowStride[0] <= 0 || byteCount > UINT_MAX || allocSize < byteCount || allocSize > UINT_MAX) {
945 mem->Release();
946 IMAGE_LOGE("ScalePixelMapEx invalid srcRowStride or pixelMap size too large");
947 return false;
948 }
949 inBuf = malloc(allocSize);
950 srcPixels[0] = reinterpret_cast<uint8_t*>(inBuf);
951 errno_t errRet = memcpy_s(inBuf, allocSize, pixelMap.GetWritablePixels(), byteCount);
952 if (errRet != EOK) {
953 if (inBuf != nullptr) {
954 free(inBuf);
955 }
956 mem->Release();
957 IMAGE_LOGE("ScalePixelMapEx memcpy_s failed with error code: %{public}d", errRet);
958 return false;
959 }
960 }
961
962 SwsContext *swsContext = sws_getContext(srcWidth, srcHeight, pixelFormat, desiredSize.width, desiredSize.height,
963 pixelFormat, GetInterpolation(option), nullptr, nullptr, nullptr);
964 if (swsContext == nullptr) {
965 if (inBuf != nullptr) {
966 free(inBuf);
967 }
968 mem->Release();
969 IMAGE_LOGE("sws_getContext failed");
970 return false;
971 }
972 auto res = sws_scale(swsContext, srcPixels, srcRowStride, 0, srcHeight, dstPixels, dstRowStride);
973
974 sws_freeContext(swsContext);
975 if (inBuf != nullptr) {
976 free(inBuf);
977 }
978 if (!res) {
979 mem->Release();
980 IMAGE_LOGE("sws_scale failed");
981 return false;
982 }
983 pixelMap.SetPixelsAddr(mem->data.data, mem->extend.data, dstBufferSize, mem->GetType(), nullptr);
984 imgInfo.size = desiredSize;
985 pixelMap.SetImageInfo(imgInfo, true);
986 return true;
987 }
988 #endif
989 } // namespace Media
990 } // namespace OHOS
991