• 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_utils.h"
17 
18 #include "image_log.h"
19 #include "ios"
20 #include "istream"
21 #include "image_trace.h"
22 #include "image_system_properties.h"
23 #include "media_errors.h"
24 #include "securec.h"
25 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
26 #include "surface_buffer.h"
27 #endif
28 
29 #undef LOG_DOMAIN
30 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
31 
32 #undef LOG_TAG
33 #define LOG_TAG "PixelYuvUtils"
34 
35 namespace OHOS {
36 namespace Media {
37 
38 static const uint8_t ODD = 1;
39 static const uint8_t EVEN = 2;
40 static const uint8_t NUM_2 = 2;
41 
42 static const int32_t degrees360 = 360;
43 static const int32_t degrees90 = 90;
44 static const int32_t degrees180 = 180;
45 static const int32_t degrees270 = 270;
46 constexpr uint8_t Y_SHIFT = 16;
47 constexpr uint8_t U_SHIFT = 8;
48 constexpr uint8_t V_SHIFT = 0;
49 constexpr uint8_t YUV_MASK = 0xFF;
50 constexpr uint8_t Y_DEFAULT = 0xFF;
51 constexpr uint8_t UV_DEFAULT = 0x80;
52 constexpr uint8_t TRANSPOSE_CLOCK = 1;
53 constexpr uint8_t TRANSPOSE_CCLOCK = 2;
54 constexpr int32_t EXPR_SUCCESS = 0;
55 constexpr int32_t MAX_DIMENSION = INT32_MAX >> NUM_2;
56 
57 static const std::map<PixelFormat, AVPixelFormat> FFMPEG_PIXEL_FORMAT_MAP = {
58     {PixelFormat::UNKNOWN, AVPixelFormat::AV_PIX_FMT_NONE},
59     {PixelFormat::NV21, AVPixelFormat::AV_PIX_FMT_NV21},
60     {PixelFormat::NV12, AVPixelFormat::AV_PIX_FMT_NV12},
61     {PixelFormat::ARGB_8888, AVPixelFormat::AV_PIX_FMT_ARGB},
62     {PixelFormat::BGRA_8888, AVPixelFormat::AV_PIX_FMT_BGRA},
63     {PixelFormat::YCRCB_P010, AVPixelFormat::AV_PIX_FMT_P010LE},
64     {PixelFormat::YCBCR_P010, AVPixelFormat::AV_PIX_FMT_P010LE},
65     {PixelFormat::RGBA_8888, AVPixelFormat::AV_PIX_FMT_RGBA},
66 };
67 
YuvConvertOption(const AntiAliasingOption & option)68 int32_t PixelYuvUtils::YuvConvertOption(const AntiAliasingOption &option)
69 {
70     switch (option) {
71         case AntiAliasingOption::NONE:
72             return SWS_POINT;
73         case AntiAliasingOption::LOW:
74             return SWS_BILINEAR;
75         case AntiAliasingOption::MEDIUM:
76             return SWS_BICUBIC;
77         case AntiAliasingOption::HIGH:
78             return SWS_AREA;
79         case AntiAliasingOption::FAST_BILINEAER:
80             return SWS_FAST_BILINEAR;
81         case AntiAliasingOption::BICUBLIN:
82             return SWS_BICUBLIN;
83         case AntiAliasingOption::GAUSS:
84             return SWS_GAUSS;
85         case AntiAliasingOption::SINC:
86             return SWS_SINC;
87         case AntiAliasingOption::LANCZOS:
88             return SWS_LANCZOS;
89         case AntiAliasingOption::SPLINE:
90             return SWS_SPLINE;
91         default:
92             return SWS_POINT;
93     }
94 }
95 
GetYSize(int32_t width,int32_t height)96 static int32_t GetYSize(int32_t width, int32_t height)
97 {
98     return width * height;
99 }
100 
101 // The stride of u and v are the same, Yuv420P u, v single planer
GetUStride(int32_t width)102 static int32_t GetUStride(int32_t width)
103 {
104     return (width + 1) / NUM_2;
105 }
106 
GetUVHeight(int32_t height)107 static int32_t GetUVHeight(int32_t height)
108 {
109     return (height + 1) / NUM_2;
110 }
111 
112 // Yuv420SP, u、 v blend planer
GetUVStride(int32_t width)113 static int32_t GetUVStride(int32_t width)
114 {
115     return (width + 1) / NUM_2 * NUM_2;
116 }
117 
GetImageSize(int32_t width,int32_t height)118 static uint32_t GetImageSize(int32_t width, int32_t height)
119 {
120     return width * height + ((width + 1) / NUM_2) * ((height + 1) / NUM_2) * NUM_2;
121 }
122 
WriteDataNV12Convert(uint8_t * srcPixels,const Size & size,uint8_t * dstPixels,Position dstPos,const YUVDataInfo & yuvDataInfo)123 static void WriteDataNV12Convert(uint8_t *srcPixels, const Size &size, uint8_t *dstPixels,
124     Position dstPos, const YUVDataInfo &yuvDataInfo)
125 {
126     if (!PixelYuvUtils::CheckWidthAndHeightMult(size.width, size.height, 1)) {
127         IMAGE_LOGE("WriteDataNV12Convert size overflow width(%{public}d), height(%{public}d)", size.width, size.height);
128         return;
129     }
130     uint8_t *dstY = dstPixels + yuvDataInfo.yOffset;
131     uint8_t *dstUV = dstPixels + yuvDataInfo.uvOffset;
132     dstPos.y = GetUVStride(dstPos.y);
133     for (int i = 0; i < size.height; i++) {
134         if (memcpy_s(dstY + (dstPos.y + i) * yuvDataInfo.yStride + dstPos.x,
135             size.width,
136             srcPixels + i * size.width,
137             size.width) != 0) {
138             IMAGE_LOGE("WriteDataNV12Convert memcpy yplane failed");
139             return;
140         }
141     }
142     for (int i = 0; i < GetUVHeight(size.height); ++i) {
143         if (memcpy_s(dstUV + ((dstPos.y) / NUM_2 + i) * GetUVStride(yuvDataInfo.uvStride) + dstPos.x,
144             GetUVStride(size.width),
145             srcPixels + GetYSize(size.width, size.height) + i * GetUVStride(size.width),
146             GetUVStride(size.width)) != 0) {
147             IMAGE_LOGE("WriteDataNV12Convert memcpy uplane or vplane failed");
148             return;
149         }
150     }
151 }
152 
153 
WriteDataNV12P010Convert(uint16_t * srcPixels,const Size & size,uint16_t * dstPixels,Position dstPos,const YUVDataInfo & yuvDataInfo)154 static void WriteDataNV12P010Convert(uint16_t *srcPixels, const Size &size, uint16_t *dstPixels,
155     Position dstPos, const YUVDataInfo &yuvDataInfo)
156 {
157     if (!PixelYuvUtils::CheckWidthAndHeightMult(size.width, size.height, 1)) {
158         IMAGE_LOGE("WriteDataNV12P010Convert size overflow width(%{public}d), height(%{public}d)",
159             size.width, size.height);
160         return;
161     }
162     uint16_t *dstY = dstPixels + yuvDataInfo.yOffset;
163     uint16_t *dstUV = dstPixels + yuvDataInfo.uvOffset;
164     dstPos.y = GetUVStride(dstPos.y);
165     for (int i = 0; i < size.height; i++) {
166         if (memcpy_s(dstY + (dstPos.y + i) * yuvDataInfo.yStride + dstPos.x,
167             size.width,
168             srcPixels + i * size.width,
169             size.width) != 0) {
170             IMAGE_LOGE("WriteDataNV12P010Convert memcpy yplane failed");
171             return;
172         }
173     }
174     for (int i = 0; i < GetUVHeight(size.height); ++i) {
175         if (memcpy_s(dstUV + ((dstPos.y) / NUM_2 + i) * GetUVStride(yuvDataInfo.uvStride) + dstPos.x,
176             GetUVStride(size.width),
177             srcPixels + GetYSize(size.width, size.height) + i * GetUVStride(size.width),
178             GetUVStride(size.width)) != 0) {
179             IMAGE_LOGE("WriteDataNV12P010Convert memcpy uplane or vplane failed");
180             return;
181         }
182     }
183 }
184 
WriteYuvConvert(const void * srcPixels,const ImageInfo & srcInfo,void * dstPixels,const Position & dstPos,const YUVDataInfo & yuvDataInfo)185 bool PixelYuvUtils::WriteYuvConvert(const void *srcPixels, const ImageInfo &srcInfo, void *dstPixels,
186     const Position &dstPos, const YUVDataInfo &yuvDataInfo)
187 {
188     if (srcPixels == nullptr || dstPixels == nullptr) {
189         IMAGE_LOGE("src or dst pixels invalid.");
190         return false;
191     }
192     switch (srcInfo.pixelFormat) {
193         case PixelFormat::NV21:
194             WriteDataNV12Convert((uint8_t *)srcPixels, srcInfo.size, static_cast<uint8_t *>(dstPixels), dstPos,
195                 yuvDataInfo);
196             return true;
197         case PixelFormat::NV12:
198             WriteDataNV12Convert((uint8_t *)srcPixels, srcInfo.size, static_cast<uint8_t *>(dstPixels), dstPos,
199                 yuvDataInfo);
200             return true;
201         case PixelFormat::YCBCR_P010:
202         case PixelFormat::YCRCB_P010:
203             WriteDataNV12P010Convert((uint16_t *)srcPixels, srcInfo.size, static_cast<uint16_t *>(dstPixels), dstPos,
204                 yuvDataInfo);
205             return true;
206         default:
207             return false;
208     }
209 }
210 
FillSrcFrameInfo(AVFrame * frame,uint8_t * pixels,YuvImageInfo & info)211 static void FillSrcFrameInfo(AVFrame *frame, uint8_t *pixels, YuvImageInfo &info)
212 {
213     if (frame == nullptr) {
214         IMAGE_LOGE("src frame is null.");
215         return;
216     }
217     if (info.format == AVPixelFormat::AV_PIX_FMT_NV21 || info.format == AVPixelFormat::AV_PIX_FMT_NV12) {
218         frame->data[0] = pixels + info.yuvDataInfo.yOffset;
219         frame->data[1] = pixels + info.yuvDataInfo.uvOffset;
220         frame->linesize[0] = static_cast<int32_t>(info.yuvDataInfo.yStride);
221         frame->linesize[1] = static_cast<int32_t>(info.yuvDataInfo.uvStride);
222     } else if (info.format == AVPixelFormat::AV_PIX_FMT_P010LE) {
223         av_image_fill_arrays(frame->data, frame->linesize, pixels,
224             info.format, info.yuvDataInfo.yStride, info.height, 1);
225     } else {
226         av_image_fill_arrays(frame->data, frame->linesize, pixels,
227             info.format, info.width, info.height, 1);
228     }
229 }
230 
FillRectFrameInfo(AVFrame * frame,uint8_t * pixels,const Rect & rect,YUVStrideInfo & info)231 static void FillRectFrameInfo(AVFrame *frame, uint8_t *pixels, const Rect &rect, YUVStrideInfo &info)
232 {
233     frame->data[0] = pixels + info.yOffset;
234     frame->data[1] = pixels + info.uvOffset;
235     frame->linesize[0] = static_cast<int32_t>(info.yStride);
236     frame->linesize[1] = static_cast<int32_t>(info.uvStride);
237 }
238 
FillDstFrameInfo(AVFrame * frame,uint8_t * pixels,YuvImageInfo & info)239 static void FillDstFrameInfo(AVFrame *frame, uint8_t *pixels, YuvImageInfo &info)
240 {
241     if (info.format == AVPixelFormat::AV_PIX_FMT_NV21 || info.format == AVPixelFormat::AV_PIX_FMT_NV12) {
242         frame->data[0] = pixels;
243         frame->data[1] = pixels + GetYSize(info.width, info.height);
244         frame->linesize[0] = info.width;
245         frame->linesize[1] = GetUVStride(info.width);
246     } else if (info.format == AVPixelFormat::AV_PIX_FMT_P010LE) {
247         av_image_fill_arrays(frame->data, frame->linesize, pixels,
248             info.format, info.yuvDataInfo.yStride, info.height, 1);
249     } else {
250         av_image_fill_arrays(frame->data, frame->linesize, pixels,
251             info.format, info.width, info.height, 1);
252     }
253 }
254 
FillRotateFrameInfo(AVFrame * frame,uint8_t * pixels,YuvImageInfo & info)255 static void FillRotateFrameInfo(AVFrame *frame, uint8_t *pixels, YuvImageInfo &info)
256 {
257     frame->data[0] = pixels;
258     frame->data[1] = pixels + GetYSize(info.width, info.height);
259     frame->linesize[0] = info.height;
260     frame->linesize[1] = GetUVStride(info.height);
261 }
262 
ConvertFormat(const PixelFormat & pixelFormat)263 AVPixelFormat PixelYuvUtils::ConvertFormat(const PixelFormat &pixelFormat)
264 {
265     auto formatSearch = FFMPEG_PIXEL_FORMAT_MAP.find(pixelFormat);
266     return (formatSearch != FFMPEG_PIXEL_FORMAT_MAP.end()) ? formatSearch->second : AVPixelFormat::AV_PIX_FMT_NONE;
267 }
268 
SetAVFrameInfo(AVFrame * frame,YuvImageInfo & info)269 static void SetAVFrameInfo(AVFrame* frame, YuvImageInfo &info)
270 {
271     frame->width = static_cast<int32_t>(info.yuvDataInfo.yStride);
272     frame->height = info.height;
273     frame->format = info.format;
274 }
275 
CleanUpFilterGraph(AVFilterGraph ** filterGraph,AVFrame ** srcFrame,AVFrame ** dstFrame)276 static void CleanUpFilterGraph(AVFilterGraph **filterGraph, AVFrame **srcFrame, AVFrame **dstFrame)
277 {
278     if (dstFrame && *dstFrame) {
279         av_frame_free(dstFrame);
280         *dstFrame = NULL;
281     }
282 
283     // Free the filter graph
284     if (filterGraph && *filterGraph) {
285         avfilter_graph_free(filterGraph);
286         *filterGraph = NULL;
287     }
288 
289     // Free the source frame
290     if (srcFrame && *srcFrame) {
291         av_frame_free(srcFrame);
292         *srcFrame = NULL;
293     }
294 }
295 
ProcessFilterGraph(AVFilterGraph * filterGraph,AVFilterContext * bufferSrcCtx,AVFilterContext * bufferSinkCtx,AVFrame * srcFrame,AVFrame * dstFrame)296 static bool ProcessFilterGraph(AVFilterGraph *filterGraph, AVFilterContext *bufferSrcCtx,
297     AVFilterContext *bufferSinkCtx, AVFrame *srcFrame, AVFrame *dstFrame)
298 {
299     // Configure the filtergraph with the previously set options
300     if (avfilter_graph_config(filterGraph, nullptr) < 0) {
301         IMAGE_LOGE("avfilter_graph_config failed");
302         return false;
303     }
304 
305     // Send the source frame to the filtergraph
306     if (av_buffersrc_add_frame_flags(bufferSrcCtx, srcFrame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {
307         IMAGE_LOGE("av_buffersrc_add_frame_flags failed");
308         return false;
309     }
310 
311     // Fetch the filtered frame from the buffersink
312     if (av_buffersink_get_frame(bufferSinkCtx, dstFrame) < 0) {
313         IMAGE_LOGE("av_buffersink_get_frame failed");
314         return false;
315     }
316     return true;
317 }
318 
CreateBufferSource(AVFilterGraph ** filterGraph,AVFilterContext ** bufferSrcCtx,YuvImageInfo & srcInfo)319 static bool CreateBufferSource(AVFilterGraph **filterGraph, AVFilterContext **bufferSrcCtx,
320     YuvImageInfo &srcInfo)
321 {
322     const char *bufferSrcArgs = av_asprintf("video_size=%dx%d:pix_fmt=%d:time_base=1/1:pixel_aspect=1/1",
323         srcInfo.yuvDataInfo.yStride, srcInfo.height, srcInfo.format);
324     if (!bufferSrcArgs) {
325         IMAGE_LOGE("bufferSrcArgs is null");
326         return false;
327     }
328 
329     if (avfilter_graph_create_filter(bufferSrcCtx, avfilter_get_by_name("buffer"), "in",
330         bufferSrcArgs, nullptr, *filterGraph) < 0) {
331         IMAGE_LOGE("create bufferSrcCtx filter falied");
332         av_free(reinterpret_cast<void *>(const_cast<char *>(bufferSrcArgs)));
333         return false;
334     }
335 
336     av_free(reinterpret_cast<void *>(const_cast<char *>(bufferSrcArgs)));
337     return true;
338 }
339 
CreateBufferSinkFilter(AVFilterGraph ** filterGraph,AVFilterContext ** bufferSinkCtx)340 static bool CreateBufferSinkFilter(AVFilterGraph **filterGraph, AVFilterContext **bufferSinkCtx)
341 {
342     int32_t ret = avfilter_graph_create_filter(bufferSinkCtx, avfilter_get_by_name("buffersink"), "out",
343         nullptr, nullptr, *filterGraph);
344     if (ret < 0) {
345         IMAGE_LOGE("create bufferSinkCtx filter falied");
346         return false;
347     }
348     return true;
349 }
350 
CreateCropFilter(AVFilterGraph ** filterGraph,AVFilterContext ** cropCtx,const Rect & rect,YUVStrideInfo & strides)351 static bool CreateCropFilter(AVFilterGraph **filterGraph, AVFilterContext **cropCtx,
352     const Rect &rect, YUVStrideInfo &strides)
353 {
354     const char *cropArgs = av_asprintf("x=%d:y=%d:out_w=%d:out_h=%d",
355         rect.left, rect.top, strides.yStride, rect.height);
356     if (!cropArgs) {
357         IMAGE_LOGE("YuvCrop cropArgs is null");
358         return false;
359     }
360 
361     int32_t ret = avfilter_graph_create_filter(cropCtx, avfilter_get_by_name("crop"), "crop",
362         cropArgs, nullptr, *filterGraph);
363     if (ret < 0) {
364         IMAGE_LOGE("create crop filter failed, ret = %{public}d", ret);
365         av_free(reinterpret_cast<void *>(const_cast<char *>(cropArgs)));
366         return false;
367     }
368     av_free(reinterpret_cast<void *>(const_cast<char *>(cropArgs)));
369     return true;
370 }
371 
CropUpDataDstdata(uint8_t * dstData,AVFrame * dstFrame,const Rect & rect,YUVStrideInfo & strides)372 static bool CropUpDataDstdata(uint8_t *dstData, AVFrame *dstFrame, const Rect &rect, YUVStrideInfo &strides)
373 {
374     dstFrame->width = static_cast<int32_t>(strides.yStride);
375     dstFrame->height = rect.height;
376 
377     int32_t dstSize = av_image_get_buffer_size(static_cast<AVPixelFormat>(dstFrame->format),
378         dstFrame->width, dstFrame->height, 1);
379     if (dstSize < 0) {
380         IMAGE_LOGE("YuvCrop get size failed");
381         return false;
382     }
383 
384     // Copy the output frame data to the destination buffer
385     if (av_image_copy_to_buffer(dstData, dstSize, dstFrame->data, dstFrame->linesize,
386         static_cast<AVPixelFormat>(dstFrame->format), dstFrame->width, dstFrame->height, 1) < 0) {
387         return false;
388     }
389 
390     return true;
391 }
392 
YuvCrop(uint8_t * srcData,YuvImageInfo & srcInfo,uint8_t * dstData,const Rect & rect,YUVStrideInfo & dstStrides)393 bool PixelYuvUtils::YuvCrop(uint8_t *srcData, YuvImageInfo &srcInfo, uint8_t *dstData, const Rect &rect,
394     YUVStrideInfo &dstStrides)
395 {
396     AVFrame *srcFrame = av_frame_alloc();
397     AVFrame *dstFrame = av_frame_alloc();
398     if (srcFrame == nullptr || dstFrame == nullptr) {
399         IMAGE_LOGE("YuvCrop av_frame_alloc failed!");
400         return false;
401     }
402     SetAVFrameInfo(srcFrame, srcInfo);
403     FillSrcFrameInfo(srcFrame, srcData, srcInfo);
404     FillRectFrameInfo(dstFrame, dstData, rect, dstStrides);
405     AVFilterGraph *filterGraph = avfilter_graph_alloc();
406     if (!filterGraph) {
407         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
408         return false;
409     }
410     // Create buffer source filter
411     AVFilterContext *bufferSrcCtx = nullptr;
412     if (!CreateBufferSource(&filterGraph, &bufferSrcCtx, srcInfo)) {
413         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
414         return false;
415     }
416     // Create crop filter
417     AVFilterContext *cropCtx = nullptr;
418     if (!CreateCropFilter(&filterGraph, &cropCtx, rect, dstStrides)) {
419         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
420         return false;
421     }
422     // Create buffer sink filter
423     AVFilterContext *bufferSinkCtx = nullptr;
424     if (!CreateBufferSinkFilter(&filterGraph, &bufferSinkCtx)) {
425         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
426         return false;
427     }
428     // Link filters
429     if (avfilter_link(bufferSrcCtx, 0, cropCtx, 0) < 0 || avfilter_link(cropCtx, 0, bufferSinkCtx, 0) < 0) {
430         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
431         return false;
432     }
433     if (!ProcessFilterGraph(filterGraph, bufferSrcCtx, bufferSinkCtx, srcFrame, dstFrame)) {
434         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
435         return false;
436     }
437     if (!CropUpDataDstdata(dstData, dstFrame, rect, dstStrides)) {
438         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
439         return false;
440     }
441     // Clean up
442     CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
443     return true;
444 }
445 
YuvScale(uint8_t * srcPixels,YuvImageInfo & srcInfo,uint8_t * dstPixels,YuvImageInfo & dstInfo,int32_t module)446 int32_t PixelYuvUtils::YuvScale(uint8_t *srcPixels, YuvImageInfo &srcInfo,
447     uint8_t *dstPixels, YuvImageInfo &dstInfo, int32_t module)
448 {
449     struct SwsContext *ctx = nullptr;
450 
451     if (srcInfo.format == AVPixelFormat::AV_PIX_FMT_NONE || dstInfo.format == AVPixelFormat::AV_PIX_FMT_NONE) {
452         IMAGE_LOGE("unsupport src/dst pixel format!");
453         return -1;
454     }
455     if (srcInfo.width <= 0 || srcInfo.height <= 0 || dstInfo.width <= 0 || dstInfo.height <= 0) {
456         IMAGE_LOGE("src/dst width/height error!");
457         return -1;
458     }
459     ctx = sws_getContext(srcInfo.width, srcInfo.height, srcInfo.format,
460                          dstInfo.width, dstInfo.height, dstInfo.format,
461                          module, nullptr, nullptr, nullptr);
462     if (ctx == nullptr) {
463         IMAGE_LOGE("FFMpeg: sws_getContext failed!");
464         return -1;
465     }
466     AVFrame *srcFrame = av_frame_alloc();
467     AVFrame *dstFrame = av_frame_alloc();
468     if (srcFrame == nullptr || dstFrame == nullptr) {
469         IMAGE_LOGE("FFMpeg: av_frame_alloc failed!");
470         sws_freeContext(ctx);
471         return  -1;
472     }
473     FillSrcFrameInfo(srcFrame, srcPixels, srcInfo);
474     FillDstFrameInfo(dstFrame, dstPixels, dstInfo);
475     auto ret = sws_scale(ctx, srcFrame->data, srcFrame->linesize, 0, srcInfo.height,
476         dstFrame->data, dstFrame->linesize);
477     av_frame_free(&srcFrame);
478     av_frame_free(&dstFrame);
479     sws_freeContext(ctx);
480     if (ret <= 0) {
481         IMAGE_LOGE("FFMpeg: sws_scale failed!");
482         return -1;
483     }
484     return EXPR_SUCCESS;
485 }
486 
CreateRotateFilter(AVFilterGraph ** filterGraph,AVFilterContext ** transposeCtx,int32_t rotateNum)487 static bool CreateRotateFilter(AVFilterGraph **filterGraph, AVFilterContext **transposeCtx,
488     int32_t rotateNum)
489 {
490     const char *rotateArgs = av_asprintf("%d", rotateNum);
491     if (!rotateArgs) {
492         IMAGE_LOGE("rotateArgs is null");
493         return false;
494     }
495 
496     int ret = avfilter_graph_create_filter(transposeCtx, avfilter_get_by_name("transpose"),
497         "rotate", rotateArgs, nullptr, *filterGraph);
498     if (ret < 0) {
499         IMAGE_LOGE("create transpose filter failed, ret = %{public}d", ret);
500         av_free(reinterpret_cast<void *>(const_cast<char *>(rotateArgs)));
501         return false;
502     }
503     av_free(reinterpret_cast<void *>(const_cast<char *>(rotateArgs)));
504     return true;
505 }
506 
RoatateUpDataDstdata(YuvImageInfo & srcInfo,YuvImageInfo & dstInfo,uint8_t * dstData,AVFrame * srcFrame,AVFrame * dstFrame)507 static bool RoatateUpDataDstdata(YuvImageInfo &srcInfo, YuvImageInfo &dstInfo, uint8_t *dstData,
508     AVFrame *srcFrame, AVFrame *dstFrame)
509 {
510     dstFrame->width = srcFrame->height;
511     dstFrame->height = srcFrame->width;
512     dstInfo.width = srcInfo.height;
513     dstInfo.height = srcInfo.width;
514 
515     int32_t dstSize = av_image_get_buffer_size(static_cast<AVPixelFormat>(dstFrame->format),
516         dstFrame->width, dstFrame->height, 1);
517     if (dstSize < 0) {
518         IMAGE_LOGE("RoatateUpDataDstdata get size failed");
519         return false;
520     }
521 
522     // Copy the output frame data to the destination buffer
523     if (av_image_copy_to_buffer(dstData, dstSize, dstFrame->data, dstFrame->linesize,
524         static_cast<AVPixelFormat>(dstFrame->format), dstFrame->width, dstFrame->height, 1) < 0) {
525         IMAGE_LOGE("RoatateUpDataDstdata copy data failed");
526         return false;
527     }
528 
529     return true;
530 }
531 
Rotate(uint8_t * srcData,YuvImageInfo & srcInfo,uint8_t * dstData,YuvImageInfo & dstInfo,int32_t rotateNum)532 static bool Rotate(uint8_t *srcData, YuvImageInfo &srcInfo, uint8_t *dstData,
533     YuvImageInfo &dstInfo, int32_t rotateNum)
534 {
535     AVFrame *srcFrame = av_frame_alloc();
536     AVFrame *dstFrame = av_frame_alloc();
537     if (srcFrame == nullptr || dstFrame == nullptr) {
538         IMAGE_LOGE("Rotate av_frame_alloc failed");
539         return false;
540     }
541 
542     SetAVFrameInfo(srcFrame, srcInfo);
543     FillSrcFrameInfo(srcFrame, srcData, srcInfo);
544     FillRotateFrameInfo(dstFrame, dstData, srcInfo);
545 
546     AVFilterGraph *filterGraph = avfilter_graph_alloc();
547     if (!filterGraph) {
548         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
549         return false;
550     }
551     // Create buffer source filter
552     AVFilterContext *bufferSrcCtx = nullptr;
553     if (!CreateBufferSource(&filterGraph, &bufferSrcCtx, srcInfo)) {
554         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
555         return false;
556     }
557     // Create transpose filter
558     AVFilterContext *transposeCtx = nullptr;
559     if (!CreateRotateFilter(&filterGraph, &transposeCtx, rotateNum)) {
560         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
561         return false;
562     }
563     // Create buffer sink filter
564     AVFilterContext *bufferSinkCtx = nullptr;
565     if (!CreateBufferSinkFilter(&filterGraph, &bufferSinkCtx)) {
566         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
567         return false;
568     }
569     // Link filters together
570     if (avfilter_link(bufferSrcCtx, 0, transposeCtx, 0) < 0 || avfilter_link(transposeCtx, 0, bufferSinkCtx, 0) < 0) {
571         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
572         return false;
573     }
574     if (!ProcessFilterGraph(filterGraph, bufferSrcCtx, bufferSinkCtx, srcFrame, dstFrame)) {
575         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
576         return false;
577     }
578     if (!RoatateUpDataDstdata(srcInfo, dstInfo, dstData, srcFrame, dstFrame)) {
579         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
580         return false;
581     }
582     // Clean up
583     CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
584     return true;
585 }
586 
CreateFilpFilter(AVFilterGraph ** filterGraph,AVFilterContext ** flipCtx,bool xAxis)587 static bool CreateFilpFilter(AVFilterGraph **filterGraph, AVFilterContext **flipCtx, bool xAxis)
588 {
589     const char *flipType = xAxis ? "hflip" : "vflip";
590     int32_t ret = avfilter_graph_create_filter(flipCtx, avfilter_get_by_name(flipType),
591         flipType, NULL, NULL, *filterGraph);
592     if (ret < 0) {
593         IMAGE_LOGE("create flip filter failed, ret = %{public}d", ret);
594         return false;
595     }
596     return true;
597 }
598 
FlipUpDataDstdata(YuvImageInfo & srcInfo,uint8_t * dstData,AVFrame * srcFrame,AVFrame * dstFrame)599 static bool FlipUpDataDstdata(YuvImageInfo &srcInfo, uint8_t *dstData, AVFrame *srcFrame, AVFrame *dstFrame)
600 {
601     dstFrame->width = srcFrame->width;
602     dstFrame->height = srcFrame->height;
603 
604     int32_t dstSize = av_image_get_buffer_size(static_cast<AVPixelFormat>(dstFrame->format),
605         dstFrame->width, dstFrame->height, 1);
606     if (dstSize < 0) {
607         IMAGE_LOGE("FlipUpDataDstdata get size failed");
608         return false;
609     }
610 
611     // Copy the output frame data to the destination buffer
612     if (av_image_copy_to_buffer(dstData, dstSize, dstFrame->data, dstFrame->linesize,
613         static_cast<AVPixelFormat>(dstFrame->format), dstFrame->width, dstFrame->height, 1) < 0) {
614         IMAGE_LOGE("FlipUpDataDstdata copy data failed");
615         return false;
616     }
617 
618     return true;
619 }
620 
YuvFlip(uint8_t * srcData,YuvImageInfo & srcInfo,uint8_t * dstData,bool xAxis)621 bool PixelYuvUtils::YuvFlip(uint8_t *srcData, YuvImageInfo &srcInfo, uint8_t *dstData, bool xAxis)
622 {
623     AVFrame *srcFrame = av_frame_alloc();
624     AVFrame *dstFrame = av_frame_alloc();
625     if (srcFrame == nullptr || dstFrame == nullptr) {
626         IMAGE_LOGE("FlipYuv av_frame_alloc failed");
627         return false;
628     }
629     SetAVFrameInfo(srcFrame, srcInfo);
630     FillSrcFrameInfo(srcFrame, srcData, srcInfo);
631     FillDstFrameInfo(dstFrame, dstData, srcInfo);
632     AVFilterGraph *filterGraph = avfilter_graph_alloc();
633     if (!filterGraph) {
634         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
635         return false;
636     }
637     // Create buffer source filter
638     AVFilterContext *bufferSrcCtx = nullptr;
639     if (!CreateBufferSource(&filterGraph, &bufferSrcCtx, srcInfo)) {
640         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
641         return false;
642     }
643     // Create crop filter
644     AVFilterContext *flipCtx = nullptr;
645     if (!CreateFilpFilter(&filterGraph, &flipCtx, xAxis)) {
646         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
647         return false;
648     }
649     // Create buffer sink filter
650     AVFilterContext *bufferSinkCtx = nullptr;
651     if (!CreateBufferSinkFilter(&filterGraph, &bufferSinkCtx)) {
652         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
653         return false;
654     }
655     // Link filters
656     if (avfilter_link(bufferSrcCtx, 0, flipCtx, 0) < 0 || avfilter_link(flipCtx, 0, bufferSinkCtx, 0) < 0) {
657         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
658         return false;
659     }
660     if (!ProcessFilterGraph(filterGraph, bufferSrcCtx, bufferSinkCtx, srcFrame, dstFrame)) {
661         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
662         return false;
663     }
664     if (!FlipUpDataDstdata(srcInfo, dstData, srcFrame, dstFrame)) {
665         CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
666         return false;
667     }
668     // Clean up
669     CleanUpFilterGraph(&filterGraph, &srcFrame, &dstFrame);
670     return true;
671 }
672 
IsYUVP010Format(PixelFormat format)673 static bool IsYUVP010Format(PixelFormat format)
674 {
675     return format == PixelFormat::YCBCR_P010 || format == PixelFormat::YCRCB_P010;
676 }
677 
YuvReversal(uint8_t * srcData,YuvImageInfo & srcInfo,uint8_t * dstData,YuvImageInfo & dstInfo)678 bool PixelYuvUtils::YuvReversal(uint8_t *srcData, YuvImageInfo &srcInfo, uint8_t *dstData, YuvImageInfo &dstInfo)
679 {
680     uint32_t dataSize = GetImageSize(srcInfo.width, srcInfo.height);
681     std::unique_ptr<uint8_t[]> tmpData = nullptr;
682     if (IsYUVP010Format(srcInfo.yuvFormat)) {
683         tmpData = std::make_unique<uint8_t[]>(dataSize * NUM_2);
684     } else {
685         tmpData = std::make_unique<uint8_t[]>(dataSize);
686     }
687     if (!YuvFlip(srcData, srcInfo, tmpData.get(), true)) {
688         IMAGE_LOGE("YuvFlip xAxis failed");
689         return false;
690     }
691     if (!YuvFlip(tmpData.get(), srcInfo, dstData, false)) {
692         IMAGE_LOGE("YuvFlip yAxis failed");
693         return false;
694     }
695     dstInfo.width = srcInfo.width;
696     dstInfo.height = srcInfo.height;
697     return true;
698 }
699 
YuvRotate(uint8_t * srcData,YuvImageInfo & srcInfo,uint8_t * dstData,YuvImageInfo & dstInfo,int32_t degrees)700 bool PixelYuvUtils::YuvRotate(uint8_t *srcData, YuvImageInfo &srcInfo,
701     uint8_t *dstData, YuvImageInfo &dstInfo, int32_t degrees)
702 {
703     if (degrees < 0) {
704         int n = abs(degrees / degrees360);
705         degrees += degrees360 * (n + 1);
706     }
707     switch (degrees) {
708         case 0:
709             return true;
710         case degrees90:
711             if (!Rotate(srcData, srcInfo, dstData, dstInfo, TRANSPOSE_CLOCK)) {
712                 IMAGE_LOGE("YuvRotate 90 failed");
713                 return false;
714             }
715             return true;
716         case degrees180: {
717             if (!YuvReversal(srcData, srcInfo, dstData, dstInfo)) {
718                 IMAGE_LOGE("YuvRotate 180 failed");
719                 return false;
720             }
721             return true;
722         }
723         case degrees270:
724             if (!Rotate(srcData, srcInfo, dstData, dstInfo, TRANSPOSE_CCLOCK)) {
725                 IMAGE_LOGE("YuvRotate 270 failed");
726                 return false;
727             }
728             return true;
729         default:
730             return false;
731     }
732 }
733 
ReadYuvConvert(const void * srcPixels,const Position & srcPos,YuvImageInfo & info,void * dstPixels,const ImageInfo & dstInfo)734 bool PixelYuvUtils::ReadYuvConvert(const void *srcPixels, const Position &srcPos, YuvImageInfo &info,
735     void *dstPixels, const ImageInfo &dstInfo)
736 {
737     if (srcPixels == nullptr || dstPixels == nullptr) {
738         IMAGE_LOGE("src or dst pixels invalid.");
739         return false;
740     }
741     Rect rect;
742     rect.left = srcPos.x;
743     rect.top = srcPos.y;
744     rect.width = dstInfo.size.width;
745     rect.height = dstInfo.size.height;
746     YUVStrideInfo dstStrides = {rect.width, rect.width, 0, rect.width * rect.height};
747     if (!YuvCrop((uint8_t *)srcPixels, info, static_cast<uint8_t *>(dstPixels), rect, dstStrides)) {
748         return false;
749     }
750     return true;
751 }
752 
753 
SetTranslateDataDefault(uint8_t * srcPixels,int32_t width,int32_t height,PixelFormat format,YUVStrideInfo & dstStrides)754 void PixelYuvUtils::SetTranslateDataDefault(uint8_t *srcPixels, int32_t width, int32_t height, PixelFormat format,
755     YUVStrideInfo &dstStrides)
756 {
757     if (dstStrides.yStride > UINT32_MAX || dstStrides.uvStride > UINT32_MAX) {
758         IMAGE_LOGE("check yStride(%{public}d) or uvStride(%{public}d)", dstStrides.yStride, dstStrides.uvStride);
759         return;
760     }
761     auto ySizeNormal = dstStrides.yStride * static_cast<uint32_t>(height);
762     auto uvSizeNormal = dstStrides.uvStride * static_cast<uint32_t>(GetUVHeight(height));
763     if (IsYUVP010Format(format)) {
764         ySizeNormal *= NUM_2;
765         uvSizeNormal *= NUM_2;
766     }
767 
768     if (ySizeNormal > UINT32_MAX || uvSizeNormal > UINT32_MAX) {
769         IMAGE_LOGE("ySizeNormal or uvSizeNormal is overflow.");
770         return;
771     }
772 
773     if (memset_s(srcPixels, ySizeNormal, Y_DEFAULT, ySizeNormal) != EOK ||
774         memset_s(srcPixels + ySizeNormal, uvSizeNormal, UV_DEFAULT, uvSizeNormal) != EOK) {
775         IMAGE_LOGW("set translate default color failed");
776     }
777 }
778 
GetYuv420Y(uint32_t x,uint32_t y,YUVDataInfo & info,const uint8_t * in)779 uint8_t PixelYuvUtils::GetYuv420Y(uint32_t x, uint32_t y, YUVDataInfo &info, const uint8_t *in)
780 {
781     return *(in + y * info.yStride + x);
782 }
783 
GetYuv420U(uint32_t x,uint32_t y,YUVDataInfo & info,PixelFormat format,const uint8_t * in)784 uint8_t PixelYuvUtils::GetYuv420U(uint32_t x, uint32_t y, YUVDataInfo &info, PixelFormat format,
785     const uint8_t *in)
786 {
787     uint32_t width = info.yStride;
788     switch (format) {
789         case PixelFormat::NV21:
790             if (width & 1) {
791                 return *(in + y / NUM_2 * NUM_2 + info.uvOffset + (y / NUM_2) * (width - 1) + (x & ~1) + 1);
792             }
793             return *(in + info.uvOffset + (y / NUM_2) * width + (x & ~1) + 1);
794         case PixelFormat::NV12:
795             if (width & 1) {
796                 return *(in + y / NUM_2 * NUM_2 + info.uvOffset + (y / NUM_2) * (width - 1) + (x & ~1));
797             }
798             return *(in + info.uvOffset + (y / NUM_2) * width + (x & ~1));
799         default:
800             break;
801     }
802     return SUCCESS;
803 }
804 
GetYuv420V(uint32_t x,uint32_t y,YUVDataInfo & info,PixelFormat format,const uint8_t * in)805 uint8_t PixelYuvUtils::GetYuv420V(uint32_t x, uint32_t y, YUVDataInfo &info, PixelFormat format,
806     const uint8_t *in)
807 {
808     uint32_t width = info.yStride;
809     switch (format) {
810         case PixelFormat::NV21:
811             if (width & 1) {
812                 return *(in + y / NUM_2 * NUM_2 + info.uvOffset + (y / NUM_2) * (width - 1) + (x & ~1));
813             }
814             return *(in + info.uvOffset + (y / NUM_2) * width + (x & ~1));
815         case PixelFormat::NV12:
816             if (width & 1) {
817                 return *(in + y / NUM_2 * NUM_2 + info.uvOffset + (y / NUM_2) * (width - 1) + (x & ~1) + 1);
818             }
819             return *(in + info.uvOffset + (y / NUM_2) * width + (x & ~1) + 1);
820         default:
821             break;
822     }
823     return SUCCESS;
824 }
825 
BGRAToYuv420(const uint8_t * src,YuvImageInfo & srcInfo,uint8_t * dst,YuvImageInfo & dstInfo)826 bool PixelYuvUtils::BGRAToYuv420(const uint8_t *src, YuvImageInfo &srcInfo, uint8_t *dst, YuvImageInfo &dstInfo)
827 {
828     if (YuvScale(const_cast<uint8_t *>(src), srcInfo, dst, dstInfo,
829                  static_cast<int32_t>(SWS_BICUBIC)) != EXPR_SUCCESS) {
830         IMAGE_LOGE("BGRAToYuv420 failed");
831         return false;
832     }
833     return true;
834 }
835 
Yuv420ToBGRA(const uint8_t * in,YuvImageInfo & srcInfo,uint8_t * out,YuvImageInfo & dstInfo)836 bool PixelYuvUtils::Yuv420ToBGRA(const uint8_t *in, YuvImageInfo &srcInfo, uint8_t *out, YuvImageInfo &dstInfo)
837 {
838     if (YuvScale(const_cast<uint8_t *>(in), srcInfo, out, dstInfo, static_cast<int32_t>(SWS_BICUBIC)) != EXPR_SUCCESS) {
839         IMAGE_LOGE("Yuv420ToBGRA failed");
840         return false;
841     }
842     return true;
843 }
844 
Yuv420ToARGB(const uint8_t * in,YuvImageInfo & srcInfo,uint8_t * out,YuvImageInfo & dstInfo)845 bool PixelYuvUtils::Yuv420ToARGB(const uint8_t *in, YuvImageInfo &srcInfo, uint8_t *out, YuvImageInfo &dstInfo)
846 {
847     if (YuvScale(const_cast<uint8_t *>(in), srcInfo, out, dstInfo, static_cast<int32_t>(SWS_BICUBIC)) != EXPR_SUCCESS) {
848         IMAGE_LOGE("Yuv420ToBGRA failed");
849         return false;
850     }
851     return true;
852 }
853 
Yuv420SPWritePixels(const YUVDataInfo & yuvInfo,uint8_t * srcPixels,const uint32_t & color,bool isNV12,ImageInfo & info)854 static void Yuv420SPWritePixels(const YUVDataInfo &yuvInfo, uint8_t *srcPixels,
855     const uint32_t &color, bool isNV12, ImageInfo &info)
856 {
857     uint8_t colorY = (color >> Y_SHIFT) & YUV_MASK;
858     uint8_t colorU = (color >> U_SHIFT) & YUV_MASK;
859     uint8_t colorV = (color >> V_SHIFT) & YUV_MASK;
860 
861     uint8_t *srcY = srcPixels + yuvInfo.yOffset;
862     uint8_t *srcUV = srcPixels + yuvInfo.uvOffset;
863 
864     for (int32_t y = 0; y < info.size.height; y++) {
865         for (int32_t x = 0; x < info.size.width; x++) {
866             *(srcY + y * yuvInfo.yStride + x) = colorY;
867         }
868     }
869 
870     for (int32_t y = 0; y < GetUVHeight(info.size.height); y++) {
871         for (int32_t x = 0; x < GetUVStride(info.size.width); x += NUM_2) {
872             if (isNV12) {
873                 *(srcUV + (y * yuvInfo.uvStride + x)) = colorU;
874                 *(srcUV + (y * yuvInfo.uvStride + x) + 1) = colorV;
875             } else {
876                 *(srcUV + (y * yuvInfo.uvStride + x)) = colorV;
877                 *(srcUV + (y * yuvInfo.uvStride + x) + 1) = colorU;
878             }
879         }
880     }
881 }
882 
P010WritePixels(const YUVDataInfo & yuvInfo,uint16_t * srcPixels,const uint32_t & color,bool isNV12P010,ImageInfo & info)883 static void P010WritePixels(const YUVDataInfo &yuvInfo, uint16_t *srcPixels,
884     const uint32_t &color, bool isNV12P010, ImageInfo &info)
885 {
886     uint16_t colorY = (color >> Y_SHIFT) & YUV_MASK;
887     uint16_t colorU = (color >> U_SHIFT) & YUV_MASK;
888     uint16_t colorV = (color >> V_SHIFT) & YUV_MASK;
889 
890     uint16_t *srcY = srcPixels + yuvInfo.yOffset;
891     uint16_t *srcUV = srcPixels + yuvInfo.uvOffset;
892 
893     for (uint32_t y = 0; y < yuvInfo.yHeight; y++) {
894         for (uint32_t x = 0; x < yuvInfo.yWidth; x++) {
895             *(srcY + y * yuvInfo.yStride + x) = colorY;
896         }
897     }
898 
899     for (int32_t y = 0; y < GetUVHeight(info.size.height); y++) {
900         for (int32_t x = 0; x < GetUVStride(info.size.width); x += NUM_2) {
901             if (isNV12P010) {
902                 *(srcUV + (y * yuvInfo.uvStride + x)) = colorU;
903                 *(srcUV + (y * yuvInfo.uvStride + x) + 1) = colorV;
904             } else {
905                 *(srcUV + (y * yuvInfo.uvStride + x)) = colorV;
906                 *(srcUV + (y * yuvInfo.uvStride + x) + 1) = colorU;
907             }
908         }
909     }
910 }
911 
Yuv420WritePixels(const YUVDataInfo & yuvInfo,uint8_t * srcPixels,ImageInfo & info,const uint32_t & color)912 bool PixelYuvUtils::Yuv420WritePixels(const YUVDataInfo &yuvInfo, uint8_t *srcPixels, ImageInfo &info,
913     const uint32_t &color)
914 {
915     switch (info.pixelFormat) {
916         case PixelFormat::NV21:
917         case PixelFormat::NV12: {
918             bool isNV12 = (info.pixelFormat == PixelFormat::NV12 ? true : false);
919             Yuv420SPWritePixels(yuvInfo, srcPixels, color, isNV12, info);
920             return true;
921         }
922         case PixelFormat::YCBCR_P010:
923         case PixelFormat::YCRCB_P010: {
924             bool isNV12P010 = (info.pixelFormat == PixelFormat::YCBCR_P010) ? true : false;
925             P010WritePixels(yuvInfo, (uint16_t *)srcPixels, color, isNV12P010, info);
926             return true;
927         }
928         default:
929             return false;
930     }
931 }
932 
Yuv420SPWritePixel(uint8_t * srcPixels,const YUVDataInfo & yuvDataInfo,const Position & pos,const uint32_t & color,bool isNV12)933 static void Yuv420SPWritePixel(uint8_t *srcPixels, const YUVDataInfo &yuvDataInfo, const Position &pos,
934     const uint32_t &color, bool isNV12)
935 {
936     uint8_t *srcY = srcPixels + yuvDataInfo.yOffset;
937     uint8_t *srcUV = srcPixels + yuvDataInfo.uvOffset;
938     uint8_t colorY = (color >> Y_SHIFT) & YUV_MASK;
939     uint8_t colorU = (color >> U_SHIFT) & YUV_MASK;
940     uint8_t colorV = (color >> V_SHIFT) & YUV_MASK;
941 
942     *(srcY + (pos.y * yuvDataInfo.yStride + pos.x)) = colorY;
943     int32_t newX = pos.x / NUM_2 * NUM_2;
944     if (isNV12) {
945         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + newX) = colorU;
946         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + newX + 1) = colorV;
947     } else {
948         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + newX) = colorV;
949         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + newX + 1) = colorU;
950     }
951 }
952 
P010WritePixel(uint16_t * srcPixels,const YUVDataInfo & yuvDataInfo,const Position & pos,const uint32_t & color,bool isYCBCRP010)953 static void P010WritePixel(uint16_t *srcPixels, const YUVDataInfo &yuvDataInfo, const Position &pos,
954     const uint32_t &color, bool isYCBCRP010)
955 {
956     uint16_t *srcY = srcPixels + yuvDataInfo.yOffset;
957     uint16_t *srcUV = srcY + yuvDataInfo.uvOffset;
958     uint16_t colorY = (color >> Y_SHIFT) & YUV_MASK << 8;
959     uint16_t colorU = (color >> U_SHIFT) & YUV_MASK << 8;
960     uint16_t colorV = (color >> V_SHIFT) & YUV_MASK << 8;
961 
962     *(srcY + (pos.y * yuvDataInfo.yStride + pos.x)) = colorY;
963 
964     if (isYCBCRP010) {
965         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + pos.x / NUM_2) = colorU;
966         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + pos.x / NUM_2 + 1) = colorV;
967     } else {
968         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + pos.x / NUM_2) = colorV;
969         *(srcUV + (pos.y / NUM_2) * yuvDataInfo.uvStride + pos.x / NUM_2 + 1) = colorU;
970     }
971 }
972 
YuvWritePixel(uint8_t * srcPixels,const YUVDataInfo & yuvDataInfo,const PixelFormat & format,const Position & pos,const uint32_t & color)973 bool PixelYuvUtils::YuvWritePixel(uint8_t *srcPixels, const YUVDataInfo &yuvDataInfo, const PixelFormat &format,
974     const Position &pos, const uint32_t &color)
975 {
976     switch (format) {
977         case PixelFormat::NV21:
978         case PixelFormat::NV12: {
979             bool isNV12 = (format == PixelFormat::NV12) ? true : false;
980             Yuv420SPWritePixel(srcPixels, yuvDataInfo, pos, color, isNV12);
981             return true;
982         }
983         case PixelFormat::YCRCB_P010:
984         case PixelFormat::YCBCR_P010: {
985             bool isYCBCRP010 = (format == PixelFormat::YCBCR_P010) ? true : false;
986             P010WritePixel((uint16_t *)srcPixels, yuvDataInfo, pos, color, isYCBCRP010);
987             return true;
988         }
989         default:
990             return false;
991     }
992 }
993 
Yuv420SPTranslate(const uint8_t * srcPixels,YUVDataInfo & yuvInfo,uint8_t * dstPixels,XYaxis & xyAxis,ImageInfo & info,YUVStrideInfo & strides)994 void PixelYuvUtils::Yuv420SPTranslate(const uint8_t *srcPixels, YUVDataInfo &yuvInfo,
995     uint8_t *dstPixels, XYaxis &xyAxis, ImageInfo &info, YUVStrideInfo &strides)
996 {
997     const uint8_t *srcY = srcPixels + yuvInfo.yOffset;
998     const uint8_t *srcUV = srcPixels + yuvInfo.uvOffset;
999     uint8_t *dstY = dstPixels;
1000     uint8_t *dstUV = dstPixels + strides.uvOffset;
1001 
1002     int32_t yCopySize = info.size.width;
1003     int32_t yCopyLine = info.size.height;
1004     uint8_t *dst = nullptr;
1005     const uint8_t *src = nullptr;
1006     for (int32_t y = 0; y < yCopyLine ; y++) {
1007         int32_t newY = y + xyAxis.yAxis;
1008         dst = dstY + newY * static_cast<int32_t>(strides.yStride) + static_cast<int32_t>(xyAxis.xAxis);
1009         src = srcY + y * static_cast<int32_t>(yuvInfo.yStride);
1010         memcpy_s(dst, yCopySize, src, yCopySize);
1011     }
1012     int32_t xOffset = ((int32_t)xyAxis.xAxis % EVEN == 0) ?  xyAxis.xAxis : xyAxis.xAxis - 1;
1013     int32_t uvWidth = (info.size.width + ODD) / EVEN * EVEN;
1014     int32_t uvHeight = (static_cast<int32_t>(yuvInfo.uvHeight) != 0) ? static_cast<int32_t>(yuvInfo.uvHeight)
1015         : ((info.size.height + ODD) / EVEN);
1016     int32_t uvCopySize = uvWidth;
1017     int32_t uvCopyLine = uvHeight;
1018     for (int32_t y = 0; y<uvCopyLine ; y++) {
1019         int32_t newY = (y + xyAxis.yAxis / EVEN);
1020         dst = dstUV+ newY * static_cast<int32_t>(strides.uvStride) + xOffset;
1021         src = srcUV + y * static_cast<int32_t>(yuvInfo.uvStride);
1022         memcpy_s(dst, uvCopySize,  src, uvCopySize);
1023     }
1024 }
1025 
P010Translate(YuvPixelsP010Translate yuvPixels,YUVDataInfo & yuvInfo,XYaxis & xyAxis,ImageInfo & info,YUVStrideInfo & strides)1026 static void P010Translate(YuvPixelsP010Translate yuvPixels, YUVDataInfo &yuvInfo,
1027     XYaxis &xyAxis, ImageInfo &info, YUVStrideInfo &strides)
1028 {
1029     const uint16_t *srcY = yuvPixels.srcPixels + yuvInfo.yOffset;
1030     const uint16_t *srcUV = yuvPixels.srcPixels + yuvInfo.uvOffset;
1031     uint16_t *dstY = yuvPixels.dstPixels;
1032     uint16_t *dstUV = yuvPixels.dstPixels + strides.uvOffset;
1033 
1034     for (int32_t y = 0; y < info.size.height; y++) {
1035         for (int32_t x = 0; x < info.size.width; x++) {
1036             int32_t newX = x + xyAxis.xAxis;
1037             int32_t newY = y + xyAxis.yAxis;
1038             if (newX >= 0 && newY >= 0 && newX < static_cast<int32_t>(info.size.width + xyAxis.xAxis) &&
1039                 newY < static_cast<int32_t>(info.size.height + xyAxis.yAxis)) {
1040                 *(dstY + newY * static_cast<int32_t>(strides.yStride) + newX) =
1041                     *(srcY + y * static_cast<int32_t>(yuvInfo.yStride) + x);
1042             }
1043         }
1044     }
1045 
1046     for (int32_t y = 0; y < GetUVHeight(yuvInfo.yHeight); y++) {
1047         for (int32_t x = 0; x < GetUVStride(yuvInfo.yWidth); x += NUM_2) {
1048             int32_t newX = x + GetUVStride(xyAxis.xAxis);
1049             int32_t newY = y + GetUVHeight(xyAxis.yAxis);
1050             if (newX >= 0 && newX < GetUVStride(strides.yStride + xyAxis.xAxis) && newY >= 0 &&
1051                 newY < GetUVHeight(yuvInfo.yHeight + xyAxis.yAxis)) {
1052                 *(dstUV + newY * static_cast<int32_t>(strides.yStride) + newX) =
1053                     *(srcUV + y * static_cast<int32_t>(yuvInfo.yStride) + x);
1054                 *(dstUV + newY * static_cast<int32_t>(strides.yStride) + newX + 1) =
1055                     *(srcUV + y * static_cast<int32_t>(yuvInfo.yStride) + x + 1);
1056             }
1057         }
1058     }
1059 }
1060 
IsLegalAxis(float xAxis,float yAxis,ImageInfo & imageInfo_)1061 bool PixelYuvUtils::IsLegalAxis(float xAxis, float yAxis, ImageInfo &imageInfo_)
1062 {
1063     if (abs(xAxis) > static_cast<float>(INT32_MAX) ||
1064         abs(yAxis) > static_cast<float>(INT32_MAX)) {
1065         IMAGE_LOGE("translate axis overflow xAxis(%{public}f), yAxis(%{public}f)", xAxis, yAxis);
1066         return false;
1067     }
1068     if (!std::isfinite(xAxis) || !std::isfinite(yAxis)) {
1069         IMAGE_LOGE("translate axis not finite");
1070         return false;
1071     }
1072     int32_t xOffset = static_cast<int32_t>(xAxis);
1073     int32_t yOffset = static_cast<int32_t>(yAxis);
1074     if (imageInfo_.size.width > INT32_MAX - xOffset) {
1075         IMAGE_LOGE("translate width overflow width(%{public}d) + xOffset(%{public}d)",
1076             imageInfo_.size.width, xOffset);
1077         return false;
1078     }
1079     if (imageInfo_.size.height > INT32_MAX - yOffset) {
1080         IMAGE_LOGE("translate height overflow height(%{public}d) + yOffset(%{public}d)",
1081             imageInfo_.size.height, yOffset);
1082         return false;
1083     }
1084     if (xOffset == 0 && yOffset == 0) {
1085         return false;
1086     }
1087     int32_t width = imageInfo_.size.width + xOffset;
1088     int32_t height = imageInfo_.size.height + yOffset;
1089     if (width < 1 || height < 1 || width > MAX_DIMENSION || height > MAX_DIMENSION) {
1090         IMAGE_LOGE("Checktranslate size overflow width(%{public}d), height(%{public}d)", width, height);
1091         return false;
1092     }
1093     return true;
1094 }
1095 
YuvTranslate(const uint8_t * srcPixels,YUVDataInfo & yuvInfo,uint8_t * dstPixels,XYaxis & xyAxis,ImageInfo & info,YUVStrideInfo & dstStrides)1096 bool PixelYuvUtils::YuvTranslate(const uint8_t *srcPixels, YUVDataInfo &yuvInfo, uint8_t *dstPixels, XYaxis &xyAxis,
1097     ImageInfo &info, YUVStrideInfo &dstStrides)
1098 {
1099     if (!IsLegalAxis(xyAxis.xAxis, xyAxis.yAxis, info)) {
1100         return false;
1101     }
1102     switch (info.pixelFormat) {
1103         case PixelFormat::NV21:
1104         case PixelFormat::NV12: {
1105             Yuv420SPTranslate(srcPixels, yuvInfo, dstPixels, xyAxis, info, dstStrides);
1106             return true;
1107         }
1108         case PixelFormat::YCBCR_P010:
1109         case PixelFormat::YCRCB_P010: {
1110             YuvPixelsP010Translate yuvPixels = {(uint16_t *)srcPixels, (uint16_t *)dstPixels};
1111             P010Translate(yuvPixels, yuvInfo, xyAxis, info, dstStrides);
1112             return true;
1113         }
1114         default:
1115             return false;
1116     }
1117 }
1118 
CheckWidthAndHeightMult(const int32_t & width,const int32_t & height,const int32_t & multiples)1119 bool PixelYuvUtils::CheckWidthAndHeightMult(const int32_t &width, const int32_t &height, const int32_t &multiples)
1120 {
1121     if (width < 1 || height < 1 || multiples < 1) {
1122         return false;
1123     }
1124     if (width > (INT32_MAX / height) / multiples) {
1125         return false;
1126     }
1127     return true;
1128 }
1129 
1130 } // namespace Media
1131 } // namespace OHOS