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