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