• 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     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