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