• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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