• 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 
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