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 if (m == nullptr) {
155 IMAGE_LOGE("scale CreateMemory failed");
156 return;
157 }
158
159 uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
160 YUVDataInfo yuvDataInfo;
161 GetImageYUVInfo(yuvDataInfo);
162 YuvImageInfo yuvInfo = {PixelYuvUtils::ConvertFormat(imageInfo.pixelFormat),
163 imageInfo.size.width, imageInfo.size.height,
164 imageInfo.pixelFormat, yuvDataInfo};
165
166 PixelYuvExtUtils::ScaleYuv420(xAxis, yAxis, option, yuvInfo, data_, dst, dstStrides);
167 SetPixelsAddr(reinterpret_cast<void *>(dst), m->extend.data, m->data.size, m->GetType(), nullptr);
168 imageInfo.size.width = dstW;
169 imageInfo.size.height = dstH;
170 SetImageInfo(imageInfo, true);
171 UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
172 AddVersionId();
173 }
174
scale(int32_t dstW,int32_t dstH,const AntiAliasingOption & option)175 void PixelYuvExt::scale(int32_t dstW, int32_t dstH, const AntiAliasingOption &option)
176 {
177 ImageTrace imageTrace("PixelMap scale");
178 IMAGE_LOGI("%{public}s (%{public}d, %{public}d)", __func__, dstW, dstH);
179 ImageInfo imageInfo;
180 GetImageInfo(imageInfo);
181
182 YUVStrideInfo dstStrides;
183 auto m = CreateMemory(imageInfo.pixelFormat, "Trans ImageData", dstW, dstH, dstStrides);
184 if (m == nullptr) {
185 IMAGE_LOGE("scale CreateMemory failed");
186 return;
187 }
188 uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
189 YUVDataInfo yuvDataInfo;
190 GetImageYUVInfo(yuvDataInfo);
191 YuvImageInfo yuvInfo = {PixelYuvUtils::ConvertFormat(imageInfo.pixelFormat),
192 imageInfo.size.width, imageInfo.size.height,
193 imageInfo.pixelFormat, yuvDataInfo};
194 PixelYuvExtUtils::ScaleYuv420(dstW, dstH, option, yuvInfo, data_, dst, dstStrides);
195 SetPixelsAddr(reinterpret_cast<void *>(dst), m->extend.data, m->data.size, m->GetType(), nullptr);
196 imageInfo.size.width = dstW;
197 imageInfo.size.height = dstH;
198 SetImageInfo(imageInfo, true);
199 UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
200 AddVersionId();
201 }
202
rotate(float degrees)203 void PixelYuvExt::rotate(float degrees)
204 {
205 if (!IsYuvFormat() || degrees == 0) {
206 return;
207 }
208 YUVDataInfo yuvDataInfo;
209 GetImageYUVInfo(yuvDataInfo);
210
211 if (degrees < 0) {
212 int n = abs(degrees / DEGREES360);
213 degrees += DEGREES360 * (n + 1);
214 }
215 OpenSourceLibyuv::RotationMode rotateNum = OpenSourceLibyuv::RotationMode::kRotate0;
216 int32_t dstWidth = imageInfo_.size.width;
217 int32_t dstHeight = imageInfo_.size.height;
218 if (!YuvRotateConvert(imageInfo_.size, degrees, dstWidth, dstHeight, rotateNum)) {
219 IMAGE_LOGI("Rotate degress is invalid, don't need rotate");
220 return ;
221 }
222
223 IMAGE_LOGD("PixelYuvExt::rotate dstWidth=%{public}d dstHeight=%{public}d", dstWidth, dstHeight);
224 YUVStrideInfo dstStrides;
225 auto m = CreateMemory(imageInfo_.pixelFormat, "rotate ImageData", dstWidth, dstHeight, dstStrides);
226 if (m == nullptr) {
227 IMAGE_LOGE("rotate CreateMemory failed");
228 return;
229 }
230 uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
231
232 yuvDataInfo.imageSize = imageInfo_.size;
233 Size dstSize = {dstWidth, dstHeight};
234 if (!PixelYuvExtUtils::YuvRotate(data_, imageInfo_.pixelFormat, yuvDataInfo, dstSize, dst, dstStrides,
235 rotateNum)) {
236 m->Release();
237 return;
238 }
239 imageInfo_.size = dstSize;
240 SetImageInfo(imageInfo_, true);
241 SetPixelsAddr(dst, m->extend.data, m->data.size, m->GetType(), nullptr);
242 UpdateYUVDataInfo(imageInfo_.pixelFormat, dstWidth, dstHeight, dstStrides)
243 AddVersionId();
244 return;
245 }
246
flip(bool xAxis,bool yAxis)247 void PixelYuvExt::flip(bool xAxis, bool yAxis)
248 {
249 if (!IsYuvFormat() || (xAxis == false && yAxis == false)) {
250 return;
251 }
252 ImageInfo imageInfo;
253 GetImageInfo(imageInfo);
254
255 if (imageInfo.pixelFormat == PixelFormat::YCBCR_P010 ||
256 imageInfo.pixelFormat == PixelFormat::YCRCB_P010) {
257 IMAGE_LOGD("P010 use PixelYuv flip");
258 PixelYuv::flip(xAxis, yAxis);
259 return;
260 }
261 YUVDataInfo yuvDataInfo;
262 GetImageYUVInfo(yuvDataInfo);
263
264 int32_t width = imageInfo.size.width;
265 int32_t height = imageInfo.size.height;
266
267 uint8_t *dst = nullptr;
268 int32_t width = imageInfo.size.width;
269 int32_t height = imageInfo.size.height;
270 YUVStrideInfo dstStrides;
271 auto m = CreateMemory(imageInfo.pixelFormat, "flip ImageData", width, height, dstStrides);
272 if (m == nullptr) {
273 IMAGE_LOGE("flip CreateMemory failed");
274 return;
275 }
276 uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
277 bool bRet = false;
278 if (xAxis && yAxis) {
279 bRet = PixelYuvExtUtils::Mirror(data_, dst, imageInfo.size, imageInfo.pixelFormat,
280 yuvDataInfo, dstStrides, true);
281 } else if (yAxis) {
282 bRet = PixelYuvExtUtils::Mirror(data_, dst, imageInfo.size, imageInfo.pixelFormat,
283 yuvDataInfo, dstStrides, false);
284 } else if (xAxis) {
285 bRet = PixelYuvExtUtils::FlipXaxis(data_, dst, imageInfo.size, imageInfo.pixelFormat, yuvDataInfo,
286 dstStrides);
287 }
288 if (!bRet) {
289 IMAGE_LOGE("flip failed xAxis=%{public}d, yAxis=%{public}d", xAxis, yAxis);
290 m->Release();
291 return;
292 }
293 SetPixelsAddr(dst, m->extend.data, m->data.size, m->GetType(), nullptr);
294 UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
295 AddVersionId();
296 }
297
GetByteCount()298 int32_t PixelYuvExt::GetByteCount()
299 {
300 return PixelYuv::GetByteCount();
301 }
302
SetPixelsAddr(void * addr,void * context,uint32_t size,AllocatorType type,CustomFreePixelMap func)303 void PixelYuvExt::SetPixelsAddr(void *addr, void *context, uint32_t size, AllocatorType type, CustomFreePixelMap func)
304 {
305 PixelYuv::SetPixelsAddr(addr, context, size, type, func);
306 }
307
308 #ifdef IMAGE_COLORSPACE_FLAG
CheckColorSpace(const OHOS::ColorManager::ColorSpace & grColorSpace)309 bool PixelYuvExt::CheckColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace)
310 {
311 auto grName = grColorSpace.GetColorSpaceName();
312 if (grColorSpace_ != nullptr &&
313 isSameColorSpace(*grColorSpace_, grColorSpace)) {
314 if (grColorSpace_->GetColorSpaceName() != grName) {
315 InnerSetColorSpace(grColorSpace);
316 IMAGE_LOGE("applyColorSpace inner set");
317 }
318 return true;
319 }
320 return false;
321 }
322
ColorSpaceBGRAToYuv(uint8_t * bgraData,SkTransYuvInfo & dst,ImageInfo & imageInfo,PixelFormat & format,const OHOS::ColorManager::ColorSpace & grColorSpace)323 int32_t PixelYuvExt::ColorSpaceBGRAToYuv(
324 uint8_t *bgraData, SkTransYuvInfo &dst, ImageInfo &imageInfo,
325 PixelFormat &format, const OHOS ::ColorManager::ColorSpace &grColorSpace)
326 {
327 int32_t dstWidth = dst.info.width();
328 int32_t dstHeight = dst.info.height();
329 YUVDataInfo yuvDataInfo;
330 GetImageYUVInfo(yuvDataInfo);
331 uint32_t pictureSize = GetImageSize(dstWidth, dstHeight, format);
332 std::unique_ptr<uint8_t[]> yuvData = std::make_unique<uint8_t[]>(pictureSize);
333 if (!PixelYuvExtUtils::BGRAToYuv420(bgraData, data_, dstWidth, dstHeight, format, yuvDataInfo)) {
334 IMAGE_LOGE("BGRAToYuv420 failed");
335 return ERR_IMAGE_COLOR_CONVERT;
336 }
337 auto grName = grColorSpace.GetColorSpaceName();
338 grColorSpace_ = std::make_shared<OHOS ::ColorManager::ColorSpace>(
339 dst.info.refColorSpace(), grName);
340 AddVersionId();
341 return SUCCESS;
342 }
343
ApplyColorSpace(const OHOS::ColorManager::ColorSpace & grColorSpace)344 uint32_t PixelYuvExt::ApplyColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace)
345 {
346 if (!IsYuvFormat()) {
347 return ERR_IMAGE_COLOR_CONVERT;
348 }
349 if (CheckColorSpace(grColorSpace)) {
350 return SUCCESS;
351 }
352 /*convert yuV420 to·BRGA */
353 PixelFormat format = imageInfo_.pixelFormat;
354 YUVDataInfo yuvDataInfo;
355 GetImageYUVInfo(yuvDataInfo);
356
357 int32_t width = imageInfo_.size.width;
358 int32_t height = imageInfo_.size.height;
359 if (!PixelYuvUtils::CheckWidthAndHeightMult(width, height, RGBA_BIT_DEPTH)) {
360 IMAGE_LOGE("ApplyColorSpace size overflow width(%{public}d), height(%{public}d)", width, height);
361 return ERR_IMAGE_COLOR_CONVERT;
362 }
363 uint8_t *srcData = data_;
364 std::unique_ptr<uint8_t[]> RGBAdata =
365 std::make_unique<uint8_t[]>(width * height * NUM_4);
366 if (!PixelYuvExtUtils::Yuv420ToBGRA(srcData, RGBAdata.get(), imageInfo_.size, format, yuvDataInfo)) {
367 IMAGE_LOGE("Yuv420ToBGRA failed");
368 return ERR_IMAGE_COLOR_CONVERT;
369 }
370 IMAGE_LOGI("applyColorSpace Yuv420ToBGRA sucess");
371 ImageInfo bgraImageInfo = imageInfo_;
372 bgraImageInfo.pixelFormat = PixelFormat::BGRA_8888;
373
374 SkTransYuvInfo src;
375 src.info = ToSkImageInfo(bgraImageInfo, ToSkColorSpace(this));
376 uint64_t rowStride = src.info.minRowBytes();
377 IMAGE_LOGI("applyColorSpace rowStride:%{public}ld sucess", rowStride);
378
379 auto bret = src.bitmap.installPixels(src.info, RGBAdata.get(), rowStride);
380 if (bret == false) {
381 IMAGE_LOGE("src.bitmap.installPixels failed");
382 return -1;
383 }
384 // Build sk target infomation
385 SkTransYuvInfo dst;
386
387 dst.info = ToSkImageInfo(bgraImageInfo, grColorSpace.ToSkColorSpace());
388 std::unique_ptr<uint8_t[]> RGBAdataC =
389 std::make_unique<uint8_t[]>(width * height * NUM_4);
390 // Transfor pixels*by readPixels
391 if (!src.bitmap.readPixels(dst.info, RGBAdataC.get(), rowStride, 0, 0)) {
392 IMAGE_LOGE("ReadPixels failed");
393 return ERR_IMAGE_COLOR_CONVERT;
394 }
395 // convert bgra back to·yuv
396 if (ColorSpaceBGRAToYuv(RGBAdataC.get(), dst, imageInfo_, format, grColorSpace) != SUCCESS) {
397 IMAGE_LOGE("ColorSpaceBGRAToYuv failed");
398 return ERR_IMAGE_COLOR_CONVERT;
399 }
400 return SUCCESS;
401 }
402 #endif
403 } // namespace Media
404 } // namespace OHOS