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
21 #include "hi_comm_vb.h"
22 #include "hi_comm_vgs.h"
23 #include "hi_comm_region.h"
24 #include "mpi_sys.h"
25 #include "mpi_vgs.h"
26 #include "hi_buffer.h"
27
28 #include "misc_util.h"
29 #include "ai_infer_process.h"
30 #include "vgs_img.h"
31
32 #ifdef __cplusplus
33 #if __cplusplus
34 extern "C" {
35 #endif
36 #endif /* End of #ifdef __cplusplus */
37
38 #define VGS_MAX_LINE 100 // The maximum number of lines for a superimposed graphics operation
39 #define RECT_LINES 4 // The number of lines in a rectangle
40
41 #define RECT_LINE1 1
42 #define RECT_LINE2 2
43 #define RECT_LINE3 3
44
45 /* Set the buf of the frame */
MppFrmSetBuf(VIDEO_FRAME_INFO_S * frm,const VB_CAL_CONFIG_S * vbCfg,HI_U64 phyAddr,uint8_t * virAddr)46 static void MppFrmSetBuf(VIDEO_FRAME_INFO_S* frm,
47 const VB_CAL_CONFIG_S *vbCfg, HI_U64 phyAddr, uint8_t *virAddr)
48 {
49 // Currently only SP422/SP420 is supported, SP444 is not supported
50 frm->stVFrame.u32HeaderStride[0] = vbCfg->u32HeadStride;
51 frm->stVFrame.u32HeaderStride[1] = vbCfg->u32HeadStride;
52 frm->stVFrame.u32HeaderStride[2] = vbCfg->u32HeadStride; // 2: Array subscript, not out of bounds
53 frm->stVFrame.u64HeaderPhyAddr[0] = phyAddr;
54 frm->stVFrame.u64HeaderPhyAddr[1] = frm->stVFrame.u64HeaderPhyAddr[0] + vbCfg->u32HeadYSize;
55 frm->stVFrame.u64HeaderPhyAddr[2] = frm->stVFrame.u64HeaderPhyAddr[1]; // 2: Array subscript, not out of bounds
56 frm->stVFrame.u64HeaderVirAddr[0] = (HI_U64)(HI_UL)virAddr;
57 frm->stVFrame.u64HeaderVirAddr[1] = frm->stVFrame.u64HeaderVirAddr[0] + vbCfg->u32HeadYSize;
58 frm->stVFrame.u64HeaderVirAddr[2] = frm->stVFrame.u64HeaderVirAddr[1]; // 2: Array subscript, not out of bounds
59
60 frm->stVFrame.u32Stride[0] = vbCfg->u32MainStride;
61 frm->stVFrame.u32Stride[1] = vbCfg->u32MainStride;
62 frm->stVFrame.u32Stride[2] = vbCfg->u32MainStride; // 2: Array subscript, not out of bounds
63 frm->stVFrame.u64PhyAddr[0] = frm->stVFrame.u64HeaderPhyAddr[0] + vbCfg->u32HeadSize;
64 frm->stVFrame.u64PhyAddr[1] = frm->stVFrame.u64PhyAddr[0] + vbCfg->u32MainYSize;
65 frm->stVFrame.u64PhyAddr[2] = frm->stVFrame.u64PhyAddr[1]; // 2: Array subscript, not out of bounds
66 frm->stVFrame.u64VirAddr[0] = frm->stVFrame.u64HeaderVirAddr[0] + vbCfg->u32HeadSize;
67 frm->stVFrame.u64VirAddr[1] = frm->stVFrame.u64VirAddr[0] + vbCfg->u32MainYSize;
68 frm->stVFrame.u64VirAddr[2] = frm->stVFrame.u64VirAddr[1]; // 2: Array subscript, not out of bounds
69 }
70
71 /* Create an empty frame buf */
MppFrmCreate(VIDEO_FRAME_INFO_S * frm,int width,int height,PIXEL_FORMAT_E pixelFormat,DATA_BITWIDTH_E bitWidth,COMPRESS_MODE_E compressMode,int align)72 int MppFrmCreate(
73 VIDEO_FRAME_INFO_S* frm,
74 int width, int height,
75 PIXEL_FORMAT_E pixelFormat,
76 DATA_BITWIDTH_E bitWidth,
77 COMPRESS_MODE_E compressMode,
78 int align)
79 {
80 HI_ASSERT(frm);
81 VB_CAL_CONFIG_S vbCfg;
82
83 if (memset_s(frm, sizeof(*frm), 0, sizeof(*frm)) != EOK) {
84 HI_ASSERT(0);
85 }
86
87 HI_ASSERT(width > 0 && height > 0);
88 if ((int)pixelFormat < 0) {
89 pixelFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
90 }
91 if ((int)bitWidth < 0) {
92 bitWidth = DATA_BITWIDTH_8;
93 }
94 if ((int)compressMode < 0) {
95 compressMode = COMPRESS_MODE_NONE;
96 }
97 if (align < 0) {
98 HI_ASSERT(0);
99 }
100
101 COMMON_GetPicBufferConfig(width, height, pixelFormat, bitWidth, compressMode, align, &vbCfg);
102
103 VB_BLK vbHnd = HI_MPI_VB_GetBlock(VB_INVALID_POOLID, vbCfg.u32VBSize, NULL);
104 if (vbHnd == VB_INVALID_HANDLE) {
105 SAMPLE_PRT("HI_MPI_VB_GetBlock FAIL\n");
106 return HI_FAILURE;
107 }
108
109 HI_U64 phyAddr = HI_MPI_VB_Handle2PhysAddr(vbHnd);
110 HI_ASSERT(phyAddr);
111 uint8_t* virAddr = (uint8_t*)HI_MPI_SYS_Mmap(phyAddr, vbCfg.u32VBSize);
112 HI_ASSERT(virAddr);
113
114 /* u64PrivateData is used to store the length of the mapped memory area and vbHnd,
115 which will be used when destroying */
116 frm->stVFrame.u64PrivateData = ((uint64_t)(uint32_t)vbHnd) << HI_INT32_BITS;
117 frm->stVFrame.u64PrivateData |= (uint64_t)vbCfg.u32VBSize;
118
119 frm->enModId = HI_ID_VGS;
120 frm->u32PoolId = HI_MPI_VB_Handle2PoolId(vbHnd);
121
122 frm->stVFrame.u32Width = width;
123 frm->stVFrame.u32Height = height;
124 frm->stVFrame.enField = VIDEO_FIELD_FRAME;
125 frm->stVFrame.enPixelFormat = pixelFormat;
126 frm->stVFrame.enVideoFormat = VIDEO_FORMAT_LINEAR;
127 frm->stVFrame.enCompressMode = compressMode;
128 frm->stVFrame.enDynamicRange = DYNAMIC_RANGE_SDR8;
129 frm->stVFrame.enColorGamut = COLOR_GAMUT_BT601;
130
131 MppFrmSetBuf(frm, &vbCfg, phyAddr, virAddr);
132 return HI_SUCCESS;
133 }
134
135 /* Determine whether the frame is available. That is, whether the memory is allocated */
MppFrmValid(const VIDEO_FRAME_INFO_S * frm)136 bool MppFrmValid(const VIDEO_FRAME_INFO_S* frm)
137 {
138 // The frame output by VPSS does not map virtual addresses by default
139 return frm->stVFrame.u64PhyAddr[0];
140 }
141
142 /* Destory frame */
MppFrmDestroy(VIDEO_FRAME_INFO_S * frm)143 void MppFrmDestroy(VIDEO_FRAME_INFO_S* frm)
144 {
145 if (!MppFrmValid(frm)) {
146 return;
147 }
148
149 // u64PrivateData is used to store the length of the mapped memory area and vbHnd, which is set at create
150 uint32_t memSize = (uint32_t)(frm->stVFrame.u64PrivateData);
151 uint32_t vbHnd = (uint32_t)(frm->stVFrame.u64PrivateData >> HI_INT32_BITS);
152 HI_S32 ret;
153
154 ret = HI_MPI_SYS_Munmap((void*)(uintptr_t)frm->stVFrame.u64VirAddr[0], memSize);
155 HI_ASSERT(ret == HI_SUCCESS);
156 ret = HI_MPI_VB_ReleaseBlock(vbHnd);
157 HI_ASSERT(ret == HI_SUCCESS);
158 if (memset_s(frm, sizeof(*frm), 0, sizeof(*frm)) != EOK) {
159 HI_ASSERT(0);
160 }
161 }
162
163 /*
164 * Perform a VGS resize.
165 * The zoom factor of each VGS resize is limited. VGS supports zooming of an image.
166 * The width and height are both enlarged by 16 times and reduced by 30 times.Support single-component (Y) scaling.
167 */
VgsResizeOnce(const VIDEO_FRAME_INFO_S * src,VIDEO_FRAME_INFO_S * dst,uint32_t dstWidth,uint32_t dstHeight)168 static int VgsResizeOnce(const VIDEO_FRAME_INFO_S* src, VIDEO_FRAME_INFO_S* dst, uint32_t dstWidth, uint32_t dstHeight)
169 {
170 HI_ASSERT(src && dst);
171 HI_ASSERT(dstWidth > 0 && dstHeight > 0);
172 VGS_HANDLE jobHnd = -1;
173 VGS_TASK_ATTR_S task;
174 int ret;
175
176 ret = MppFrmCreate(dst, dstWidth, dstHeight, src->stVFrame.enPixelFormat, DATA_BITWIDTH_8,
177 src->stVFrame.enCompressMode, 0);
178 if (ret != 0) {
179 SAMPLE_PRT("frm resize FAIL, for create dstFrm FAIL\n");
180 return ret;
181 }
182
183 if (memset_s(&task, sizeof(task), 0, sizeof(task)) != EOK) {
184 HI_ASSERT(0);
185 }
186 task.stImgIn = *src;
187 task.stImgOut = *dst;
188
189 ret = HI_MPI_VGS_BeginJob(&jobHnd);
190 if (ret != 0) {
191 SAMPLE_PRT("HI_MPI_VGS_BeginJob FAIL, ret=%08X\n", ret);
192 if (jobHnd >= 0 && HI_MPI_VGS_CancelJob(jobHnd) != HI_SUCCESS) {
193 HI_ASSERT(0);
194 }
195 MppFrmDestroy(dst);
196 return ret;
197 }
198 HI_ASSERT(jobHnd >= 0);
199
200 ret = HI_MPI_VGS_AddScaleTask(jobHnd, &task, VGS_SCLCOEF_NORMAL);
201 if (ret != 0) {
202 SAMPLE_PRT("HI_MPI_VGS_AddScaleTask FAIL, ret=%08X\n", ret);
203 if (jobHnd >= 0 && HI_MPI_VGS_CancelJob(jobHnd) != HI_SUCCESS) {
204 HI_ASSERT(0);
205 }
206 MppFrmDestroy(dst);
207 return ret;
208 }
209
210 ret = HI_MPI_VGS_EndJob(jobHnd);
211 if (ret != 0) {
212 SAMPLE_PRT("HI_MPI_VGS_EndJob FAIL, ret=%08X\n", ret);
213 if (jobHnd >= 0 && HI_MPI_VGS_CancelJob(jobHnd) != HI_SUCCESS) {
214 HI_ASSERT(0);
215 }
216 MppFrmDestroy(dst);
217 return ret;
218 }
219 return 0;
220 }
221
222 /*
223 * resize frame.
224 * Call vgs_resize multiple times to achieve arbitrary scaling.
225 * In order to simplify the implementation, it is agreed that each zoom is up to 14 times,
226 * and at this time, the width and height only need to be aligned by 2 pixels.
227 * When the zoom directions are different in the two directions, for example,
228 * one direction (such as X) zooms in and the other direction zooms in, no special processing is required.
229 * At this time, the zoom ratio in one direction or both directions exceeds the standard,
230 * and no special treatment is required.
231 */
MppFrmResize(const VIDEO_FRAME_INFO_S * src,VIDEO_FRAME_INFO_S * dst,uint32_t dstWidth,uint32_t dstHeight)232 int MppFrmResize(
233 const VIDEO_FRAME_INFO_S* src,
234 VIDEO_FRAME_INFO_S* dst,
235 uint32_t dstWidth, uint32_t dstHeight)
236 {
237 static const double rateMax = 14.0; // Maximum magnification
238 static const double rateMin = 1.0 / rateMax; // The smallest magnification, that is, the largest reduction
239
240 uint32_t srcWidth = src->stVFrame.u32Width;
241 uint32_t srcHeight = src->stVFrame.u32Height;
242 HI_ASSERT(srcWidth > 0 && srcHeight > 0);
243 HI_ASSERT(!(srcWidth % HI_OVEN_BASE) && !(srcHeight % HI_OVEN_BASE));
244 HI_ASSERT(dstWidth > 0 && dstHeight > 0);
245 HI_ASSERT(!(dstWidth % HI_OVEN_BASE) && !(dstHeight % HI_OVEN_BASE));
246 int ret;
247
248 // magnification
249 double widthRate = ((double)dstWidth) / (double)srcWidth; // >1 means zoom in, <1 means zoom out
250 double heightRate = ((double)dstHeight) / (double)srcHeight; // >1 means zoom in, <1 means zoom out
251
252 // Separate processing according to zoom factor
253 if (widthRate > rateMax || widthRate < rateMin ||
254 heightRate > rateMax || heightRate < rateMin) {
255 // When the zoom factor exceeds the maximum value of one VGS, recursive processing...
256 uint32_t midWidth = (uint32_t)IntZoomTo((int)srcWidth, widthRate, rateMin, rateMax);
257 uint32_t midHeight = (uint32_t)IntZoomTo((int)srcHeight, heightRate, rateMin, rateMax);
258 /* Make sure it is an even number. When it is an odd number,
259 the zoom is reduced by one, otherwise it is increased by one */
260 if (midWidth % HI_OVEN_BASE) {
261 midWidth += widthRate > 1 ? -1 : 1;
262 }
263 if (midHeight % HI_OVEN_BASE) {
264 midHeight += heightRate > 1 ? -1 : 1;
265 }
266
267 SAMPLE_PRT("@@@ multi-lev vgs resize, src={%u, %u}, mid={%u, %u}, dst={%u, %u}, rate={%.4f, %.4f}\n",
268 srcWidth, srcHeight, midWidth, midHeight, dstWidth, dstHeight, widthRate, heightRate);
269
270 // Zoom once
271 VIDEO_FRAME_INFO_S midFrm;
272 ret = VgsResizeOnce(src, &midFrm, midWidth, midHeight);
273 if (ret != 0) {
274 SAMPLE_PRT("VgsResizeOnce(dw=%u, dh=%u) FAIL\n", midWidth, midHeight);
275 return ret;
276 }
277
278 // Recursively call midFrm as src
279 ret = MppFrmResize(&midFrm, dst, dstWidth, dstHeight);
280 MppFrmDestroy(&midFrm);
281 if (ret != 0) {
282 SAMPLE_PRT("sub call MppFrmResize(dw=%u, dh=%u) FAIL\n", dstWidth, dstHeight);
283 return ret;
284 }
285 } else { // The zoom factor does not exceed the maximum value of VGS once, and it is done directly
286 ret = VgsResizeOnce(src, dst, dstWidth, dstHeight);
287 if (ret != 0) {
288 SAMPLE_PRT("VgsResizeOnce(dw=%u, dh=%u) FAIL\n", dstWidth, dstHeight);
289 return ret;
290 }
291 }
292 return ret;
293 }
294
295 /* Round up integers to even numbers */
IntToOven(int x)296 static inline int IntToOven(int x)
297 {
298 if (x % HI_OVEN_BASE == 0) {
299 return x;
300 } else {
301 return x + 1;
302 }
303 }
304
305 /* Create and execute VGS draw lines job */
VgsDrawLines(VIDEO_FRAME_INFO_S * frm,const VGS_DRAW_LINE_S lines[],int lineNum)306 static HI_S32 VgsDrawLines(VIDEO_FRAME_INFO_S *frm, const VGS_DRAW_LINE_S lines[], int lineNum)
307 {
308 VGS_HANDLE jobHnd = -1;
309 VGS_TASK_ATTR_S task;
310 int ret;
311
312 if (memset_s(&task, sizeof(task), 0, sizeof(task)) != EOK) {
313 HI_ASSERT(0);
314 }
315 task.stImgIn = *frm;
316 task.stImgOut = *frm;
317
318 ret = HI_MPI_VGS_BeginJob(&jobHnd);
319 if (ret != 0) {
320 SAMPLE_PRT("HI_MPI_VGS_BeginJob FAIL, ret=%08X\n", ret);
321 if (jobHnd >= 0 && HI_MPI_VGS_CancelJob(jobHnd) != HI_SUCCESS) {
322 HI_ASSERT(0);
323 }
324 return ret;
325 }
326 HI_ASSERT(jobHnd >= 0);
327
328 ret = HI_MPI_VGS_AddDrawLineTaskArray(jobHnd, &task, lines, lineNum);
329 if (ret != 0) {
330 SAMPLE_PRT("HI_MPI_VGS_AddDrawLineTaskArray FAIL, ret=%08X\n", ret);
331 if (jobHnd >= 0 && HI_MPI_VGS_CancelJob(jobHnd) != HI_SUCCESS) {
332 HI_ASSERT(0);
333 }
334 return ret;
335 }
336
337 ret = HI_MPI_VGS_EndJob(jobHnd);
338 if (ret != 0) {
339 SAMPLE_PRT("HI_MPI_VGS_EndJob FAIL, ret=%08X\n", ret);
340 if (jobHnd >= 0 && HI_MPI_VGS_CancelJob(jobHnd) != HI_SUCCESS) {
341 HI_ASSERT(0);
342 }
343 return ret;
344 }
345 return 0;
346 }
347
348 /* Superimpose one or more rectangular boxes in the frame */
MppFrmDrawRects(VIDEO_FRAME_INFO_S * frm,const RectBox * boxes,int boxesNum,uint32_t color,int thick)349 int MppFrmDrawRects(VIDEO_FRAME_INFO_S *frm,
350 const RectBox *boxes, int boxesNum, uint32_t color, int thick)
351 {
352 VGS_DRAW_LINE_S lines[VGS_MAX_LINE];
353 int i;
354
355 if (thick <= 0) {
356 HI_ASSERT(0);
357 }
358
359 // Plan the four sides of each rectangle into lines
360 for (i = 0; i < boxesNum; i++) {
361 lines[RECT_LINES * i].stStartPoint.s32X = IntToOven(boxes[i].xmin);
362 lines[RECT_LINES * i].stStartPoint.s32Y = IntToOven(boxes[i].ymin);
363 lines[RECT_LINES * i].stEndPoint.s32X = IntToOven(boxes[i].xmax);
364 lines[RECT_LINES * i].stEndPoint.s32Y = IntToOven(boxes[i].ymin);
365 lines[RECT_LINES * i].u32Color = color;
366 lines[RECT_LINES * i].u32Thick = thick;
367 lines[RECT_LINES * i + RECT_LINE1].stStartPoint.s32X = IntToOven(boxes[i].xmax);
368 lines[RECT_LINES * i + RECT_LINE1].stStartPoint.s32Y = IntToOven(boxes[i].ymin);
369 lines[RECT_LINES * i + RECT_LINE1].stEndPoint.s32X = IntToOven(boxes[i].xmax);
370 lines[RECT_LINES * i + RECT_LINE1].stEndPoint.s32Y = IntToOven(boxes[i].ymax);
371 lines[RECT_LINES * i + RECT_LINE1].u32Color = color;
372 lines[RECT_LINES * i + RECT_LINE1].u32Thick = thick;
373 lines[RECT_LINES * i + RECT_LINE2].stStartPoint.s32X = IntToOven(boxes[i].xmax);
374 lines[RECT_LINES * i + RECT_LINE2].stStartPoint.s32Y = IntToOven(boxes[i].ymax);
375 lines[RECT_LINES * i + RECT_LINE2].stEndPoint.s32X = IntToOven(boxes[i].xmin);
376 lines[RECT_LINES * i + RECT_LINE2].stEndPoint.s32Y = IntToOven(boxes[i].ymax);
377 lines[RECT_LINES * i + RECT_LINE2].u32Color = color;
378 lines[RECT_LINES * i + RECT_LINE2].u32Thick = thick;
379 lines[RECT_LINES * i + RECT_LINE3].stStartPoint.s32X = IntToOven(boxes[i].xmin);
380 lines[RECT_LINES * i + RECT_LINE3].stStartPoint.s32Y = IntToOven(boxes[i].ymax);
381 lines[RECT_LINES * i + RECT_LINE3].stEndPoint.s32X = IntToOven(boxes[i].xmin);
382 lines[RECT_LINES * i + RECT_LINE3].stEndPoint.s32Y = IntToOven(boxes[i].ymin);
383 lines[RECT_LINES * i + RECT_LINE3].u32Color = color;
384 lines[RECT_LINES * i + RECT_LINE3].u32Thick = thick;
385 }
386 return VgsDrawLines(frm, lines, i * RECT_LINES);
387 }
388
389 #ifdef __cplusplus
390 #if __cplusplus
391 }
392 #endif
393 #endif /* End of #ifdef __cplusplus */
394