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 DOUBLE_NUM = 2;
48 static const uint8_t NUM_4 = 4;
49 static const int32_t DEGREES360 = 360;
50 static const float ROUND_FLOAT_NUMBER = 0.5f;
51
ToSkImageInfo(ImageInfo & info,sk_sp<SkColorSpace> colorSpace)52 static SkImageInfo ToSkImageInfo(ImageInfo &info, sk_sp<SkColorSpace> colorSpace)
53 {
54 SkColorType colorType = ImageTypeConverter::ToSkColorType(info.pixelFormat);
55 SkAlphaType alphaType = ImageTypeConverter::ToSkAlphaType(info.alphaType);
56 IMAGE_LOGD("ToSkImageInfo w %{public}d,h %{public}d", info.size.width, info.size.height);
57 IMAGE_LOGD("ToSkImageInfo pf %{public}s, at %{public}s, skpf %{public}s, "
58 "skat %{public}s",
59 ImageTypeConverter::ToName(info.pixelFormat).c_str(),
60 ImageTypeConverter::ToName(info.alphaType).c_str(),
61 ImageTypeConverter::ToName(colorType).c_str(),
62 ImageTypeConverter::ToName(alphaType).c_str());
63 return SkImageInfo::Make(info.size.width, info.size.height, colorType, alphaType, colorSpace);
64 }
65
ToSkColorSpace(PixelMap * pixelmap)66 static sk_sp<SkColorSpace> ToSkColorSpace(PixelMap *pixelmap)
67 {
68 #ifdef IMAGE_COLORSPACE_FLAG
69 if (pixelmap->InnerGetGrColorSpacePtr() == nullptr) {
70 return nullptr;
71 }
72 return pixelmap->InnerGetGrColorSpacePtr()->ToSkColorSpace();
73 #else
74 return nullptr;
75 #endif
76 }
77
isSameColorSpace(const OHOS::ColorManager::ColorSpace & src,const OHOS::ColorManager::ColorSpace & dst)78 static bool isSameColorSpace(const OHOS::ColorManager::ColorSpace &src,
79 const OHOS::ColorManager::ColorSpace &dst)
80 {
81 auto skSrc = src.ToSkColorSpace();
82 auto skDst = dst.ToSkColorSpace();
83 return SkColorSpace::Equals(skSrc.get(), skDst.get());
84 }
85
resize(float xAxis,float yAxis)86 bool PixelYuvExt::resize(float xAxis, float yAxis)
87 {
88 scale(xAxis, yAxis);
89 return true;
90 }
91
resize(int32_t dstW,int32_t dstH)92 bool PixelYuvExt::resize(int32_t dstW, int32_t dstH)
93 {
94 scale(dstW, dstH);
95 return true;
96 }
97
98 constexpr int32_t ANTIALIASING_SIZE = 350;
99
IsSupportAntiAliasing(const ImageInfo & imageInfo,const AntiAliasingOption & option)100 static bool IsSupportAntiAliasing(const ImageInfo &imageInfo, const AntiAliasingOption &option)
101 {
102 return option != AntiAliasingOption::NONE &&
103 imageInfo.size.width <= ANTIALIASING_SIZE &&
104 imageInfo.size.height <= ANTIALIASING_SIZE;
105 }
106
scale(int32_t dstW,int32_t dstH)107 void PixelYuvExt::scale(int32_t dstW, int32_t dstH)
108 {
109 if (!IsYuvFormat()) {
110 return;
111 }
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 if (imageInfo.pixelFormat == PixelFormat::YCBCR_P010 ||
153 imageInfo.pixelFormat == PixelFormat::YCRCB_P010) {
154 dstW = (dstW + 1) / DOUBLE_NUM * DOUBLE_NUM;
155 dstH = (dstH + 1) / DOUBLE_NUM * DOUBLE_NUM;
156 }
157 YUVStrideInfo dstStrides;
158 auto m = CreateMemory(imageInfo.pixelFormat, "Trans ImageData", dstW, dstH, dstStrides);
159 if (m == nullptr) {
160 IMAGE_LOGE("scale CreateMemory failed");
161 return;
162 }
163
164 uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
165 YUVDataInfo yuvDataInfo;
166 GetImageYUVInfo(yuvDataInfo);
167 YuvImageInfo yuvInfo = {PixelYuvUtils::ConvertFormat(imageInfo.pixelFormat),
168 imageInfo.size.width, imageInfo.size.height,
169 imageInfo.pixelFormat, yuvDataInfo};
170
171 PixelYuvExtUtils::ScaleYuv420(xAxis, yAxis, option, yuvInfo, data_, dst, dstStrides);
172 SetPixelsAddr(reinterpret_cast<void *>(dst), m->extend.data, m->data.size, m->GetType(), nullptr);
173 imageInfo.size.width = dstW;
174 imageInfo.size.height = dstH;
175 SetImageInfo(imageInfo, true);
176 UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
177 }
178
scale(int32_t dstW,int32_t dstH,const AntiAliasingOption & option)179 void PixelYuvExt::scale(int32_t dstW, int32_t dstH, const AntiAliasingOption &option)
180 {
181 ImageTrace imageTrace("PixelMap scale");
182 ImageInfo imageInfo;
183 GetImageInfo(imageInfo);
184
185 YUVStrideInfo dstStrides;
186 auto m = CreateMemory(imageInfo.pixelFormat, "Trans ImageData", dstW, dstH, dstStrides);
187 if (m == nullptr) {
188 IMAGE_LOGE("scale CreateMemory failed");
189 return;
190 }
191
192 uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
193 YUVDataInfo yuvDataInfo;
194 GetImageYUVInfo(yuvDataInfo);
195 YuvImageInfo yuvInfo = {PixelYuvUtils::ConvertFormat(imageInfo.pixelFormat),
196 imageInfo.size.width, imageInfo.size.height,
197 imageInfo.pixelFormat, yuvDataInfo};
198
199 PixelYuvExtUtils::ScaleYuv420(dstW, dstH, option, yuvInfo, data_, dst, dstStrides);
200 SetPixelsAddr(reinterpret_cast<void *>(dst), m->extend.data, m->data.size, m->GetType(), nullptr);
201 imageInfo.size.width = dstW;
202 imageInfo.size.height = dstH;
203 SetImageInfo(imageInfo, true);
204 UpdateYUVDataInfo(imageInfo.pixelFormat, imageInfo.size.width, imageInfo.size.height, dstStrides);
205 }
206
rotate(float degrees)207 void PixelYuvExt::rotate(float degrees)
208 {
209 if (!IsYuvFormat() || degrees == 0) {
210 return;
211 }
212 YUVDataInfo yuvDataInfo;
213 GetImageYUVInfo(yuvDataInfo);
214
215 if (degrees < 0) {
216 int n = abs(degrees / DEGREES360);
217 degrees += DEGREES360 * (n + 1);
218 }
219 OpenSourceLibyuv::RotationMode rotateNum = OpenSourceLibyuv::RotationMode::kRotate0;
220 int32_t dstWidth = imageInfo_.size.width;
221 int32_t dstHeight = imageInfo_.size.height;
222 if (!YuvRotateConvert(imageInfo_.size, degrees, dstWidth, dstHeight, rotateNum)) {
223 IMAGE_LOGI("Rotate degress is invalid, don't need rotate");
224 return ;
225 }
226
227 IMAGE_LOGD("PixelYuvExt::rotate dstWidth=%{public}d dstHeight=%{public}d", dstWidth, dstHeight);
228 YUVStrideInfo dstStrides;
229 auto m = CreateMemory(imageInfo_.pixelFormat, "rotate ImageData", dstWidth, dstHeight, dstStrides);
230 if (m == nullptr) {
231 IMAGE_LOGE("rotate CreateMemory failed");
232 return;
233 }
234 uint8_t *dst = reinterpret_cast<uint8_t *>(m->data.data);
235
236 yuvDataInfo.imageSize = imageInfo_.size;
237 Size dstSize = {dstWidth, dstHeight};
238 if (!PixelYuvExtUtils::YuvRotate(data_, imageInfo_.pixelFormat, yuvDataInfo, dstSize, dst, dstStrides,
239 rotateNum)) {
240 m->Release();
241 return;
242 }
243 imageInfo_.size = dstSize;
244 SetImageInfo(imageInfo_, true);
245 SetPixelsAddr(dst, m->extend.data, m->data.size, m->GetType(), nullptr);
246 UpdateYUVDataInfo(imageInfo_.pixelFormat, dstWidth, dstHeight, dstStrides);
247 return;
248 }
249
flip(bool xAxis,bool yAxis)250 void PixelYuvExt::flip(bool xAxis, bool yAxis)
251 {
252 if (!IsYuvFormat() || (xAxis == false && yAxis == false)) {
253 return;
254 }
255 ImageInfo imageInfo;
256 GetImageInfo(imageInfo);
257
258 if (imageInfo.pixelFormat == PixelFormat::YCBCR_P010 ||
259 imageInfo.pixelFormat == PixelFormat::YCRCB_P010) {
260 IMAGE_LOGD("P010 use PixelYuv flip");
261 PixelYuv::flip(xAxis, yAxis);
262 return;
263 }
264 YUVDataInfo yuvDataInfo;
265 GetImageYUVInfo(yuvDataInfo);
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 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 }
296
GetByteCount()297 int32_t PixelYuvExt::GetByteCount()
298 {
299 return PixelYuv::GetByteCount();
300 }
301
SetPixelsAddr(void * addr,void * context,uint32_t size,AllocatorType type,CustomFreePixelMap func)302 void PixelYuvExt::SetPixelsAddr(void *addr, void *context, uint32_t size, AllocatorType type, CustomFreePixelMap func)
303 {
304 PixelYuv::SetPixelsAddr(addr, context, size, type, func);
305 }
306
307 #ifdef IMAGE_COLORSPACE_FLAG
CheckColorSpace(const OHOS::ColorManager::ColorSpace & grColorSpace)308 bool PixelYuvExt::CheckColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace)
309 {
310 auto grName = grColorSpace.GetColorSpaceName();
311 if (grColorSpace_ != nullptr &&
312 isSameColorSpace(*grColorSpace_, grColorSpace)) {
313 if (grColorSpace_->GetColorSpaceName() != grName) {
314 InnerSetColorSpace(grColorSpace);
315 IMAGE_LOGE("applyColorSpace inner set");
316 }
317 return true;
318 }
319 return false;
320 }
321
ColorSpaceBGRAToYuv(uint8_t * bgraData,SkTransYuvInfo & dst,ImageInfo & imageInfo,PixelFormat & format,const OHOS::ColorManager::ColorSpace & grColorSpace)322 int32_t PixelYuvExt::ColorSpaceBGRAToYuv(
323 uint8_t *bgraData, SkTransYuvInfo &dst, ImageInfo &imageInfo,
324 PixelFormat &format, const OHOS ::ColorManager::ColorSpace &grColorSpace)
325 {
326 int32_t dstWidth = dst.info.width();
327 int32_t dstHeight = dst.info.height();
328 YUVDataInfo yuvDataInfo;
329 GetImageYUVInfo(yuvDataInfo);
330 uint32_t pictureSize = GetImageSize(dstWidth, dstHeight, format);
331 std::unique_ptr<uint8_t[]> yuvData = std::make_unique<uint8_t[]>(pictureSize);
332 if (!PixelYuvExtUtils::BGRAToYuv420(bgraData, data_, dstWidth, dstHeight, format, yuvDataInfo)) {
333 IMAGE_LOGE("BGRAToYuv420 failed");
334 return ERR_IMAGE_COLOR_CONVERT;
335 }
336 auto grName = grColorSpace.GetColorSpaceName();
337 grColorSpace_ = std::make_shared<OHOS ::ColorManager::ColorSpace>(
338 dst.info.refColorSpace(), grName);
339 return SUCCESS;
340 }
341
ApplyColorSpace(const OHOS::ColorManager::ColorSpace & grColorSpace)342 uint32_t PixelYuvExt::ApplyColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace)
343 {
344 if (!IsYuvFormat()) {
345 return ERR_IMAGE_COLOR_CONVERT;
346 }
347 if (CheckColorSpace(grColorSpace)) {
348 return SUCCESS;
349 }
350 /*convert yuV420 to·BRGA */
351 PixelFormat format = imageInfo_.pixelFormat;
352 YUVDataInfo yuvDataInfo;
353 GetImageYUVInfo(yuvDataInfo);
354
355 int32_t width = imageInfo_.size.width;
356 int32_t height = imageInfo_.size.height;
357 uint8_t *srcData = data_;
358 std::unique_ptr<uint8_t[]> RGBAdata =
359 std::make_unique<uint8_t[]>(width * height * NUM_4);
360 if (!PixelYuvExtUtils::Yuv420ToBGRA(srcData, RGBAdata.get(), imageInfo_.size, format, yuvDataInfo)) {
361 IMAGE_LOGE("Yuv420ToBGRA failed");
362 return ERR_IMAGE_COLOR_CONVERT;
363 }
364 IMAGE_LOGI("applyColorSpace Yuv420ToBGRA sucess");
365 ImageInfo bgraImageInfo = imageInfo_;
366 bgraImageInfo.pixelFormat = PixelFormat::BGRA_8888;
367
368 SkTransYuvInfo src;
369 src.info = ToSkImageInfo(bgraImageInfo, ToSkColorSpace(this));
370 uint64_t rowStride = src.info.minRowBytes();
371 IMAGE_LOGI("applyColorSpace rowStride:%{public}ld sucess", rowStride);
372
373 auto bret = src.bitmap.installPixels(src.info, RGBAdata.get(), rowStride);
374 if (bret == false) {
375 IMAGE_LOGE("src.bitmap.installPixels failed");
376 return -1;
377 }
378 // Build sk target infomation
379 SkTransYuvInfo dst;
380
381 dst.info = ToSkImageInfo(bgraImageInfo, grColorSpace.ToSkColorSpace());
382 std::unique_ptr<uint8_t[]> RGBAdataC =
383 std::make_unique<uint8_t[]>(width * height * NUM_4);
384 // Transfor pixels*by readPixels
385 if (!src.bitmap.readPixels(dst.info, RGBAdataC.get(), rowStride, 0, 0)) {
386 IMAGE_LOGE("ReadPixels failed");
387 return ERR_IMAGE_COLOR_CONVERT;
388 }
389 // convert bgra back to·yuv
390 if (ColorSpaceBGRAToYuv(RGBAdataC.get(), dst, imageInfo_, format, grColorSpace) != SUCCESS) {
391 IMAGE_LOGE("ColorSpaceBGRAToYuv failed");
392 return ERR_IMAGE_COLOR_CONVERT;
393 }
394 return SUCCESS;
395 }
396 #endif
397 } // namespace Media
398 } // namespace OHOS