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