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