1 /*
2 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 <stdlib.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <stdbool.h>
20 #include <errno.h>
21 #include <unistd.h>
22
23 #include "hi_comm_vb.h"
24 #include "mpi_sys.h"
25 #include "ive_img.h"
26
27 #ifdef __cplusplus
28 #if __cplusplus
29 extern "C" {
30 #endif
31 #endif /* End of #ifdef __cplusplus */
32
33 #define HALF_THE_HEIGHT 2 // Half the height
34
HiAlign16(HI_U32 num)35 HI_U32 HiAlign16(HI_U32 num)
36 {
37 return (((num) + 16 - 1) / 16 * 16); // 16: align 16
38 }
39
HiAlign32(HI_U32 num)40 HI_U32 HiAlign32(HI_U32 num)
41 {
42 return (((num) + 32 - 1) / 32 * 32); // 32: align 32
43 }
44
45 /*
46 * VIDEO_FRAME_INFO_S格式转换成IVE_IMAGE_S格式
47 * 复制数据指针,不复制数据
48 *
49 * video frame to ive image.
50 * Copy the data pointer, do not copy the data.
51 */
FrmToOrigImg(const VIDEO_FRAME_INFO_S * frm,IVE_IMAGE_S * img)52 int FrmToOrigImg(const VIDEO_FRAME_INFO_S* frm, IVE_IMAGE_S *img)
53 {
54 static const int chnNum = 2; // Currently only supports YUV420/422, so only the addresses of 2 channels are copied
55 PIXEL_FORMAT_E pixelFormat = frm->stVFrame.enPixelFormat;
56
57 if (memset_s(img, sizeof(*img), 0, sizeof(*img)) != EOK) {
58 HI_ASSERT(0);
59 }
60
61 img->u32Width = frm->stVFrame.u32Width;
62 img->u32Height = frm->stVFrame.u32Height;
63
64 if (pixelFormat == PIXEL_FORMAT_YVU_SEMIPLANAR_420) {
65 img->enType = IVE_IMAGE_TYPE_YUV420SP;
66 } else if (pixelFormat == PIXEL_FORMAT_YVU_SEMIPLANAR_422) {
67 img->enType = IVE_IMAGE_TYPE_YUV422SP;
68 } else {
69 HI_ASSERT(0);
70 return -1;
71 }
72
73 for (int i = 0; i < chnNum; i++) {
74 img->au64PhyAddr[i] = frm->stVFrame.u64PhyAddr[i];
75 img->au64VirAddr[i] = frm->stVFrame.u64VirAddr[i];
76 img->au32Stride[i] = frm->stVFrame.u32Stride[i];
77 }
78 return 0;
79 }
80
81 /*
82 * 计算通道的步长
83 * Calculate the stride of a channel
84 */
IveCalStride(IVE_IMAGE_TYPE_E enType,uint32_t width,AlignType align)85 static uint32_t IveCalStride(IVE_IMAGE_TYPE_E enType, uint32_t width, AlignType align)
86 {
87 uint32_t size = 1;
88
89 switch (enType) {
90 case IVE_IMAGE_TYPE_U8C1:
91 case IVE_IMAGE_TYPE_S8C1:
92 case IVE_IMAGE_TYPE_S8C2_PACKAGE:
93 case IVE_IMAGE_TYPE_S8C2_PLANAR:
94 case IVE_IMAGE_TYPE_U8C3_PACKAGE:
95 case IVE_IMAGE_TYPE_U8C3_PLANAR:
96 size = sizeof(HI_U8);
97 break;
98 case IVE_IMAGE_TYPE_S16C1:
99 case IVE_IMAGE_TYPE_U16C1:
100 size = sizeof(HI_U16);
101 break;
102 case IVE_IMAGE_TYPE_S32C1:
103 case IVE_IMAGE_TYPE_U32C1:
104 size = sizeof(uint32_t);
105 break;
106 case IVE_IMAGE_TYPE_S64C1:
107 case IVE_IMAGE_TYPE_U64C1:
108 size = sizeof(uint64_t);
109 break;
110 default:
111 break;
112 }
113
114 if (align == ALIGN_TYPE_16) {
115 return HiAlign16(width * size);
116 } else if (align == ALIGN_TYPE_32) {
117 return HiAlign32(width * size);
118 } else {
119 HI_ASSERT(0);
120 return 0;
121 }
122 }
123
124 /*
125 * 根据类型和大小创建缓存
126 * Create ive image buffer based on type and size
127 */
IveImgCreate(IVE_IMAGE_S * img,IVE_IMAGE_TYPE_E enType,uint32_t width,uint32_t height)128 int IveImgCreate(IVE_IMAGE_S* img,
129 IVE_IMAGE_TYPE_E enType, uint32_t width, uint32_t height)
130 {
131 HI_ASSERT(img);
132 uint32_t oneChnSize;
133 uint32_t size;
134 int ret;
135
136 if (memset_s(img, sizeof(*img), 0, sizeof(*img)) != EOK) {
137 HI_ASSERT(0);
138 }
139 img->enType = enType;
140 img->u32Width = width;
141 img->u32Height = height;
142 img->au32Stride[0] = IveCalStride(img->enType, img->u32Width, ALIGN_TYPE_16);
143
144 switch (enType) {
145 case IVE_IMAGE_TYPE_U8C1:
146 case IVE_IMAGE_TYPE_S8C1: // Only 1 channel
147 size = img->au32Stride[0] * img->u32Height;
148 ret = HI_MPI_SYS_MmzAlloc(&img->au64PhyAddr[0], (void**)&img->au64VirAddr[0], NULL, NULL, size);
149 SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != ret, ret, "Error(%#x), HI_MPI_SYS_MmzAlloc!\n", ret);
150 break;
151 /*
152 * 大小相当于像素的1.5倍(3/2), 相当于2个通道
153 * The size is equivalent to 1.5 times (3/2) of the pixel, which is equivalent to 2 channels
154 */
155 case IVE_IMAGE_TYPE_YUV420SP:
156 /*
157 * 大小相当于像素的2倍,相当于2个通道
158 * The size is equivalent to 2 times the pixel, which is equivalent to 2 channels
159 */
160 case IVE_IMAGE_TYPE_YUV422SP:
161 if (enType == IVE_IMAGE_TYPE_YUV420SP) {
162 size = img->au32Stride[0] * img->u32Height * THREE_TIMES / TWO_TIMES;
163 } else {
164 size = img->au32Stride[0] * img->u32Height * TWO_TIMES;
165 }
166 ret = HI_MPI_SYS_MmzAlloc(&img->au64PhyAddr[0], (void**)&img->au64VirAddr[0], NULL, NULL, size);
167 SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != ret, ret, "Error(%#x), HI_MPI_SYS_MmzAlloc!\n", ret);
168
169 /*
170 * 设置通道1地址的步长,两者都需要通道1
171 * Set the stride of the address of channel 1, both of which require channel 1
172 */
173 img->au32Stride[1] = img->au32Stride[0];
174 img->au64PhyAddr[1] = img->au64PhyAddr[0] + img->au32Stride[0] * (uint64_t)img->u32Height;
175 img->au64VirAddr[1] = img->au64VirAddr[0] + img->au32Stride[0] * (uint64_t)img->u32Height;
176 break;
177
178 case IVE_IMAGE_TYPE_U8C3_PLANAR: // 3 channels, often used for RGB
179 oneChnSize = img->au32Stride[0] * img->u32Height;
180 size = oneChnSize * 3; // 3 channels have the same size
181 ret = HI_MPI_SYS_MmzAlloc(&img->au64PhyAddr[0], (void**)&img->au64VirAddr[0], NULL, NULL, size);
182 SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != ret, ret, "Error(%#x), HI_MPI_SYS_MmzAlloc!\n", ret);
183
184 /*
185 * 设置通道1和通道2的地址和步长
186 * Set the address and stride of channel 1 and channel 2
187 */
188 img->au64VirAddr[1] = img->au64VirAddr[0] + oneChnSize;
189 img->au64PhyAddr[1] = img->au64PhyAddr[0] + oneChnSize;
190 img->au32Stride[1] = img->au32Stride[0];
191 img->au64VirAddr[2] = img->au64VirAddr[1] + oneChnSize; // 2: au64VirAddr array subscript, not out of bounds
192 img->au64PhyAddr[2] = img->au64PhyAddr[1] + oneChnSize; // 2: au64VirAddr array subscript, not out of bounds
193 img->au32Stride[2] = img->au32Stride[0]; // 2: au64VirAddr array subscript, not out of bounds
194 break;
195
196 /*
197 * 目前如下格式不支持,主要为YVC420P, YUV422P, S8C2_PACKAGE, S8C2_PLANAR,
198 * S32C1, U32C1, S64C1, U64C1, S16C1, U16C1, U8C3_PACKAGE等
199 *
200 * Types not currently supported: YVC420P, YUV422P, S8C2_PACKAGE, S8C2_PLANAR,
201 * S32C1, U32C1, S64C1, U64C1, S16C1, U16C1, U8C3_PACKAGE,etc.
202 */
203 default:
204 HI_ASSERT(0);
205 break;
206 }
207 return HI_SUCCESS;
208 }
209
ImgYuvCrop(const IVE_IMAGE_S * src,IVE_IMAGE_S * dst,const RectBox * origBox)210 int ImgYuvCrop(const IVE_IMAGE_S *src, IVE_IMAGE_S *dst, const RectBox* origBox)
211 {
212 RectBox box = *origBox;
213 int boxWidth = box.xmax - box.xmin;
214 int boxHeight = box.ymax - box.ymin;
215 int ret;
216
217 HI_ASSERT(boxWidth > 0 && boxWidth <= src->u32Width);
218 HI_ASSERT(boxHeight > 0 && boxHeight <= src->u32Height);
219 HI_ASSERT(src->au64VirAddr[0]);
220 HI_ASSERT(src->au32Stride[0] >= src->u32Width);
221
222 /*
223 * 将框的宽度/高度调整为 2 的倍数
224 * Adjust the width/height of the box to a multiple of 2
225 */
226 if (boxWidth == 1 || boxHeight == 1) {
227 SAMPLE_PRT("box dstWidth=1 && dstHeight=1\n");
228 return -1;
229 }
230 if (boxWidth % HI_OVEN_BASE) {
231 box.xmax--;
232 boxWidth--;
233 }
234 if (boxHeight % HI_OVEN_BASE) {
235 box.ymax--;
236 boxHeight--;
237 }
238
239 ret = IveImgCreate(dst, src->enType, boxWidth, boxHeight);
240 HI_ASSERT(!ret);
241
242 /*
243 * 将框从源地址复制到目的地址
244 * copy box from src to dst
245 */
246 /*
247 * Y分量
248 * Y component
249 */
250 int srcStrideY = src->au32Stride[0];
251 int dstStrideY = dst->au32Stride[0];
252 uint8_t *srcBufY = (uint8_t*)((uintptr_t)src->au64VirAddr[0]);
253 uint8_t *dstBufY = (uint8_t*)((uintptr_t)dst->au64VirAddr[0]);
254 uint8_t *srcPtrY = &srcBufY[box.ymin * srcStrideY];
255 uint8_t *dstPtrY = dstBufY;
256 for (int h = 0; h < boxHeight; h++, srcPtrY += srcStrideY, dstPtrY += dstStrideY) {
257 if (memcpy_s(dstPtrY, boxWidth, srcPtrY + box.xmin, boxWidth) != EOK) {
258 HI_ASSERT(0);
259 }
260 }
261 HI_ASSERT(dstPtrY - dstBufY == boxHeight * dstStrideY);
262
263 /*
264 * UV分量
265 * UV component
266 */
267 int srcStrideUV = src->au32Stride[1];
268 int dstStrideUV = dst->au32Stride[1];
269 uint8_t *srcBufUV = (uint8_t*)((uintptr_t)src->au64VirAddr[1]);
270 uint8_t *dstBufUV = (uint8_t*)((uintptr_t)dst->au64VirAddr[1]);
271 uint8_t *srcPtrUV = &srcBufUV[(box.ymin / HALF_THE_HEIGHT) * srcStrideUV];
272 uint8_t *dstPtrUV = dstBufUV;
273 for (int h = 0; h < (boxHeight / HALF_THE_HEIGHT);
274 h++, srcPtrUV += srcStrideUV, dstPtrUV += dstStrideUV) {
275 if (memcpy_s(dstPtrUV, boxWidth, srcPtrUV + box.xmin, boxWidth) != EOK) {
276 HI_ASSERT(0);
277 }
278 }
279 HI_ASSERT(dstPtrUV - dstBufUV == (boxHeight / HALF_THE_HEIGHT) * dstStrideUV);
280
281 return ret;
282 }
283
284 /*
285 * 销毁ive image
286 * Destory ive image
287 */
IveImgDestroy(IVE_IMAGE_S * img)288 void IveImgDestroy(IVE_IMAGE_S* img)
289 {
290 for (int i = 0; i < IMG_FULL_CHN; i++) {
291 if (img->au64PhyAddr[0] && img->au64VirAddr[0]) {
292 HI_MPI_SYS_MmzFree(img->au64PhyAddr[i], (void*)((uintptr_t)img->au64VirAddr[i]));
293 img->au64PhyAddr[i] = 0;
294 img->au64VirAddr[i] = 0;
295 }
296 }
297 if (memset_s(img, sizeof(*img), 0, sizeof(*img)) != EOK) {
298 HI_ASSERT(0);
299 }
300 }
301
OrigImgToFrm(const IVE_IMAGE_S * img,VIDEO_FRAME_INFO_S * frm)302 int OrigImgToFrm(const IVE_IMAGE_S *img, VIDEO_FRAME_INFO_S* frm)
303 {
304 static const int chnNum = 2;
305 IVE_IMAGE_TYPE_E enType = img->enType;
306 if (memset_s(frm, sizeof(*frm), 0, sizeof(*frm)) != EOK) {
307 HI_ASSERT(0);
308 }
309
310 frm->stVFrame.u32Width = img->u32Width;
311 frm->stVFrame.u32Height = img->u32Height;
312
313 if (enType == IVE_IMAGE_TYPE_YUV420SP) {
314 frm->stVFrame.enPixelFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
315 } else if (enType == IVE_IMAGE_TYPE_YUV422SP) {
316 frm->stVFrame.enPixelFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_422;
317 } else {
318 HI_ASSERT(0);
319 return -1;
320 }
321
322 for (int i = 0; i < chnNum; i++) {
323 frm->stVFrame.u64PhyAddr[i] = img->au64PhyAddr[i];
324 frm->stVFrame.u64VirAddr[i] = img->au64VirAddr[i];
325 frm->stVFrame.u32Stride[i] = img->au32Stride[i];
326 }
327 return 0;
328 }
329
330 #ifdef __cplusplus
331 #if __cplusplus
332 }
333 #endif
334 #endif /* End of #ifdef __cplusplus */
335