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