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