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