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 to ive image.
47 * Copy the data pointer, do not copy the data.
48 */
FrmToOrigImg(const VIDEO_FRAME_INFO_S * frm,IVE_IMAGE_S * img)49 int FrmToOrigImg(const VIDEO_FRAME_INFO_S* frm, IVE_IMAGE_S *img)
50 {
51 static const int chnNum = 2; // Currently only supports YUV420/422, so only the addresses of 2 channels are copied
52 PIXEL_FORMAT_E pixelFormat = frm->stVFrame.enPixelFormat;
53
54 if (memset_s(img, sizeof(*img), 0, sizeof(*img)) != EOK) {
55 HI_ASSERT(0);
56 }
57
58 img->u32Width = frm->stVFrame.u32Width;
59 img->u32Height = frm->stVFrame.u32Height;
60
61 if (pixelFormat == PIXEL_FORMAT_YVU_SEMIPLANAR_420) {
62 img->enType = IVE_IMAGE_TYPE_YUV420SP;
63 } else if (pixelFormat == PIXEL_FORMAT_YVU_SEMIPLANAR_422) {
64 img->enType = IVE_IMAGE_TYPE_YUV422SP;
65 } else {
66 HI_ASSERT(0);
67 return -1;
68 }
69
70 for (int i = 0; i < chnNum; i++) {
71 img->au64PhyAddr[i] = frm->stVFrame.u64PhyAddr[i];
72 img->au64VirAddr[i] = frm->stVFrame.u64VirAddr[i];
73 img->au32Stride[i] = frm->stVFrame.u32Stride[i];
74 }
75 return 0;
76 }
77
78 /* Calculate the stride of a channel */
IveCalStride(IVE_IMAGE_TYPE_E enType,uint32_t width,AlignType align)79 static uint32_t IveCalStride(IVE_IMAGE_TYPE_E enType, uint32_t width, AlignType align)
80 {
81 uint32_t size = 1;
82
83 switch (enType) {
84 case IVE_IMAGE_TYPE_U8C1:
85 case IVE_IMAGE_TYPE_S8C1:
86 case IVE_IMAGE_TYPE_S8C2_PACKAGE:
87 case IVE_IMAGE_TYPE_S8C2_PLANAR:
88 case IVE_IMAGE_TYPE_U8C3_PACKAGE:
89 case IVE_IMAGE_TYPE_U8C3_PLANAR:
90 size = sizeof(HI_U8);
91 break;
92 case IVE_IMAGE_TYPE_S16C1:
93 case IVE_IMAGE_TYPE_U16C1:
94 size = sizeof(HI_U16);
95 break;
96 case IVE_IMAGE_TYPE_S32C1:
97 case IVE_IMAGE_TYPE_U32C1:
98 size = sizeof(uint32_t);
99 break;
100 case IVE_IMAGE_TYPE_S64C1:
101 case IVE_IMAGE_TYPE_U64C1:
102 size = sizeof(uint64_t);
103 break;
104 default:
105 break;
106 }
107
108 if (align == ALIGN_TYPE_16) {
109 return HiAlign16(width * size);
110 } else if (align == ALIGN_TYPE_32) {
111 return HiAlign32(width * size);
112 } else {
113 HI_ASSERT(0);
114 return 0;
115 }
116 }
117
118 /* Create ive image buffer based on type and size */
IveImgCreate(IVE_IMAGE_S * img,IVE_IMAGE_TYPE_E enType,uint32_t width,uint32_t height)119 int IveImgCreate(IVE_IMAGE_S* img,
120 IVE_IMAGE_TYPE_E enType, uint32_t width, uint32_t height)
121 {
122 HI_ASSERT(img);
123 uint32_t oneChnSize;
124 uint32_t size;
125 int ret;
126
127 if (memset_s(img, sizeof(*img), 0, sizeof(*img)) != EOK) {
128 HI_ASSERT(0);
129 }
130 img->enType = enType;
131 img->u32Width = width;
132 img->u32Height = height;
133 img->au32Stride[0] = IveCalStride(img->enType, img->u32Width, ALIGN_TYPE_16);
134
135 switch (enType) {
136 case IVE_IMAGE_TYPE_U8C1:
137 case IVE_IMAGE_TYPE_S8C1: // Only 1 channel
138 size = img->au32Stride[0] * img->u32Height;
139 ret = HI_MPI_SYS_MmzAlloc(&img->au64PhyAddr[0], (void**)&img->au64VirAddr[0], NULL, NULL, size);
140 SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != ret, ret, "Error(%#x), HI_MPI_SYS_MmzAlloc!\n", ret);
141 break;
142 // The size is equivalent to 1.5 times (3/2) of the pixel, which is equivalent to 2 channels
143 case IVE_IMAGE_TYPE_YUV420SP:
144 // The size is equivalent to 2 times the pixel, which is equivalent to 2 channels
145 case IVE_IMAGE_TYPE_YUV422SP:
146 if (enType == IVE_IMAGE_TYPE_YUV420SP) {
147 size = img->au32Stride[0] * img->u32Height * THREE_TIMES / TWO_TIMES;
148 } else {
149 size = img->au32Stride[0] * img->u32Height * TWO_TIMES;
150 }
151 ret = HI_MPI_SYS_MmzAlloc(&img->au64PhyAddr[0], (void**)&img->au64VirAddr[0], NULL, NULL, size);
152 SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != ret, ret, "Error(%#x), HI_MPI_SYS_MmzAlloc!\n", ret);
153
154 // Set the stride of the address of channel 1, both of which require channel 1
155 img->au32Stride[1] = img->au32Stride[0];
156 img->au64PhyAddr[1] = img->au64PhyAddr[0] + img->au32Stride[0] * (uint64_t)img->u32Height;
157 img->au64VirAddr[1] = img->au64VirAddr[0] + img->au32Stride[0] * (uint64_t)img->u32Height;
158 break;
159
160 case IVE_IMAGE_TYPE_U8C3_PLANAR: // 3 channels, often used for RGB
161 oneChnSize = img->au32Stride[0] * img->u32Height;
162 size = oneChnSize * 3; // 3 channels have the same size
163 ret = HI_MPI_SYS_MmzAlloc(&img->au64PhyAddr[0], (void**)&img->au64VirAddr[0], NULL, NULL, size);
164 SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != ret, ret, "Error(%#x), HI_MPI_SYS_MmzAlloc!\n", ret);
165
166 // Set the address and stride of channel 1 and channel 2
167 img->au64VirAddr[1] = img->au64VirAddr[0] + oneChnSize;
168 img->au64PhyAddr[1] = img->au64PhyAddr[0] + oneChnSize;
169 img->au32Stride[1] = img->au32Stride[0];
170 img->au64VirAddr[2] = img->au64VirAddr[1] + oneChnSize; // 2: au64VirAddr array subscript, not out of bounds
171 img->au64PhyAddr[2] = img->au64PhyAddr[1] + oneChnSize; // 2: au64VirAddr array subscript, not out of bounds
172 img->au32Stride[2] = img->au32Stride[0]; // 2: au64VirAddr array subscript, not out of bounds
173 break;
174
175 // Types not currently supported: YVC420P, YUV422P, S8C2_PACKAGE, S8C2_PLANAR,
176 // S32C1, U32C1, S64C1, U64C1, S16C1, U16C1, U8C3_PACKAGE,etc.
177 default:
178 HI_ASSERT(0);
179 break;
180 }
181 return HI_SUCCESS;
182 }
183
ImgYuvCrop(const IVE_IMAGE_S * src,IVE_IMAGE_S * dst,const RectBox * origBox)184 int ImgYuvCrop(const IVE_IMAGE_S *src, IVE_IMAGE_S *dst, const RectBox* origBox)
185 {
186 RectBox box = *origBox;
187 int boxWidth = box.xmax - box.xmin;
188 int boxHeight = box.ymax - box.ymin;
189 int ret;
190
191 HI_ASSERT(boxWidth > 0 && boxWidth <= src->u32Width);
192 HI_ASSERT(boxHeight > 0 && boxHeight <= src->u32Height);
193 HI_ASSERT(src->au64VirAddr[0]);
194 HI_ASSERT(src->au32Stride[0] >= src->u32Width);
195
196 // Adjust the width/height of the box to a multiple of 2
197 if (boxWidth == 1 || boxHeight == 1) {
198 SAMPLE_PRT("box dstWidth=1 && dstHeight=1\n");
199 return -1;
200 }
201 if (boxWidth % HI_OVEN_BASE) {
202 box.xmax--;
203 boxWidth--;
204 }
205 if (boxHeight % HI_OVEN_BASE) {
206 box.ymax--;
207 boxHeight--;
208 }
209 // Create empty dst img
210 ret = IveImgCreate(dst, src->enType, boxWidth, boxHeight);
211 HI_ASSERT(!ret);
212 // Use IVE DMA to copy to improve performance
213 // copy box from src to dst
214 // Y
215 int srcStrideY = src->au32Stride[0];
216 int dstStrideY = dst->au32Stride[0];
217 uint8_t *srcBufY = (uint8_t*)((uintptr_t)src->au64VirAddr[0]);
218 uint8_t *dstBufY = (uint8_t*)((uintptr_t)dst->au64VirAddr[0]);
219 uint8_t *srcPtrY = &srcBufY[box.ymin * srcStrideY];
220 uint8_t *dstPtrY = dstBufY;
221 for (int h = 0; h < boxHeight; h++, srcPtrY += srcStrideY, dstPtrY += dstStrideY) {
222 if (memcpy_s(dstPtrY, boxWidth, srcPtrY + box.xmin, boxWidth) != EOK) {
223 HI_ASSERT(0);
224 }
225 }
226 HI_ASSERT(dstPtrY - dstBufY == boxHeight * dstStrideY);
227
228 // UV
229 int srcStrideUV = src->au32Stride[1];
230 int dstStrideUV = dst->au32Stride[1];
231 uint8_t *srcBufUV = (uint8_t*)((uintptr_t)src->au64VirAddr[1]);
232 uint8_t *dstBufUV = (uint8_t*)((uintptr_t)dst->au64VirAddr[1]);
233 uint8_t *srcPtrUV = &srcBufUV[(box.ymin / HALF_THE_HEIGHT) * srcStrideUV];
234 uint8_t *dstPtrUV = dstBufUV;
235 for (int h = 0; h < (boxHeight / HALF_THE_HEIGHT);
236 h++, srcPtrUV += srcStrideUV, dstPtrUV += dstStrideUV) {
237 if (memcpy_s(dstPtrUV, boxWidth, srcPtrUV + box.xmin, boxWidth) != EOK) {
238 HI_ASSERT(0);
239 }
240 }
241 HI_ASSERT(dstPtrUV - dstBufUV == (boxHeight / HALF_THE_HEIGHT) * dstStrideUV);
242
243 return ret;
244 }
245
246 /* Destory ive Image */
IveImgDestroy(IVE_IMAGE_S * img)247 void IveImgDestroy(IVE_IMAGE_S* img)
248 {
249 for (int i = 0; i < IMG_FULL_CHN; i++) {
250 if (img->au64PhyAddr[0] && img->au64VirAddr[0]) {
251 HI_MPI_SYS_MmzFree(img->au64PhyAddr[i], (void*)((uintptr_t)img->au64VirAddr[i]));
252 img->au64PhyAddr[i] = 0;
253 img->au64VirAddr[i] = 0;
254 }
255 }
256 if (memset_s(img, sizeof(*img), 0, sizeof(*img)) != EOK) {
257 HI_ASSERT(0);
258 }
259 }
260
OrigImgToFrm(const IVE_IMAGE_S * img,VIDEO_FRAME_INFO_S * frm)261 int OrigImgToFrm(const IVE_IMAGE_S *img, VIDEO_FRAME_INFO_S* frm)
262 {
263 static const int chnNum = 2;
264 IVE_IMAGE_TYPE_E enType = img->enType;
265 if (memset_s(frm, sizeof(*frm), 0, sizeof(*frm)) != EOK) {
266 HI_ASSERT(0);
267 }
268
269 frm->stVFrame.u32Width = img->u32Width;
270 frm->stVFrame.u32Height = img->u32Height;
271
272 if (enType == IVE_IMAGE_TYPE_YUV420SP) {
273 frm->stVFrame.enPixelFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
274 } else if (enType == IVE_IMAGE_TYPE_YUV422SP) {
275 frm->stVFrame.enPixelFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_422;
276 } else {
277 HI_ASSERT(0);
278 return -1;
279 }
280
281 for (int i = 0; i < chnNum; i++) {
282 frm->stVFrame.u64PhyAddr[i] = img->au64PhyAddr[i];
283 frm->stVFrame.u64VirAddr[i] = img->au64VirAddr[i];
284 frm->stVFrame.u32Stride[i] = img->au32Stride[i];
285 }
286 return 0;
287 }
288
289 #ifdef __cplusplus
290 #if __cplusplus
291 }
292 #endif
293 #endif /* End of #ifdef __cplusplus */
294