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 <iostream>
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <csignal>
21 #include <unistd.h>
22 #include <pthread.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <sys/ioctl.h>
27 #include <sys/prctl.h>
28
29 #include "hi_mipi_tx.h"
30 #include "sdk.h"
31 #include "sample_comm.h"
32 #include "ai_infer_process.h"
33 #include "tennis_detect.h"
34 #include "vgs_img.h"
35 #include "base_interface.h"
36 #include "posix_help.h"
37 #include "sample_media_ai.h"
38 #include "sample_media_opencv.h"
39
40 using namespace std;
41
42 static HI_BOOL s_bOpenCVProcessStopSignal = HI_FALSE;
43 static pthread_t g_openCVProcessThread = 0;
44 static int g_opencv = 0;
45 static AicMediaInfo g_aicTennisMediaInfo = { 0 };
46 static AiPlugLib g_tennisWorkPlug = {0};
47 static HI_CHAR tennisDetectThreadName[16] = {0};
48
49 /* Set VI DEV information */
TennisViCfgSetDev(ViCfg * self,int devId,WDR_MODE_E wdrMode)50 static void TennisViCfgSetDev(ViCfg* self, int devId, WDR_MODE_E wdrMode)
51 {
52 HI_ASSERT(self);
53 HI_ASSERT((int)wdrMode < WDR_MODE_BUTT);
54
55 self->astViInfo[0].stDevInfo.ViDev = devId;
56 self->astViInfo[0].stDevInfo.enWDRMode = wdrMode;
57 }
58
59 /* Set up the VI channel */
TennisViCfgSetChn(ViCfg * self,int chnId,PIXEL_FORMAT_E pixFormat,VIDEO_FORMAT_E videoFormat,DYNAMIC_RANGE_E dynamicRange)60 static void TennisViCfgSetChn(ViCfg* self, int chnId, PIXEL_FORMAT_E pixFormat,
61 VIDEO_FORMAT_E videoFormat, DYNAMIC_RANGE_E dynamicRange)
62 {
63 HI_ASSERT(self);
64 HI_ASSERT((int)pixFormat < PIXEL_FORMAT_BUTT);
65 HI_ASSERT((int)videoFormat < VIDEO_FORMAT_BUTT);
66 HI_ASSERT((int)dynamicRange < DYNAMIC_RANGE_BUTT);
67
68 self->astViInfo[0].stChnInfo.ViChn = chnId;
69 self->astViInfo[0].stChnInfo.enPixFormat = pixFormat;
70 self->astViInfo[0].stChnInfo.enVideoFormat = videoFormat;
71 self->astViInfo[0].stChnInfo.enDynamicRange = dynamicRange;
72 }
73
TennisViPramCfg(HI_VOID)74 static HI_VOID TennisViPramCfg(HI_VOID)
75 {
76 ViCfgInit(&g_aicTennisMediaInfo.viCfg);
77 TennisViCfgSetDev(&g_aicTennisMediaInfo.viCfg, 0, WDR_MODE_NONE);
78 ViCfgSetPipe(&g_aicTennisMediaInfo.viCfg, 0, -1, -1, -1);
79 g_aicTennisMediaInfo.viCfg.astViInfo[0].stPipeInfo.enMastPipeMode = VI_OFFLINE_VPSS_OFFLINE;
80 TennisViCfgSetChn(&g_aicTennisMediaInfo.viCfg, 0, PIXEL_FORMAT_YVU_SEMIPLANAR_420,
81 VIDEO_FORMAT_LINEAR, DYNAMIC_RANGE_SDR8);
82 g_aicTennisMediaInfo.viCfg.astViInfo[0].stChnInfo.enCompressMode = COMPRESS_MODE_SEG;
83 }
84
TennisStVbParamCfg(VbCfg * self)85 static HI_VOID TennisStVbParamCfg(VbCfg *self)
86 {
87 memset_s(&g_aicTennisMediaInfo.vbCfg, sizeof(VB_CONFIG_S), 0, sizeof(VB_CONFIG_S));
88 // 2: The number of buffer pools that can be accommodated in the entire system
89 self->u32MaxPoolCnt = 2;
90
91 /* get picture buffer size */
92 g_aicTennisMediaInfo.u32BlkSize = COMMON_GetPicBufferSize(g_aicTennisMediaInfo.stSize.u32Width,
93 g_aicTennisMediaInfo.stSize.u32Height, SAMPLE_PIXEL_FORMAT, DATA_BITWIDTH_8, COMPRESS_MODE_SEG, DEFAULT_ALIGN);
94 self->astCommPool[0].u64BlkSize = g_aicTennisMediaInfo.u32BlkSize;
95 // 10: Number of cache blocks per cache pool. Value range: (0, 10240]
96 self->astCommPool[0].u32BlkCnt = 10;
97
98 /* get raw buffer size */
99 g_aicTennisMediaInfo.u32BlkSize = VI_GetRawBufferSize(g_aicTennisMediaInfo.stSize.u32Width,
100 g_aicTennisMediaInfo.stSize.u32Height, PIXEL_FORMAT_RGB_BAYER_16BPP, COMPRESS_MODE_NONE, DEFAULT_ALIGN);
101 self->astCommPool[1].u64BlkSize = g_aicTennisMediaInfo.u32BlkSize;
102 // 4: Number of cache blocks per cache pool. Value range: (0, 10240]
103 self->astCommPool[1].u32BlkCnt = 4;
104 }
105
TennisVpssParamCfg(HI_VOID)106 static HI_VOID TennisVpssParamCfg(HI_VOID)
107 {
108 VpssCfgInit(&g_aicTennisMediaInfo.vpssCfg);
109 VpssCfgSetGrp(&g_aicTennisMediaInfo.vpssCfg, 0, NULL,
110 g_aicTennisMediaInfo.stSize.u32Width, g_aicTennisMediaInfo.stSize.u32Width);
111 g_aicTennisMediaInfo.vpssCfg.grpAttr.enPixelFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
112 // 1920:AICSTART_VI_OUTWIDTH, 1080: AICSTART_VI_OUTHEIGHT
113 VpssCfgAddChn(&g_aicTennisMediaInfo.vpssCfg, 1, NULL, 1920, 1080);
114 HI_ASSERT(!g_aicTennisMediaInfo.viSess);
115 }
116
TennisStVoParamCfg(VoCfg * self)117 static HI_VOID TennisStVoParamCfg(VoCfg *self)
118 {
119 SAMPLE_COMM_VO_GetDefConfig(self);
120 self->enDstDynamicRange = DYNAMIC_RANGE_SDR8;
121
122 self->enVoIntfType = VO_INTF_MIPI; /* set VO int type */
123 self->enIntfSync = VO_OUTPUT_USER; /* set VO output information */
124
125 self->enPicSize = g_aicTennisMediaInfo.enPicSize;
126 }
127
TennisDetectAiProcess(VIDEO_FRAME_INFO_S frm,VO_LAYER voLayer,VO_CHN voChn)128 static HI_VOID TennisDetectAiProcess(VIDEO_FRAME_INFO_S frm, VO_LAYER voLayer, VO_CHN voChn)
129 {
130 int ret;
131 tennis_detect opencv;
132 if (GetCfgBool("tennis_detect_switch:support_tennis_detect", true)) {
133 if (g_tennisWorkPlug.model == 0) {
134 ret = opencv.TennisDetectLoad(&g_tennisWorkPlug.model);
135 if (ret < 0) {
136 g_tennisWorkPlug.model = 0;
137 SAMPLE_CHECK_EXPR_GOTO(ret < 0, TENNIS_RELEASE, "TennisDetectLoad err, ret=%#x\n", ret);
138 }
139 }
140
141 VIDEO_FRAME_INFO_S calFrm;
142 ret = MppFrmResize(&frm, &calFrm, 640, 480); // 640: FRM_WIDTH, 480: FRM_HEIGHT
143 ret = opencv.TennisDetectCal(g_tennisWorkPlug.model, &calFrm, &frm);
144 SAMPLE_CHECK_EXPR_GOTO(ret < 0, TENNIS_RELEASE, "TennisDetectCal err, ret=%#x\n", ret);
145
146 ret = HI_MPI_VO_SendFrame(voLayer, voChn, &frm, 0);
147 SAMPLE_CHECK_EXPR_GOTO(ret != HI_SUCCESS, TENNIS_RELEASE,
148 "HI_MPI_VO_SendFrame err, ret=%#x\n", ret);
149 MppFrmDestroy(&calFrm);
150 }
151
152 TENNIS_RELEASE:
153 ret = HI_MPI_VPSS_ReleaseChnFrame(g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0, &frm);
154 if (ret != HI_SUCCESS) {
155 SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_ReleaseChnFrame failed,Grp(%d) chn(%d)!\n",
156 ret, g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0);
157 }
158 }
159
GetVpssChnFrameTennisDetect(HI_VOID * arg)160 static HI_VOID* GetVpssChnFrameTennisDetect(HI_VOID* arg)
161 {
162 int ret;
163 VIDEO_FRAME_INFO_S frm;
164 HI_S32 s32MilliSec = 2000;
165 VO_LAYER voLayer = 0;
166 VO_CHN voChn = 0;
167
168 SAMPLE_PRT("vpssGrp:%d, vpssChn0:%d\n", g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0);
169
170 while (HI_FALSE == s_bOpenCVProcessStopSignal) {
171 ret = HI_MPI_VPSS_GetChnFrame(g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0, &frm, s32MilliSec);
172 if (ret != 0) {
173 SAMPLE_PRT("HI_MPI_VPSS_GetChnFrame FAIL, err=%#x, grp=%d, chn=%d\n",
174 ret, g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0);
175 ret = HI_MPI_VPSS_ReleaseChnFrame(g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0, &frm);
176 if (ret != HI_SUCCESS) {
177 SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_ReleaseChnFrame failed,Grp(%d) chn(%d)!\n",
178 ret, g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0);
179 }
180 continue;
181 }
182 SAMPLE_PRT("get vpss frame success, weight:%d, height:%d\n", frm.stVFrame.u32Width, frm.stVFrame.u32Height);
183
184 if (g_opencv == 0) {
185 ConfBaseInit("./sample_ai.conf");
186 g_opencv++;
187 }
188 TennisDetectAiProcess(frm, voLayer, voChn);
189 }
190
191 return HI_NULL;
192 }
193
PauseDoUnloadTennisModel(HI_VOID)194 static HI_VOID PauseDoUnloadTennisModel(HI_VOID)
195 {
196 if (GetCfgBool("tennis_detect_switch:support_tennis_detect", true)) {
197 memset_s(&g_tennisWorkPlug, sizeof(g_tennisWorkPlug), 0x00, sizeof(g_tennisWorkPlug));
198 ConfBaseExt();
199 SAMPLE_PRT("tennis detect exit success\n");
200 g_opencv = 0;
201 }
202 }
203
TennisDetectAiThreadProcess(HI_VOID)204 static HI_S32 TennisDetectAiThreadProcess(HI_VOID)
205 {
206 HI_S32 s32Ret;
207 if (snprintf_s(tennisDetectThreadName, sizeof(tennisDetectThreadName),
208 sizeof(tennisDetectThreadName) - 1, "OpencvProcess") < 0) {
209 HI_ASSERT(0);
210 }
211 prctl(PR_SET_NAME, (unsigned long)tennisDetectThreadName, 0, 0, 0);
212 s32Ret = pthread_create(&g_openCVProcessThread, NULL, GetVpssChnFrameTennisDetect, NULL);
213
214 return s32Ret;
215 }
216
217 /*
218 * Display the data collected by sensor to LCD screen
219 * VI->VPSS->VO->MIPI
220 */
SAMPLE_MEDIA_TENNIS_DETECT(HI_VOID)221 HI_S32 sample_media_opencv::SAMPLE_MEDIA_TENNIS_DETECT(HI_VOID)
222 {
223 HI_S32 s32Ret;
224 HI_S32 fd = 0;
225
226 /* config vi */
227 TennisViPramCfg();
228
229 /* get picture size */
230 s32Ret = SAMPLE_COMM_VI_GetSizeBySensor(g_aicTennisMediaInfo.viCfg.astViInfo[0].stSnsInfo.enSnsType,
231 &g_aicTennisMediaInfo.enPicSize);
232 SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "get pic size by sensor fail, s32Ret=%#x\n", s32Ret);
233
234 /* get picture size(w*h), according enPicSize */
235 s32Ret = SAMPLE_COMM_SYS_GetPicSize(g_aicTennisMediaInfo.enPicSize, &g_aicTennisMediaInfo.stSize);
236 SAMPLE_PRT("AIC: snsMaxSize=%ux%u\n", g_aicTennisMediaInfo.stSize.u32Width, g_aicTennisMediaInfo.stSize.u32Height);
237 SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "get picture size failed, s32Ret=%#x\n", s32Ret);
238
239 /* config vb */
240 TennisStVbParamCfg(&g_aicTennisMediaInfo.vbCfg);
241
242 /* vb init & MPI system init */
243 s32Ret = SAMPLE_COMM_SYS_Init(&g_aicTennisMediaInfo.vbCfg);
244 SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "system init failed, s32Ret=%#x\n", s32Ret);
245
246 /* set VO config to mipi, get mipi device */
247 s32Ret = SAMPLE_VO_CONFIG_MIPI(&fd);
248 SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT, "CONFIG MIPI FAIL.s32Ret:0x%x\n", s32Ret);
249
250 /* config vpss */
251 TennisVpssParamCfg();
252 s32Ret = ViVpssCreate(&g_aicTennisMediaInfo.viSess, &g_aicTennisMediaInfo.viCfg, &g_aicTennisMediaInfo.vpssCfg);
253 SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT1, "ViVpss Sess create FAIL, ret=%#x\n", s32Ret);
254 g_aicTennisMediaInfo.vpssGrp = 0;
255 g_aicTennisMediaInfo.vpssChn0 = 1;
256
257 /* config vo */
258 TennisStVoParamCfg(&g_aicTennisMediaInfo.voCfg);
259
260 /* start vo */
261 s32Ret = SampleCommVoStartMipi(&g_aicTennisMediaInfo.voCfg);
262 SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT1, "start vo FAIL. s32Ret: 0x%x\n", s32Ret);
263
264 /* vpss bind vo */
265 s32Ret = SAMPLE_COMM_VPSS_Bind_VO(g_aicTennisMediaInfo.vpssGrp,
266 g_aicTennisMediaInfo.vpssChn0, g_aicTennisMediaInfo.voCfg.VoDev, 0);
267 SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT2, "vo bind vpss FAIL. s32Ret: 0x%x\n", s32Ret);
268 SAMPLE_PRT("vpssGrp:%d, vpssChn:%d\n", g_aicTennisMediaInfo.vpssGrp, g_aicTennisMediaInfo.vpssChn0);
269
270 /* create work thread to run ai */
271 s32Ret = TennisDetectAiThreadProcess();
272 SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "ai proccess thread creat fail:%s\n", strerror(s32Ret));
273
274 PAUSE();
275 s_bOpenCVProcessStopSignal = HI_TRUE;
276 pthread_join(g_openCVProcessThread, nullptr);
277 g_openCVProcessThread = 0;
278 PauseDoUnloadTennisModel();
279
280 SAMPLE_COMM_VPSS_UnBind_VO(g_aicTennisMediaInfo.vpssGrp,
281 g_aicTennisMediaInfo.vpssChn0, g_aicTennisMediaInfo.voCfg.VoDev, 0);
282 SAMPLE_VO_DISABLE_MIPITx(fd);
283 SampleCloseMipiTxFd(fd);
284 system("echo 0 > /sys/class/gpio/gpio55/value");
285
286 EXIT2:
287 SAMPLE_COMM_VO_StopVO(&g_aicTennisMediaInfo.voCfg);
288 EXIT1:
289 VpssStop(&g_aicTennisMediaInfo.vpssCfg);
290 SAMPLE_COMM_VI_UnBind_VPSS(g_aicTennisMediaInfo.viCfg.astViInfo[0].stPipeInfo.aPipe[0],
291 g_aicTennisMediaInfo.viCfg.astViInfo[0].stChnInfo.ViChn, g_aicTennisMediaInfo.vpssGrp);
292 ViStop(&g_aicTennisMediaInfo.viCfg);
293 free(g_aicTennisMediaInfo.viSess);
294 EXIT:
295 SAMPLE_COMM_SYS_Exit();
296 return s32Ret;
297 }