• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "pixel_yuv_ext.h"
17 #include "pixel_yuv_ext_utils.h"
18 
19 #include "image_utils.h"
20 #include "image_trace.h"
21 #include "image_type_converter.h"
22 #include "memory_manager.h"
23 #include "hilog/log.h"
24 #include "hitrace_meter.h"
25 #include "log_tags.h"
26 #include "media_errors.h"
27 #include "pubdef.h"
28 #include "pixel_yuv_utils.h"
29 #include "securec.h"
30 #include "image_log.h"
31 #include "image_mdk_common.h"
32 #include "image_system_properties.h"
33 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
34 #include "surface_buffer.h"
35 #endif
36 
37 #undef LOG_DOMAIN
38 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
39 
40 #undef LOG_TAG
41 #define LOG_TAG "PixelYuvExt"
42 
43 namespace OHOS {
44 namespace Media {
45 using namespace std;
46 
47 static const uint8_t NUM_2 = 2;
48 static const uint8_t NUM_4 = 4;
49 static const uint8_t RGBA_BIT_DEPTH = 4;
50 static const int32_t DEGREES360 = 360;
51 static const float ROUND_FLOAT_NUMBER = 0.5f;
52 
ToSkImageInfo(ImageInfo & info,sk_sp<SkColorSpace> colorSpace)53 static SkImageInfo ToSkImageInfo(ImageInfo &info, sk_sp<SkColorSpace> colorSpace)
54 {
55     SkColorType colorType = ImageTypeConverter::ToSkColorType(info.pixelFormat);
56     SkAlphaType alphaType = ImageTypeConverter::ToSkAlphaType(info.alphaType);
57     IMAGE_LOGD("ToSkImageInfo w %{public}d,h %{public}d", info.size.width, info.size.height);
58     IMAGE_LOGD("ToSkImageInfo pf %{public}s, at %{public}s, skpf %{public}s, "
59                "skat %{public}s",
60                ImageTypeConverter::ToName(info.pixelFormat).c_str(),
61                ImageTypeConverter::ToName(info.alphaType).c_str(),
62                ImageTypeConverter::ToName(colorType).c_str(),
63                ImageTypeConverter::ToName(alphaType).c_str());
64     return SkImageInfo::Make(info.size.width, info.size.height, colorType, alphaType, colorSpace);
65 }
66 
ToSkColorSpace(PixelMap * pixelmap)67 static sk_sp<SkColorSpace> ToSkColorSpace(PixelMap *pixelmap)
68 {
69 #ifdef IMAGE_COLORSPACE_FLAG
70     if (pixelmap->InnerGetGrColorSpacePtr() == nullptr) {
71         return nullptr;
72     }
73     return pixelmap->InnerGetGrColorSpacePtr()->ToSkColorSpace();
74 #else
75     return nullptr;
76 #endif
77 }
78 
isSameColorSpace(const OHOS::ColorManager::ColorSpace & src,const OHOS::ColorManager::ColorSpace & dst)79 static bool isSameColorSpace(const OHOS::ColorManager::ColorSpace &src,
80     const OHOS::ColorManager::ColorSpace &dst)
81 {
82     auto skSrc = src.ToSkColorSpace();
83     auto skDst = dst.ToSkColorSpace();
84     return SkColorSpace::Equals(skSrc.get(), skDst.get());
85 }
86 
resize(float xAxis,float yAxis)87 bool  PixelYuvExt::resize(float xAxis, float yAxis)
88 {
89     scale(xAxis, yAxis);
90     return true;
91 }
92 
resize(int32_t dstW,int32_t dstH)93 bool PixelYuvExt::resize(int32_t dstW, int32_t dstH)
94 {
95     scale(dstW, dstH);
96     return true;
97 }
98 
99 constexpr int32_t ANTIALIASING_SIZE = 350;
100 
IsSupportAntiAliasing(const ImageInfo & imageInfo,const AntiAliasingOption & option)101 static bool IsSupportAntiAliasing(const ImageInfo &imageInfo, const AntiAliasingOption &option)
102 {
103     return option != AntiAliasingOption::NONE &&
104            imageInfo.size.width <= ANTIALIASING_SIZE &&
105            imageInfo.size.height <= ANTIALIASING_SIZE;
106 }
107 
scale(int32_t dstW,int32_t dstH)108 void PixelYuvExt::scale(int32_t dstW, int32_t dstH)
109 {
110     if (!IsYuvFormat()) {
111         return;
112     }
113     ImageInfo imageInfo;
114     GetImageInfo(imageInfo);
115     AntiAliasingOption operation = AntiAliasingOption::NONE;
116     AntiAliasingOption option = AntiAliasingOption::NONE;
117     if (ImageSystemProperties::GetAntiAliasingEnabled() && IsSupportAntiAliasing(imageInfo, option)) {
118         operation = AntiAliasingOption::MEDIUM;
119     } else {
120         operation = option;
121     }
122     scale(dstW, dstH, operation);
123 }
124 
~PixelYuvExt()125 PixelYuvExt::~PixelYuvExt()
126 {
127 }
scale(float xAxis,float yAxis)128 void PixelYuvExt::scale(float xAxis, float yAxis)
129 {
130     if (!IsYuvFormat()) {
131         return;
132     }
133     ImageInfo imageInfo;
134     GetImageInfo(imageInfo);
135     AntiAliasingOption operation = AntiAliasingOption::NONE;
136     AntiAliasingOption option = AntiAliasingOption::NONE;
137     if (ImageSystemProperties::GetAntiAliasingEnabled() && IsSupportAntiAliasing(imageInfo, option)) {
138         operation = AntiAliasingOption::MEDIUM;
139     } else {
140         operation = option;
141     }
142     scale(xAxis, yAxis, operation);
143 }
144 
scale(float xAxis,float yAxis,const AntiAliasingOption & option)145 void PixelYuvExt::scale(float xAxis, float yAxis, const AntiAliasingOption &option)
146 {
147     ImageTrace imageTrace("PixelMap scale");
148     ImageInfo imageInfo;
149     GetImageInfo(imageInfo);
150     int32_t dstW = (imageInfo.size.width  * xAxis + ROUND_FLOAT_NUMBER);
151     int32_t dstH = (imageInfo.size.height * yAxis + ROUND_FLOAT_NUMBER);
152     YUVStrideInfo dstStrides;
153     auto m = CreateMemory(imageInfo.pixelFormat, "Trans ImageData", dstW, dstH, dstStrides);
154     CHECK_ERROR_RETURN_LOG(m == nullptr, "scale CreateMemory failed");
155     int64_t dstBufferSizeOverflow = static_cast<int64_t>(dstW) * static_cast<int64_t>(dstH);
156     bool cond = ImageUtils::GetPixelBytes(imageInfo.pixelFormat) == 0;
157     CHECK_ERROR_RETURN_LOG(cond, "invalid pixelFormat:[%{public}d]", imageInfo.pixelFormat);
158     int64_t maxDstBufferSize = static_cast<int64_t>(INT32_MAX) / ImageUtils::GetPixelBytes(imageInfo.pixelFormat);
159     cond = abs(dstBufferSizeOverflow) > maxDstBufferSize;
160     CHECK_ERROR_RETURN_LOG(cond, "scale target size too large, srcWidth(%{public}d) * xAxis(%{public}.2f), "
161             "srcHeight(%{public}d) * yAxis(%{public}.2f)", imageInfo.size.width, xAxis, imageInfo.size.height, yAxis);
162 
163     uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
164     YUVDataInfo yuvDataInfo;
165     GetImageYUVInfo(yuvDataInfo);
166     uint32_t pixelsSize = pixelsSize_;
167 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
168     if (allocatorType_ == AllocatorType::DMA_ALLOC) {
169         SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(GetFd());
170         if (sbBuffer == nullptr) {
171             IMAGE_LOGE("PixelYuvExt scale get SurfaceBuffer failed");
172         } else {
173             pixelsSize = sbBuffer->GetSize();
174         }
175     }
176 #endif
177     YuvImageInfo yuvInfo = {PixelYuvUtils::ConvertFormat(imageInfo.pixelFormat),
178                             imageInfo.size.width, imageInfo.size.height,
179                             imageInfo.pixelFormat, yuvDataInfo, pixelsSize};
180 
181     PixelYuvExtUtils::ScaleYuv420(xAxis, yAxis, option, yuvInfo, data_, dst, dstStrides);
182     SetPixelsAddr(reinterpret_cast<void *>(dst), m->extend.data, m->data.size, m->GetType(), nullptr);
183     imageInfo.size.width = dstW;
184     imageInfo.size.height = dstH;
185     SetImageInfo(imageInfo, true);
186     UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
187     AddVersionId();
188 }
189 
scale(int32_t dstW,int32_t dstH,const AntiAliasingOption & option)190 void PixelYuvExt::scale(int32_t dstW, int32_t dstH, const AntiAliasingOption &option)
191 {
192     ImageTrace imageTrace("PixelMap scale");
193     IMAGE_LOGI("%{public}s (%{public}d, %{public}d)", __func__, dstW, dstH);
194     ImageInfo imageInfo;
195     GetImageInfo(imageInfo);
196 
197     YUVStrideInfo dstStrides;
198     auto m = CreateMemory(imageInfo.pixelFormat, "Trans ImageData", dstW, dstH, dstStrides);
199     CHECK_ERROR_RETURN_LOG(m == nullptr, "scale CreateMemory failed");
200     uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
201     YUVDataInfo yuvDataInfo;
202     GetImageYUVInfo(yuvDataInfo);
203     uint32_t pixelsSize = pixelsSize_;
204 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
205     if (allocatorType_ == AllocatorType::DMA_ALLOC) {
206         SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(GetFd());
207         if (sbBuffer == nullptr) {
208             IMAGE_LOGE("PixelYuvExt scale get SurfaceBuffer failed");
209         } else {
210             pixelsSize = sbBuffer->GetSize();
211         }
212     }
213 #endif
214     YuvImageInfo yuvInfo = {PixelYuvUtils::ConvertFormat(imageInfo.pixelFormat),
215                             imageInfo.size.width, imageInfo.size.height,
216                             imageInfo.pixelFormat, yuvDataInfo, pixelsSize};
217     PixelYuvExtUtils::ScaleYuv420(dstW, dstH, option, yuvInfo, data_, dst, dstStrides);
218     SetPixelsAddr(reinterpret_cast<void *>(dst), m->extend.data, m->data.size, m->GetType(), nullptr);
219     imageInfo.size.width = dstW;
220     imageInfo.size.height = dstH;
221     SetImageInfo(imageInfo, true);
222     UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
223     AddVersionId();
224 }
225 
rotate(float degrees)226 void PixelYuvExt::rotate(float degrees)
227 {
228     bool cond = !IsYuvFormat() || degrees == 0;
229     CHECK_ERROR_RETURN(cond);
230     YUVDataInfo yuvDataInfo;
231     GetImageYUVInfo(yuvDataInfo);
232 
233     if (degrees < 0) {
234         int n = abs(degrees / DEGREES360);
235         degrees += DEGREES360 * (n + 1);
236     }
237     OpenSourceLibyuv::RotationMode rotateNum = OpenSourceLibyuv::RotationMode::kRotate0;
238     int32_t dstWidth = imageInfo_.size.width;
239     int32_t dstHeight = imageInfo_.size.height;
240     if (!YuvRotateConvert(imageInfo_.size, degrees, dstWidth, dstHeight, rotateNum)) {
241         IMAGE_LOGI("Rotate degress is invalid, don't need rotate");
242         return ;
243     }
244 
245     IMAGE_LOGD("PixelYuvExt::rotate dstWidth=%{public}d dstHeight=%{public}d", dstWidth, dstHeight);
246     YUVStrideInfo dstStrides;
247     auto m = CreateMemory(imageInfo_.pixelFormat, "rotate ImageData", dstWidth, dstHeight, dstStrides);
248     CHECK_ERROR_RETURN_LOG(m == nullptr, "rotate CreateMemory failed");
249     uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
250 
251     yuvDataInfo.imageSize = imageInfo_.size;
252     Size dstSize = {dstWidth, dstHeight};
253     if (!PixelYuvExtUtils::YuvRotate(data_, imageInfo_.pixelFormat, yuvDataInfo, dstSize, dst, dstStrides,
254                                      rotateNum)) {
255         m->Release();
256         return;
257     }
258     imageInfo_.size = dstSize;
259     SetImageInfo(imageInfo_, true);
260     SetPixelsAddr(dst, m->extend.data, m->data.size, m->GetType(), nullptr);
261     UpdateYUVDataInfo(imageInfo_.pixelFormat, dstWidth, dstHeight, dstStrides)
262     AddVersionId();
263     return;
264 }
265 
flip(bool xAxis,bool yAxis)266 void PixelYuvExt::flip(bool xAxis, bool yAxis)
267 {
268     bool cond = !IsYuvFormat() || (xAxis == false && yAxis == false);
269     CHECK_ERROR_RETURN(cond);
270     ImageInfo imageInfo;
271     GetImageInfo(imageInfo);
272 
273     if (imageInfo.pixelFormat == PixelFormat::YCBCR_P010 ||
274         imageInfo.pixelFormat == PixelFormat::YCRCB_P010) {
275         IMAGE_LOGD("P010 use PixelYuv flip");
276         PixelYuv::flip(xAxis, yAxis);
277         return;
278     }
279     YUVDataInfo yuvDataInfo;
280     GetImageYUVInfo(yuvDataInfo);
281 
282     int32_t width = imageInfo.size.width;
283     int32_t height = imageInfo.size.height;
284 
285     uint8_t *dst = nullptr;
286     int32_t width = imageInfo.size.width;
287     int32_t height = imageInfo.size.height;
288     YUVStrideInfo dstStrides;
289     auto m = CreateMemory(imageInfo.pixelFormat, "flip ImageData", width, height, dstStrides);
290     CHECK_ERROR_RETURN_LOG(m == nullptr, "flip CreateMemory failed");
291     uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
292     bool bRet = false;
293     if (xAxis && yAxis) {
294         bRet = PixelYuvExtUtils::Mirror(data_, dst, imageInfo.size, imageInfo.pixelFormat,
295                                         yuvDataInfo, dstStrides, true);
296     } else if (yAxis) {
297         bRet = PixelYuvExtUtils::Mirror(data_, dst, imageInfo.size, imageInfo.pixelFormat,
298                                         yuvDataInfo, dstStrides, false);
299     } else if (xAxis) {
300         bRet = PixelYuvExtUtils::FlipXaxis(data_, dst, imageInfo.size, imageInfo.pixelFormat, yuvDataInfo,
301                                            dstStrides);
302     }
303     if (!bRet) {
304         IMAGE_LOGE("flip failed xAxis=%{public}d, yAxis=%{public}d", xAxis, yAxis);
305         m->Release();
306         return;
307     }
308     SetPixelsAddr(dst, m->extend.data, m->data.size, m->GetType(), nullptr);
309     UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
310     AddVersionId();
311 }
312 
GetByteCount()313 int32_t PixelYuvExt::GetByteCount()
314 {
315     return PixelYuv::GetByteCount();
316 }
317 
SetPixelsAddr(void * addr,void * context,uint32_t size,AllocatorType type,CustomFreePixelMap func)318 void PixelYuvExt::SetPixelsAddr(void *addr, void *context, uint32_t size, AllocatorType type, CustomFreePixelMap func)
319 {
320     PixelYuv::SetPixelsAddr(addr, context, size, type, func);
321 }
322 
323 #ifdef IMAGE_COLORSPACE_FLAG
CheckColorSpace(const OHOS::ColorManager::ColorSpace & grColorSpace)324 bool PixelYuvExt::CheckColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace)
325 {
326     auto grName = grColorSpace.GetColorSpaceName();
327     if (grColorSpace_ != nullptr &&
328         isSameColorSpace(*grColorSpace_, grColorSpace)) {
329         if (grColorSpace_->GetColorSpaceName() != grName) {
330             InnerSetColorSpace(grColorSpace);
331             IMAGE_LOGE("applyColorSpace inner set");
332         }
333         return true;
334     }
335     return false;
336 }
337 
ColorSpaceBGRAToYuv(uint8_t * bgraData,SkTransYuvInfo & dst,ImageInfo & imageInfo,PixelFormat & format,const OHOS::ColorManager::ColorSpace & grColorSpace)338 int32_t PixelYuvExt::ColorSpaceBGRAToYuv(
339     uint8_t *bgraData, SkTransYuvInfo &dst, ImageInfo &imageInfo,
340     PixelFormat &format, const OHOS ::ColorManager::ColorSpace &grColorSpace)
341 {
342     int32_t dstWidth = dst.info.width();
343     int32_t dstHeight = dst.info.height();
344     YUVDataInfo yuvDataInfo;
345     GetImageYUVInfo(yuvDataInfo);
346     uint32_t pictureSize = GetImageSize(dstWidth, dstHeight, format);
347     std::unique_ptr<uint8_t[]> yuvData = std::make_unique<uint8_t[]>(pictureSize);
348     bool cond = !PixelYuvExtUtils::BGRAToYuv420(bgraData, data_, dstWidth, dstHeight, format, yuvDataInfo);
349     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_COLOR_CONVERT, "BGRAToYuv420 failed");
350     auto grName = grColorSpace.GetColorSpaceName();
351     grColorSpace_ = std::make_shared<OHOS ::ColorManager::ColorSpace>(
352         dst.info.refColorSpace(), grName);
353     AddVersionId();
354     return SUCCESS;
355 }
356 
ApplyColorSpace(const OHOS::ColorManager::ColorSpace & grColorSpace)357 uint32_t PixelYuvExt::ApplyColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace)
358 {
359     bool cond = !IsYuvFormat();
360     CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_COLOR_CONVERT);
361     cond = CheckColorSpace(grColorSpace);
362     CHECK_ERROR_RETURN_RET(cond, SUCCESS);
363     /*convert yuV420 to·BRGA */
364     PixelFormat format = imageInfo_.pixelFormat;
365     YUVDataInfo yuvDataInfo;
366     GetImageYUVInfo(yuvDataInfo);
367 
368     int32_t width = imageInfo_.size.width;
369     int32_t height = imageInfo_.size.height;
370     cond = !PixelYuvUtils::CheckWidthAndHeightMult(width, height, RGBA_BIT_DEPTH);
371     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_COLOR_CONVERT,
372         "ApplyColorSpace size overflow width(%{public}d), height(%{public}d)", width, height);
373     uint8_t *srcData = data_;
374     std::unique_ptr<uint8_t[]> RGBAdata =
375         std::make_unique<uint8_t[]>(width * height * NUM_4);
376     if (!PixelYuvExtUtils::Yuv420ToBGRA(srcData, RGBAdata.get(), imageInfo_.size, format, yuvDataInfo)) {
377         IMAGE_LOGE("Yuv420ToBGRA failed");
378         return ERR_IMAGE_COLOR_CONVERT;
379     }
380     IMAGE_LOGI("applyColorSpace Yuv420ToBGRA sucess");
381     ImageInfo bgraImageInfo = imageInfo_;
382     bgraImageInfo.pixelFormat = PixelFormat::BGRA_8888;
383 
384     SkTransYuvInfo src;
385     src.info = ToSkImageInfo(bgraImageInfo, ToSkColorSpace(this));
386     uint64_t rowStride = src.info.minRowBytes();
387     IMAGE_LOGI("applyColorSpace rowStride:%{public}ld sucess", rowStride);
388 
389     auto bret = src.bitmap.installPixels(src.info, RGBAdata.get(), rowStride);
390     CHECK_ERROR_RETURN_RET_LOG(bret == false, -1, "src.bitmap.installPixels failed");
391     // Build sk target infomation
392     SkTransYuvInfo dst;
393 
394     dst.info = ToSkImageInfo(bgraImageInfo, grColorSpace.ToSkColorSpace());
395     std::unique_ptr<uint8_t[]> RGBAdataC =
396         std::make_unique<uint8_t[]>(width * height * NUM_4);
397     // Transfor pixels*by readPixels
398     cond = !src.bitmap.readPixels(dst.info, RGBAdataC.get(), rowStride, 0, 0);
399     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_COLOR_CONVERT, "ReadPixels failed");
400     // convert bgra back to·yuv
401     cond = ColorSpaceBGRAToYuv(RGBAdataC.get(), dst, imageInfo_, format, grColorSpace) != SUCCESS;
402     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_COLOR_CONVERT, "ColorSpaceBGRAToYuv failed");
403     return SUCCESS;
404 }
405 #endif
406 } // namespace Media
407 } // namespace OHOS