关于RKRTSP推流方法结合YOLOV5物体检测无法显示推理结果问题

  • Crocodile wrote: 2024-02-26 11:05
    chenmodegaoyang wrote: 2024-02-26 10:22 您好我成功修改了您的demo并且编译成功其中修改后的rtsp_opencv.cc文件代码如下:

    Code: Select all

    #include <assert.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <getopt.h>
    #include <pthread.h>
    #include <signal.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/poll.h>
    #include <sys/types.h>
    #include <sys/wait.h> 
    #include <time.h>
    #include <unistd.h>
    #include <vector>
    #include <termios.h>
    
    #include "rtsp_demo.h"
    #include "sample_comm.h"
    #include "yolov5.h"
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    
    // disp size
    int width    = 720;
    int height   = 480;
    
    // model size
    int model_width = 640;
    int model_height = 640;	
    float scale ;
    int leftPadding ;
    int topPadding  ;
    
    static RK_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) {
    	printf("%s\n",__func__);
    	VENC_RECV_PIC_PARAM_S stRecvParam;
    	VENC_CHN_ATTR_S stAttr;
    	memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S));
    
    	// RTSP H264	
    	stAttr.stVencAttr.enType = enType;
    	//stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stAttr.stVencAttr.enPixelFormat = RK_FMT_RGB888;	
    	stAttr.stVencAttr.u32Profile = H264E_PROFILE_MAIN;
    	stAttr.stVencAttr.u32PicWidth = width;
    	stAttr.stVencAttr.u32PicHeight = height;
    	stAttr.stVencAttr.u32VirWidth = width;
    	stAttr.stVencAttr.u32VirHeight = height;
    	stAttr.stVencAttr.u32StreamBufCnt = 2;
    	stAttr.stVencAttr.u32BufSize = width * height * 3 / 2;
    	stAttr.stVencAttr.enMirror = MIRROR_NONE;
    		
    	stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    	stAttr.stRcAttr.stH264Cbr.u32BitRate = 3 * 1024;
    	stAttr.stRcAttr.stH264Cbr.u32Gop = 1;
    	RK_MPI_VENC_CreateChn(chnId, &stAttr);
    
    	memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
    	stRecvParam.s32RecvPicNum = -1;
    	RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);
    
    	return 0;
    }
    
    
    // demo板dev默认都是0,根据不同的channel 来选择不同的vi节点
    int vi_dev_init() {
    	printf("%s\n", __func__);
    	int ret = 0;
    	int devId = 0;
    	int pipeId = devId;
    
    	VI_DEV_ATTR_S stDevAttr;
    	VI_DEV_BIND_PIPE_S stBindPipe;
    	memset(&stDevAttr, 0, sizeof(stDevAttr));
    	memset(&stBindPipe, 0, sizeof(stBindPipe));
    	// 0. get dev config status
    	ret = RK_MPI_VI_GetDevAttr(devId, &stDevAttr);
    	if (ret == RK_ERR_VI_NOT_CONFIG) {
    		// 0-1.config dev
    		ret = RK_MPI_VI_SetDevAttr(devId, &stDevAttr);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevAttr %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_SetDevAttr already\n");
    	}
    	// 1.get dev enable status
    	ret = RK_MPI_VI_GetDevIsEnable(devId);
    	if (ret != RK_SUCCESS) {
    		// 1-2.enable dev
    		ret = RK_MPI_VI_EnableDev(devId);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_EnableDev %x\n", ret);
    			return -1;
    		}
    		// 1-3.bind dev/pipe
    		stBindPipe.u32Num = pipeId;
    		stBindPipe.PipeId[0] = pipeId;
    		ret = RK_MPI_VI_SetDevBindPipe(devId, &stBindPipe);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_EnableDev already\n");
    	}
    
    	return 0;
    }
    
    int vi_chn_init(int channelId, int width, int height) {
    	int ret;
    	int buf_cnt = 2;
    	// VI init
    	VI_CHN_ATTR_S vi_chn_attr;
    	memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
    	vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
    	vi_chn_attr.stIspOpt.enMemoryType =
    	    VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
    	vi_chn_attr.stSize.u32Width = width;
    	vi_chn_attr.stSize.u32Height = height;
    	vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
    	vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE; // COMPRESS_AFBC_16x16;
    	vi_chn_attr.u32Depth = 2;
    	ret = RK_MPI_VI_SetChnAttr(0, channelId, &vi_chn_attr);
    	ret |= RK_MPI_VI_EnableChn(0, channelId);
    	if (ret) {
    		printf("ERROR: create VI error! ret=%d\n", ret);
    		return ret;
    	}
    
    	return ret;
    }
    
    int test_vpss_init(int VpssChn, int width, int height) {
    	printf("%s\n",__func__);
    	int s32Ret;
    	VPSS_CHN_ATTR_S stVpssChnAttr;
    	VPSS_GRP_ATTR_S stGrpVpssAttr;
    
    	int s32Grp = 0;
    
    	stGrpVpssAttr.u32MaxW = 4096;
    	stGrpVpssAttr.u32MaxH = 4096;
    	stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stGrpVpssAttr.stFrameRate.s32SrcFrameRate = -1;
    	stGrpVpssAttr.stFrameRate.s32DstFrameRate = -1;
    	stGrpVpssAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	stVpssChnAttr.enChnMode = VPSS_CHN_MODE_USER;
    	stVpssChnAttr.enDynamicRange = DYNAMIC_RANGE_SDR8;
    	stVpssChnAttr.enPixelFormat = RK_FMT_RGB888;
    	stVpssChnAttr.stFrameRate.s32SrcFrameRate = -1;
    	stVpssChnAttr.stFrameRate.s32DstFrameRate = -1;
    	stVpssChnAttr.u32Width = width;
    	stVpssChnAttr.u32Height = height;
    	stVpssChnAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	s32Ret = RK_MPI_VPSS_CreateGrp(s32Grp, &stGrpVpssAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_SetChnAttr(s32Grp, VpssChn, &stVpssChnAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	s32Ret = RK_MPI_VPSS_EnableChn(s32Grp, VpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_StartGrp(s32Grp);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	return s32Ret;
    }
    
    cv::Mat letterbox(cv::Mat input)
    {
    	float scaleX = (float)model_width  / (float)width; //0.888
    	float scaleY = (float)model_height / (float)height; //1.125	
    	scale = scaleX < scaleY ? scaleX : scaleY;
    	
    	int inputWidth   = (int)((float)width * scale);
    	int inputHeight  = (int)((float)height * scale);
    
    	leftPadding = (model_width  - inputWidth) / 2;
    	topPadding  = (model_height - inputHeight) / 2;	
    	
    
    	cv::Mat inputScale;
        cv::resize(input, inputScale, cv::Size(inputWidth,inputHeight), 0, 0, cv::INTER_LINEAR);	
    	cv::Mat letterboxImage(640, 640, CV_8UC3,cv::Scalar(0, 0, 0));
        cv::Rect roi(leftPadding, topPadding, inputWidth, inputHeight);
        inputScale.copyTo(letterboxImage(roi));
    
    	return letterboxImage; 	
    }
    
    void mapCoordinates(int *x, int *y) {	
    	int mx = *x - leftPadding;
    	int my = *y - topPadding;
    
        *x = (int)((float)mx / scale);
        *y = (int)((float)my / scale);
    }
    void rx_buffer_Handle(char *p)
    {
    if(strncmp(p,"close",5)==0){
    	//close demo
    	exit(0);
    }else if(strncmp(p,"reboot",5)==0){
    	//reboot system
    	system("reboot");
    }else if(strncmp(p,"rkill",5)==0){
    	//killall rkipc
    	system("killall rkipc");
    }	
    }
    
    
    rtsp_demo_handle g_rtsplive = NULL;
    rknn_app_context_t rknn_app_ctx;
    MPP_CHN_S stSrcChn, stvpssChn;
    VENC_STREAM_S stFrame;
    int serial_fd;
    //parameter release
    
    void sigint_handler(int signal){
    	//release
    	close(serial_fd);
    	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
    	
    	RK_MPI_VI_DisableChn(0, 0);
    	RK_MPI_VI_DisableDev(0);
    	
    	RK_MPI_VPSS_StopGrp(0);
    	RK_MPI_VPSS_DestroyGrp(0);
    	
    	RK_MPI_VENC_StopRecvFrame(0);
    	RK_MPI_VENC_DestroyChn(0);
    
    	free(stFrame.pstPack);
    
    	if (g_rtsplive)
    	rtsp_del_demo(g_rtsplive);
    	SAMPLE_COMM_ISP_Stop(0);
    
    	RK_MPI_SYS_Exit();
    	// Release rknn model
        release_yolov5_model(&rknn_app_ctx);		
        deinit_post_process();
    	exit(0);	
    }
    
    
    
    int main(int argc, char *argv[]) {
    	
    
    
    	RK_S32 s32Ret = 0; 
    	int sX,sY,eX,eY; 
    		
    	// Rknn model
    	char text[16];
    		
    	object_detect_result_list od_results;
        int ret;
    	const char *model_path = "./model/yolov5.rknn";
        memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));	
        init_yolov5_model(model_path, &rknn_app_ctx);
    	printf("init rknn model success!\n");
        init_post_process();
    
    	//h264_frame	
    		
    	stFrame.pstPack = (VENC_PACK_S *)malloc(sizeof(VENC_PACK_S));
     	VIDEO_FRAME_INFO_S h264_frame;
     	VIDEO_FRAME_INFO_S stVpssFrame;
    
    	// rkaiq init
    	RK_BOOL multi_sensor = RK_FALSE;	
    	const char *iq_dir = "/etc/iqfiles";
    	rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
    	//hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
    	SAMPLE_COMM_ISP_Init(0, hdr_mode, multi_sensor, iq_dir);
    	SAMPLE_COMM_ISP_Run(0);
    
    	// rkmpi init
    	if (RK_MPI_SYS_Init() != RK_SUCCESS) {
    		RK_LOGE("rk mpi sys init fail!");
    		return -1;
    	}
    
    	// rtsp init	
    	
    	rtsp_session_handle g_rtsp_session;
    	g_rtsplive = create_rtsp_demo(554);
    	g_rtsp_session = rtsp_new_session(g_rtsplive, "/live/0");
    	rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);
    	rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());
    	
    	// vi init
    	vi_dev_init();
    	vi_chn_init(0, width, height);
    
    	// vpss init
    	test_vpss_init(0, width, height);
    
    	// bind vi to vpss
    	
    	stSrcChn.enModId = RK_ID_VI;
    	stSrcChn.s32DevId = 0;
    	stSrcChn.s32ChnId = 0;
    
    	stvpssChn.enModId = RK_ID_VPSS;
    	stvpssChn.s32DevId = 0;
    	stvpssChn.s32ChnId = 0;
    	printf("====RK_MPI_SYS_Bind vi0 to vpss0====\n");
    	s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stvpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		RK_LOGE("bind 0 ch venc failed");
    		return -1;
    	}
    
    	// venc init
    	RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_AVC;
    	test_venc_init(0, width, height, enCodecType);
    	printf("venc init success\n");
    
    	//uart3 init
    	int serial_port_num;
        const char serial_port[] = "/dev/ttyS3";
        
    	signal(SIGINT, sigint_handler);
    
        serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
        if (serial_fd == -1) {
            perror("Failed to open serial port");
            return 1;
        }
    
        struct termios tty;
        memset(&tty, 0, sizeof(tty));
    
        if (tcgetattr(serial_fd, &tty) != 0) {
            perror("Error from tcgetattr");
            return 1;
        }
    
        cfsetospeed(&tty, B9600);
        cfsetispeed(&tty, B9600);
    
        tty.c_cflag &= ~PARENB;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CSIZE;
        tty.c_cflag |= CS8;
    
        if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
            perror("Error from tcsetattr");
            return 1;
        }
    
    	//init fork
    	pid_t child_pid;
    	char tx_buffer[256];
    	child_pid=fork();
    	if(child_pid<0)
    	{
    		perror("fork error");
    		return -1;
    	}
    	if(child_pid==0){
    	while(1)
    	{	
    		// get vpss frame
    		s32Ret = RK_MPI_VPSS_GetChnFrame(0,0, &stVpssFrame,-1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);	
    			//opencv	
    			cv::Mat frame(height,width,CV_8UC3,data);			
    			//cv::Mat frame640;
            	//cv::resize(frame, frame640, cv::Size(640,640), 0, 0, cv::INTER_LINEAR);	
    			//letterbox
    			cv::Mat letterboxImage = letterbox(frame);	
    			memcpy(rknn_app_ctx.input_mems[0]->virt_addr, letterboxImage.data, model_width*model_height*3);		
    			inference_yolov5_model(&rknn_app_ctx, &od_results);
    
    			for(int i = 0; i < od_results.count; i++)
    			{					
    				//获取框的四个坐标 
    				if(od_results.count >= 1)
    				{
    					object_detect_result *det_result = &(od_results.results[i]);
    					/*printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
    							 det_result->box.left, det_result->box.top,
    							 det_result->box.right, det_result->box.bottom,
    							 det_result->prop);
    					*/
    					sX = (int)(det_result->box.left   );	
    					sY = (int)(det_result->box.top 	  );	
    					eX = (int)(det_result->box.right  );	
    					eY = (int)(det_result->box.bottom );
    					int centerX = (sX + eX) / 2;
    					int centerY = (sY + eY) / 2;
    					// printf("$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    					// 		 centerX,centerY,det_result->prop,
    					// 		 det_result->box.left,det_result->box.right,
    					// 		 det_result->box.top,det_result->box.bottom
    					// 		 );
    					sprintf(tx_buffer,"$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    							 centerX,centerY,det_result->prop,
    							 det_result->box.left,det_result->box.right,
    							 det_result->box.top,det_result->box.bottom
    							 );
    					//send rknn result
    					write(serial_fd,tx_buffer,sizeof(tx_buffer));
    					memset(tx_buffer,0,sizeof(tx_buffer));
    					mapCoordinates(&sX,&sY);
    					mapCoordinates(&eX,&eY);
    
    					cv::rectangle(frame,cv::Point(sX ,sY),
    								        cv::Point(eX ,eY),
    										cv::Scalar(0,255,0),3);
    					sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
    					cv::putText(frame,text,cv::Point(sX, sY - 8),
    												 cv::FONT_HERSHEY_SIMPLEX,1,
    												 cv::Scalar(0,255,0),2);
    					//draw circle
    					cv::circle(frame, cv::Point(centerX, centerY), 5, cv::Scalar(0, 0, 255), -1);
    				}
    			}
    
    			memcpy(data, frame.data, width * height * 3);					
    		}
    		
    
    		// send stream
    		// encode H264
    		RK_MPI_VENC_SendFrame(0, &stVpssFrame,-1);
    		// rtsp
    		s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			if(g_rtsplive && g_rtsp_session)
    			{
    				//printf("len = %d PTS = %d \n",stFrame.pstPack->u32Len, stFrame.pstPack->u64PTS);
    				
    				void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
    				rtsp_tx_video(g_rtsp_session, (uint8_t *)pData, stFrame.pstPack->u32Len,
    							  stFrame.pstPack->u64PTS);
    				rtsp_do_event(g_rtsplive);
    			}
    		}
    
    		// release frame 
    		s32Ret = RK_MPI_VPSS_ReleaseChnFrame(0, 0, &stVpssFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
    		}
    		s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
    			}
    		memset(text,0,8);
    		}
    	}else if(child_pid >0){
    		//UART handle
    		char rx_buffer[256];
    		int status;
    		while(1){
    		int ret = waitpid(child_pid, &status,WNOHANG);
    		int bytes_read=read(serial_fd,rx_buffer,sizeof(rx_buffer));
    		if(bytes_read < 0){
    		perror("receive error");
    		}else{
    			rx_buffer[bytes_read]='\0';
    			//printf("RX:%s\n",rx_buffer);
    			write(serial_fd,rx_buffer,sizeof(rx_buffer));
    			rx_buffer_Handle(rx_buffer);
    		}
    		memset(rx_buffer,0,sizeof(rx_buffer));
    		if(ret>0)
    		{
    			close(serial_fd);
    			exit(0);
    		}
    		}
    		
    	}
    
    	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
    	
    	RK_MPI_VI_DisableChn(0, 0);
    	RK_MPI_VI_DisableDev(0);
    	
    	RK_MPI_VPSS_StopGrp(0);
    	RK_MPI_VPSS_DestroyGrp(0);
    	
    	RK_MPI_VENC_StopRecvFrame(0);
    	RK_MPI_VENC_DestroyChn(0);
    
    	free(stFrame.pstPack);
    
    	if (g_rtsplive)
    	rtsp_del_demo(g_rtsplive);
    	SAMPLE_COMM_ISP_Stop(0);
    
    	RK_MPI_SYS_Exit();
    	// Release rknn model
        release_yolov5_model(&rknn_app_ctx);		
        deinit_post_process();
    	
    	return 0;
    }
    
    
    我添加了串口3打印的逻辑,并且分为了父子进程,父进程用来处理发送过来的串口数据并做出相应系统操作,子进程用于发送RKNN推理结果,并且加入了SIGINT(ctrl+c信号)的处理函数,用于释放while循环之后一直没有被释放的资源,并将涉及到释放的资源弄成了全局变量,也添加了一些子进程的回收操作,想问这个从串口三判断完数据后用system(“lINUX指令”)方式执行操作这样的方式可行吗如下代码

    Code: Select all

    void rx_buffer_Handle(char *p)
    {
    if(strncmp(p,"close",5)==0){
    	//close demo
    	exit(0);
    }else if(strncmp(p,"reboot",5)==0){
    	//reboot system
    	system("reboot");
    }else if(strncmp(p,"rkill",5)==0){
    	//killall rkipc
    	system("killall rkipc");
    }	
    还是需要写一些执行脚本(包含Linux指令)去调用脚本运行Linux指令呢?如果要写的话执行脚本是怎样的格式呢放在哪里比较合适呢?另外这个自启动想要直接运行这个程序的话可以在inid中写一个开机启动执行这个demo的话,格式有什么要求吗
    您好,rx_buffer_Handle 调用 system 来执行 shell 命令这种方式是可行的,exit(0) 会立刻结束程序并回收程序的内存空间但是不会回收 malloc 或者 rkmpi 申请的动态内存,这可能会导致内存泄漏的问题。建议还是使用退出 while 循环的方式使用 RKMPI 资源回收 API 来结束程序的运行。
    相应的方法可以参考 Linux 多线程编程中共享变量、管道、消息队列的方式,比如创建一个全局变量 quit ,循环程序在 while(!quit) 中运行,通过修改quit就可以退出 while 循环。

    开机启动程序的脚本请参考 shell 脚本编写,如果只需要简单的执行程序,可以在 init.d 文件夹下创建 S99code

    Code: Select all

    cd <可支持文件所在文件夹>
    ./<可执行文件>
    
    您好我看了/home/alientek/sdk_RV1106/luckfox-pico-main/media/samples/simple_test下面的simple_vi_venc_rtsp.c中的代码,并对我的代码运用线程和!quit全局变量进行了修改,虽然成功编译并运行但是一但运用ctrl+c信号阻断运行就会发现他会进入信号处理函数但是并且关闭了串口输出和程序输出,但是程序却不能停止下来了,如下图所示,尝试了好几回ctrl+c去阻止运行一直卡在了这里,不知道是哪里的问题,而且我想是不是这个ctrl+c时他只会仅信号处理函数但是不会再回到主函数进行运行,那么这个quit可能就没了作用
    Image
    我修改后的代码如下:

    Code: Select all

    #include <assert.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <getopt.h>
    #include <pthread.h>
    #include <signal.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/poll.h>
    #include <sys/types.h>
    #include <sys/wait.h> 
    #include <time.h>
    #include <unistd.h>
    #include <vector>
    #include <termios.h>
    
    #include "rtsp_demo.h"
    #include "sample_comm.h"
    #include "yolov5.h"
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    
    // disp size
    int width    = 720;
    int height   = 480;
    
    // model size
    int model_width = 640;
    int model_height = 640;	
    float scale ;
    int leftPadding ;
    int topPadding  ;
    //handle while function
    static bool quit=false;
    
    static RK_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) {
    	printf("%s\n",__func__);
    	VENC_RECV_PIC_PARAM_S stRecvParam;
    	VENC_CHN_ATTR_S stAttr;
    	memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S));
    
    	// RTSP H264	
    	stAttr.stVencAttr.enType = enType;
    	//stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stAttr.stVencAttr.enPixelFormat = RK_FMT_RGB888;	
    	stAttr.stVencAttr.u32Profile = H264E_PROFILE_MAIN;
    	stAttr.stVencAttr.u32PicWidth = width;
    	stAttr.stVencAttr.u32PicHeight = height;
    	stAttr.stVencAttr.u32VirWidth = width;
    	stAttr.stVencAttr.u32VirHeight = height;
    	stAttr.stVencAttr.u32StreamBufCnt = 2;
    	stAttr.stVencAttr.u32BufSize = width * height * 3 / 2;
    	stAttr.stVencAttr.enMirror = MIRROR_NONE;
    		
    	stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    	stAttr.stRcAttr.stH264Cbr.u32BitRate = 3 * 1024;
    	stAttr.stRcAttr.stH264Cbr.u32Gop = 1;
    	RK_MPI_VENC_CreateChn(chnId, &stAttr);
    
    	memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
    	stRecvParam.s32RecvPicNum = -1;
    	RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);
    
    	return 0;
    }
    
    
    // demo板dev默认都是0,根据不同的channel 来选择不同的vi节点
    int vi_dev_init() {
    	printf("%s\n", __func__);
    	int ret = 0;
    	int devId = 0;
    	int pipeId = devId;
    
    	VI_DEV_ATTR_S stDevAttr;
    	VI_DEV_BIND_PIPE_S stBindPipe;
    	memset(&stDevAttr, 0, sizeof(stDevAttr));
    	memset(&stBindPipe, 0, sizeof(stBindPipe));
    	// 0. get dev config status
    	ret = RK_MPI_VI_GetDevAttr(devId, &stDevAttr);
    	if (ret == RK_ERR_VI_NOT_CONFIG) {
    		// 0-1.config dev
    		ret = RK_MPI_VI_SetDevAttr(devId, &stDevAttr);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevAttr %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_SetDevAttr already\n");
    	}
    	// 1.get dev enable status
    	ret = RK_MPI_VI_GetDevIsEnable(devId);
    	if (ret != RK_SUCCESS) {
    		// 1-2.enable dev
    		ret = RK_MPI_VI_EnableDev(devId);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_EnableDev %x\n", ret);
    			return -1;
    		}
    		// 1-3.bind dev/pipe
    		stBindPipe.u32Num = pipeId;
    		stBindPipe.PipeId[0] = pipeId;
    		ret = RK_MPI_VI_SetDevBindPipe(devId, &stBindPipe);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_EnableDev already\n");
    	}
    
    	return 0;
    }
    
    int vi_chn_init(int channelId, int width, int height) {
    	int ret;
    	int buf_cnt = 2;
    	// VI init
    	VI_CHN_ATTR_S vi_chn_attr;
    	memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
    	vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
    	vi_chn_attr.stIspOpt.enMemoryType =
    	    VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
    	vi_chn_attr.stSize.u32Width = width;
    	vi_chn_attr.stSize.u32Height = height;
    	vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
    	vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE; // COMPRESS_AFBC_16x16;
    	vi_chn_attr.u32Depth = 2;
    	ret = RK_MPI_VI_SetChnAttr(0, channelId, &vi_chn_attr);
    	ret |= RK_MPI_VI_EnableChn(0, channelId);
    	if (ret) {
    		printf("ERROR: create VI error! ret=%d\n", ret);
    		return ret;
    	}
    
    	return ret;
    }
    
    int test_vpss_init(int VpssChn, int width, int height) {
    	printf("%s\n",__func__);
    	int s32Ret;
    	VPSS_CHN_ATTR_S stVpssChnAttr;
    	VPSS_GRP_ATTR_S stGrpVpssAttr;
    
    	int s32Grp = 0;
    
    	stGrpVpssAttr.u32MaxW = 4096;
    	stGrpVpssAttr.u32MaxH = 4096;
    	stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stGrpVpssAttr.stFrameRate.s32SrcFrameRate = -1;
    	stGrpVpssAttr.stFrameRate.s32DstFrameRate = -1;
    	stGrpVpssAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	stVpssChnAttr.enChnMode = VPSS_CHN_MODE_USER;
    	stVpssChnAttr.enDynamicRange = DYNAMIC_RANGE_SDR8;
    	stVpssChnAttr.enPixelFormat = RK_FMT_RGB888;
    	stVpssChnAttr.stFrameRate.s32SrcFrameRate = -1;
    	stVpssChnAttr.stFrameRate.s32DstFrameRate = -1;
    	stVpssChnAttr.u32Width = width;
    	stVpssChnAttr.u32Height = height;
    	stVpssChnAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	s32Ret = RK_MPI_VPSS_CreateGrp(s32Grp, &stGrpVpssAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_SetChnAttr(s32Grp, VpssChn, &stVpssChnAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	s32Ret = RK_MPI_VPSS_EnableChn(s32Grp, VpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_StartGrp(s32Grp);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	return s32Ret;
    }
    
    cv::Mat letterbox(cv::Mat input)
    {
    	float scaleX = (float)model_width  / (float)width; //0.888
    	float scaleY = (float)model_height / (float)height; //1.125	
    	scale = scaleX < scaleY ? scaleX : scaleY;
    	
    	int inputWidth   = (int)((float)width * scale);
    	int inputHeight  = (int)((float)height * scale);
    
    	leftPadding = (model_width  - inputWidth) / 2;
    	topPadding  = (model_height - inputHeight) / 2;	
    	
    
    	cv::Mat inputScale;
        cv::resize(input, inputScale, cv::Size(inputWidth,inputHeight), 0, 0, cv::INTER_LINEAR);	
    	cv::Mat letterboxImage(640, 640, CV_8UC3,cv::Scalar(0, 0, 0));
        cv::Rect roi(leftPadding, topPadding, inputWidth, inputHeight);
        inputScale.copyTo(letterboxImage(roi));
    
    	return letterboxImage; 	
    }
    
    void mapCoordinates(int *x, int *y) {	
    	int mx = *x - leftPadding;
    	int my = *y - topPadding;
    
        *x = (int)((float)mx / scale);
        *y = (int)((float)my / scale);
    }
    void rx_buffer_Handle(char *p)
    {
    if(strncmp(p,"close",5)==0){
    	//close demo
    	//exit(0);
    }else if(strncmp(p,"reboot",5)==0){
    	//reboot system
    	system("reboot");
    }else if(strncmp(p,"rkill",5)==0){
    	//killall rkipc
    	system("killall rkipc");
    }	
    }
    
    
    rtsp_demo_handle g_rtsplive = NULL;
    rknn_app_context_t rknn_app_ctx;
    MPP_CHN_S stSrcChn, stvpssChn;
    VENC_STREAM_S stFrame;
    int serial_fd;
    //parameter release
    
    void sigint_handler(int sig){
    	//release
    	fprintf(stderr, "signal %d-------------------------------\n", sig);
    	quit=true;
    }
    static void *User_Handle(void *arg){
    		//UART handle
    		char rx_buffer[256];
    		while(!quit){
    		int bytes_read=read(serial_fd,rx_buffer,sizeof(rx_buffer));
    		if(bytes_read < 0){
    		perror("receive error");
    		}else{
    			rx_buffer[bytes_read]='\0';
    			//printf("RX:%s\n",rx_buffer);
    			write(serial_fd,rx_buffer,bytes_read);
    			rx_buffer_Handle(rx_buffer);
    		}
    		memset(rx_buffer,0,sizeof(rx_buffer));
    		}
    }
    
    
    int main(int argc, char *argv[]) {
    	
    
    
    	RK_S32 s32Ret = 0; 
    	int sX,sY,eX,eY; 
    		
    	// Rknn model
    	char text[16];
    		
    	object_detect_result_list od_results;
        int ret;
    	const char *model_path = "./model/yolov5.rknn";
        memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));	
        init_yolov5_model(model_path, &rknn_app_ctx);
    	printf("init rknn model success!\n");
        init_post_process();
    
    	//h264_frame	
    		
    	stFrame.pstPack = (VENC_PACK_S *)malloc(sizeof(VENC_PACK_S));
     	VIDEO_FRAME_INFO_S h264_frame;
     	VIDEO_FRAME_INFO_S stVpssFrame;
    
    	// rkaiq init
    	RK_BOOL multi_sensor = RK_FALSE;	
    	const char *iq_dir = "/etc/iqfiles";
    	rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
    	//hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
    	SAMPLE_COMM_ISP_Init(0, hdr_mode, multi_sensor, iq_dir);
    	SAMPLE_COMM_ISP_Run(0);
    
    	// rkmpi init
    	if (RK_MPI_SYS_Init() != RK_SUCCESS) {
    		RK_LOGE("rk mpi sys init fail!");
    		return -1;
    	}
    
    	// rtsp init	
    	
    	rtsp_session_handle g_rtsp_session;
    	g_rtsplive = create_rtsp_demo(554);
    	g_rtsp_session = rtsp_new_session(g_rtsplive, "/live/0");
    	rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);
    	rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());
    	
    	// vi init
    	vi_dev_init();
    	vi_chn_init(0, width, height);
    
    	// vpss init
    	test_vpss_init(0, width, height);
    
    	// bind vi to vpss
    	
    	stSrcChn.enModId = RK_ID_VI;
    	stSrcChn.s32DevId = 0;
    	stSrcChn.s32ChnId = 0;
    
    	stvpssChn.enModId = RK_ID_VPSS;
    	stvpssChn.s32DevId = 0;
    	stvpssChn.s32ChnId = 0;
    	printf("====RK_MPI_SYS_Bind vi0 to vpss0====\n");
    	s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stvpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		RK_LOGE("bind 0 ch venc failed");
    		return -1;
    	}
    
    	// venc init
    	RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_AVC;
    	test_venc_init(0, width, height, enCodecType);
    	printf("venc init success\n");
    
    	//uart3 init
    	int serial_port_num;
        const char serial_port[] = "/dev/ttyS3";
        
    	signal(SIGINT, sigint_handler);
    
        serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
        if (serial_fd == -1) {
            perror("Failed to open serial port");
            return 1;
        }
    
        struct termios tty;
        memset(&tty, 0, sizeof(tty));
    
        if (tcgetattr(serial_fd, &tty) != 0) {
            perror("Error from tcgetattr");
            return 1;
        }
    
        cfsetospeed(&tty, B9600);
        cfsetispeed(&tty, B9600);
    
        tty.c_cflag &= ~PARENB;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CSIZE;
        tty.c_cflag |= CS8;
    
        if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
            perror("Error from tcsetattr");
            return 1;
        }
    
    	//init fork
    	char tx_buffer[256];
    	pthread_t Handle_thread;
    	pthread_create(&Handle_thread, NULL, User_Handle, NULL);
    	
    	while(!quit)
    	{	
    		// get vpss frame
    		s32Ret = RK_MPI_VPSS_GetChnFrame(0,0, &stVpssFrame,-1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);	
    			//opencv	
    			cv::Mat frame(height,width,CV_8UC3,data);			
    			//cv::Mat frame640;
            	//cv::resize(frame, frame640, cv::Size(640,640), 0, 0, cv::INTER_LINEAR);	
    			//letterbox
    			cv::Mat letterboxImage = letterbox(frame);	
    			memcpy(rknn_app_ctx.input_mems[0]->virt_addr, letterboxImage.data, model_width*model_height*3);		
    			inference_yolov5_model(&rknn_app_ctx, &od_results);
    
    			for(int i = 0; i < od_results.count; i++)
    			{					
    				//获取框的四个坐标 
    				if(od_results.count >= 1)
    				{
    					object_detect_result *det_result = &(od_results.results[i]);
    					/*printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
    							 det_result->box.left, det_result->box.top,
    							 det_result->box.right, det_result->box.bottom,
    							 det_result->prop);
    					*/
    					sX = (int)(det_result->box.left   );	
    					sY = (int)(det_result->box.top 	  );	
    					eX = (int)(det_result->box.right  );	
    					eY = (int)(det_result->box.bottom );
    					int centerX = (sX + eX) / 2;
    					int centerY = (sY + eY) / 2;
    					// printf("$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    					// 		 centerX,centerY,det_result->prop,
    					// 		 det_result->box.left,det_result->box.right,
    					// 		 det_result->box.top,det_result->box.bottom
    					// 		 );
    					sprintf(tx_buffer,"$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    							 centerX,centerY,det_result->prop,
    							 det_result->box.left,det_result->box.right,
    							 det_result->box.top,det_result->box.bottom
    							 );
    					//send rknn result
    					write(serial_fd,tx_buffer,strlen(tx_buffer));
    					memset(tx_buffer,0,sizeof(tx_buffer));
    					mapCoordinates(&sX,&sY);
    					mapCoordinates(&eX,&eY);
    
    					cv::rectangle(frame,cv::Point(sX ,sY),
    								        cv::Point(eX ,eY),
    										cv::Scalar(0,255,0),3);
    					sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
    					cv::putText(frame,text,cv::Point(sX, sY - 8),
    												 cv::FONT_HERSHEY_SIMPLEX,1,
    												 cv::Scalar(0,255,0),2);
    					//draw circle
    					cv::circle(frame, cv::Point(centerX, centerY), 5, cv::Scalar(0, 0, 255), -1);
    				}
    			}
    			memcpy(data, frame.data, width * height * 3);					
    		}
    		
    
    		// send stream
    		// encode H264
    		RK_MPI_VENC_SendFrame(0, &stVpssFrame,-1);
    		// rtsp
    		s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			if(g_rtsplive && g_rtsp_session)
    			{
    				//printf("len = %d PTS = %d \n",stFrame.pstPack->u32Len, stFrame.pstPack->u64PTS);
    				
    				void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
    				rtsp_tx_video(g_rtsp_session, (uint8_t *)pData, stFrame.pstPack->u32Len,
    							  stFrame.pstPack->u64PTS);
    				rtsp_do_event(g_rtsplive);
    			}
    		}
    		// release frame 
    		s32Ret = RK_MPI_VPSS_ReleaseChnFrame(0, 0, &stVpssFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
    		}
    		s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
    			}
    		memset(text,0,8);
    		}
    	//release thread
    	pthread_join(Handle_thread, NULL);
    	printf("exit result enter--------------------------------------------------------------------------------------------\n");
    	close(serial_fd);
    	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
    	
    	RK_MPI_VI_DisableChn(0, 0);
    	RK_MPI_VI_DisableDev(0);
    	
    	RK_MPI_VPSS_StopGrp(0);
    	RK_MPI_VPSS_DestroyGrp(0);
    	
    	RK_MPI_VENC_StopRecvFrame(0);
    	RK_MPI_VENC_DestroyChn(0);
    
    	free(stFrame.pstPack);
    
    	if (g_rtsplive)
    	rtsp_del_demo(g_rtsplive);
    	SAMPLE_COMM_ISP_Stop(0);
    
    	RK_MPI_SYS_Exit();
    	// Release rknn model
        release_yolov5_model(&rknn_app_ctx);		
        deinit_post_process();
    	
    	return 0;
    }
    
    但是他有信号ctrl+c时卡死了并不会退出程序
    Attachments
    信号错误.png
  • chenmodegaoyang wrote: 2024-02-27 3:05
    Crocodile wrote: 2024-02-26 11:05
    chenmodegaoyang wrote: 2024-02-26 10:22 您好我成功修改了您的demo并且编译成功其中修改后的rtsp_opencv.cc文件代码如下:

    Code: Select all

    #include <assert.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <getopt.h>
    #include <pthread.h>
    #include <signal.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/poll.h>
    #include <sys/types.h>
    #include <sys/wait.h> 
    #include <time.h>
    #include <unistd.h>
    #include <vector>
    #include <termios.h>
    
    #include "rtsp_demo.h"
    #include "sample_comm.h"
    #include "yolov5.h"
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    
    // disp size
    int width    = 720;
    int height   = 480;
    
    // model size
    int model_width = 640;
    int model_height = 640;	
    float scale ;
    int leftPadding ;
    int topPadding  ;
    
    static RK_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) {
    	printf("%s\n",__func__);
    	VENC_RECV_PIC_PARAM_S stRecvParam;
    	VENC_CHN_ATTR_S stAttr;
    	memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S));
    
    	// RTSP H264	
    	stAttr.stVencAttr.enType = enType;
    	//stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stAttr.stVencAttr.enPixelFormat = RK_FMT_RGB888;	
    	stAttr.stVencAttr.u32Profile = H264E_PROFILE_MAIN;
    	stAttr.stVencAttr.u32PicWidth = width;
    	stAttr.stVencAttr.u32PicHeight = height;
    	stAttr.stVencAttr.u32VirWidth = width;
    	stAttr.stVencAttr.u32VirHeight = height;
    	stAttr.stVencAttr.u32StreamBufCnt = 2;
    	stAttr.stVencAttr.u32BufSize = width * height * 3 / 2;
    	stAttr.stVencAttr.enMirror = MIRROR_NONE;
    		
    	stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    	stAttr.stRcAttr.stH264Cbr.u32BitRate = 3 * 1024;
    	stAttr.stRcAttr.stH264Cbr.u32Gop = 1;
    	RK_MPI_VENC_CreateChn(chnId, &stAttr);
    
    	memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
    	stRecvParam.s32RecvPicNum = -1;
    	RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);
    
    	return 0;
    }
    
    
    // demo板dev默认都是0,根据不同的channel 来选择不同的vi节点
    int vi_dev_init() {
    	printf("%s\n", __func__);
    	int ret = 0;
    	int devId = 0;
    	int pipeId = devId;
    
    	VI_DEV_ATTR_S stDevAttr;
    	VI_DEV_BIND_PIPE_S stBindPipe;
    	memset(&stDevAttr, 0, sizeof(stDevAttr));
    	memset(&stBindPipe, 0, sizeof(stBindPipe));
    	// 0. get dev config status
    	ret = RK_MPI_VI_GetDevAttr(devId, &stDevAttr);
    	if (ret == RK_ERR_VI_NOT_CONFIG) {
    		// 0-1.config dev
    		ret = RK_MPI_VI_SetDevAttr(devId, &stDevAttr);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevAttr %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_SetDevAttr already\n");
    	}
    	// 1.get dev enable status
    	ret = RK_MPI_VI_GetDevIsEnable(devId);
    	if (ret != RK_SUCCESS) {
    		// 1-2.enable dev
    		ret = RK_MPI_VI_EnableDev(devId);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_EnableDev %x\n", ret);
    			return -1;
    		}
    		// 1-3.bind dev/pipe
    		stBindPipe.u32Num = pipeId;
    		stBindPipe.PipeId[0] = pipeId;
    		ret = RK_MPI_VI_SetDevBindPipe(devId, &stBindPipe);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_EnableDev already\n");
    	}
    
    	return 0;
    }
    
    int vi_chn_init(int channelId, int width, int height) {
    	int ret;
    	int buf_cnt = 2;
    	// VI init
    	VI_CHN_ATTR_S vi_chn_attr;
    	memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
    	vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
    	vi_chn_attr.stIspOpt.enMemoryType =
    	    VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
    	vi_chn_attr.stSize.u32Width = width;
    	vi_chn_attr.stSize.u32Height = height;
    	vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
    	vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE; // COMPRESS_AFBC_16x16;
    	vi_chn_attr.u32Depth = 2;
    	ret = RK_MPI_VI_SetChnAttr(0, channelId, &vi_chn_attr);
    	ret |= RK_MPI_VI_EnableChn(0, channelId);
    	if (ret) {
    		printf("ERROR: create VI error! ret=%d\n", ret);
    		return ret;
    	}
    
    	return ret;
    }
    
    int test_vpss_init(int VpssChn, int width, int height) {
    	printf("%s\n",__func__);
    	int s32Ret;
    	VPSS_CHN_ATTR_S stVpssChnAttr;
    	VPSS_GRP_ATTR_S stGrpVpssAttr;
    
    	int s32Grp = 0;
    
    	stGrpVpssAttr.u32MaxW = 4096;
    	stGrpVpssAttr.u32MaxH = 4096;
    	stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stGrpVpssAttr.stFrameRate.s32SrcFrameRate = -1;
    	stGrpVpssAttr.stFrameRate.s32DstFrameRate = -1;
    	stGrpVpssAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	stVpssChnAttr.enChnMode = VPSS_CHN_MODE_USER;
    	stVpssChnAttr.enDynamicRange = DYNAMIC_RANGE_SDR8;
    	stVpssChnAttr.enPixelFormat = RK_FMT_RGB888;
    	stVpssChnAttr.stFrameRate.s32SrcFrameRate = -1;
    	stVpssChnAttr.stFrameRate.s32DstFrameRate = -1;
    	stVpssChnAttr.u32Width = width;
    	stVpssChnAttr.u32Height = height;
    	stVpssChnAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	s32Ret = RK_MPI_VPSS_CreateGrp(s32Grp, &stGrpVpssAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_SetChnAttr(s32Grp, VpssChn, &stVpssChnAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	s32Ret = RK_MPI_VPSS_EnableChn(s32Grp, VpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_StartGrp(s32Grp);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	return s32Ret;
    }
    
    cv::Mat letterbox(cv::Mat input)
    {
    	float scaleX = (float)model_width  / (float)width; //0.888
    	float scaleY = (float)model_height / (float)height; //1.125	
    	scale = scaleX < scaleY ? scaleX : scaleY;
    	
    	int inputWidth   = (int)((float)width * scale);
    	int inputHeight  = (int)((float)height * scale);
    
    	leftPadding = (model_width  - inputWidth) / 2;
    	topPadding  = (model_height - inputHeight) / 2;	
    	
    
    	cv::Mat inputScale;
        cv::resize(input, inputScale, cv::Size(inputWidth,inputHeight), 0, 0, cv::INTER_LINEAR);	
    	cv::Mat letterboxImage(640, 640, CV_8UC3,cv::Scalar(0, 0, 0));
        cv::Rect roi(leftPadding, topPadding, inputWidth, inputHeight);
        inputScale.copyTo(letterboxImage(roi));
    
    	return letterboxImage; 	
    }
    
    void mapCoordinates(int *x, int *y) {	
    	int mx = *x - leftPadding;
    	int my = *y - topPadding;
    
        *x = (int)((float)mx / scale);
        *y = (int)((float)my / scale);
    }
    void rx_buffer_Handle(char *p)
    {
    if(strncmp(p,"close",5)==0){
    	//close demo
    	exit(0);
    }else if(strncmp(p,"reboot",5)==0){
    	//reboot system
    	system("reboot");
    }else if(strncmp(p,"rkill",5)==0){
    	//killall rkipc
    	system("killall rkipc");
    }	
    }
    
    
    rtsp_demo_handle g_rtsplive = NULL;
    rknn_app_context_t rknn_app_ctx;
    MPP_CHN_S stSrcChn, stvpssChn;
    VENC_STREAM_S stFrame;
    int serial_fd;
    //parameter release
    
    void sigint_handler(int signal){
    	//release
    	close(serial_fd);
    	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
    	
    	RK_MPI_VI_DisableChn(0, 0);
    	RK_MPI_VI_DisableDev(0);
    	
    	RK_MPI_VPSS_StopGrp(0);
    	RK_MPI_VPSS_DestroyGrp(0);
    	
    	RK_MPI_VENC_StopRecvFrame(0);
    	RK_MPI_VENC_DestroyChn(0);
    
    	free(stFrame.pstPack);
    
    	if (g_rtsplive)
    	rtsp_del_demo(g_rtsplive);
    	SAMPLE_COMM_ISP_Stop(0);
    
    	RK_MPI_SYS_Exit();
    	// Release rknn model
        release_yolov5_model(&rknn_app_ctx);		
        deinit_post_process();
    	exit(0);	
    }
    
    
    
    int main(int argc, char *argv[]) {
    	
    
    
    	RK_S32 s32Ret = 0; 
    	int sX,sY,eX,eY; 
    		
    	// Rknn model
    	char text[16];
    		
    	object_detect_result_list od_results;
        int ret;
    	const char *model_path = "./model/yolov5.rknn";
        memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));	
        init_yolov5_model(model_path, &rknn_app_ctx);
    	printf("init rknn model success!\n");
        init_post_process();
    
    	//h264_frame	
    		
    	stFrame.pstPack = (VENC_PACK_S *)malloc(sizeof(VENC_PACK_S));
     	VIDEO_FRAME_INFO_S h264_frame;
     	VIDEO_FRAME_INFO_S stVpssFrame;
    
    	// rkaiq init
    	RK_BOOL multi_sensor = RK_FALSE;	
    	const char *iq_dir = "/etc/iqfiles";
    	rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
    	//hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
    	SAMPLE_COMM_ISP_Init(0, hdr_mode, multi_sensor, iq_dir);
    	SAMPLE_COMM_ISP_Run(0);
    
    	// rkmpi init
    	if (RK_MPI_SYS_Init() != RK_SUCCESS) {
    		RK_LOGE("rk mpi sys init fail!");
    		return -1;
    	}
    
    	// rtsp init	
    	
    	rtsp_session_handle g_rtsp_session;
    	g_rtsplive = create_rtsp_demo(554);
    	g_rtsp_session = rtsp_new_session(g_rtsplive, "/live/0");
    	rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);
    	rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());
    	
    	// vi init
    	vi_dev_init();
    	vi_chn_init(0, width, height);
    
    	// vpss init
    	test_vpss_init(0, width, height);
    
    	// bind vi to vpss
    	
    	stSrcChn.enModId = RK_ID_VI;
    	stSrcChn.s32DevId = 0;
    	stSrcChn.s32ChnId = 0;
    
    	stvpssChn.enModId = RK_ID_VPSS;
    	stvpssChn.s32DevId = 0;
    	stvpssChn.s32ChnId = 0;
    	printf("====RK_MPI_SYS_Bind vi0 to vpss0====\n");
    	s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stvpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		RK_LOGE("bind 0 ch venc failed");
    		return -1;
    	}
    
    	// venc init
    	RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_AVC;
    	test_venc_init(0, width, height, enCodecType);
    	printf("venc init success\n");
    
    	//uart3 init
    	int serial_port_num;
        const char serial_port[] = "/dev/ttyS3";
        
    	signal(SIGINT, sigint_handler);
    
        serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
        if (serial_fd == -1) {
            perror("Failed to open serial port");
            return 1;
        }
    
        struct termios tty;
        memset(&tty, 0, sizeof(tty));
    
        if (tcgetattr(serial_fd, &tty) != 0) {
            perror("Error from tcgetattr");
            return 1;
        }
    
        cfsetospeed(&tty, B9600);
        cfsetispeed(&tty, B9600);
    
        tty.c_cflag &= ~PARENB;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CSIZE;
        tty.c_cflag |= CS8;
    
        if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
            perror("Error from tcsetattr");
            return 1;
        }
    
    	//init fork
    	pid_t child_pid;
    	char tx_buffer[256];
    	child_pid=fork();
    	if(child_pid<0)
    	{
    		perror("fork error");
    		return -1;
    	}
    	if(child_pid==0){
    	while(1)
    	{	
    		// get vpss frame
    		s32Ret = RK_MPI_VPSS_GetChnFrame(0,0, &stVpssFrame,-1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);	
    			//opencv	
    			cv::Mat frame(height,width,CV_8UC3,data);			
    			//cv::Mat frame640;
            	//cv::resize(frame, frame640, cv::Size(640,640), 0, 0, cv::INTER_LINEAR);	
    			//letterbox
    			cv::Mat letterboxImage = letterbox(frame);	
    			memcpy(rknn_app_ctx.input_mems[0]->virt_addr, letterboxImage.data, model_width*model_height*3);		
    			inference_yolov5_model(&rknn_app_ctx, &od_results);
    
    			for(int i = 0; i < od_results.count; i++)
    			{					
    				//获取框的四个坐标 
    				if(od_results.count >= 1)
    				{
    					object_detect_result *det_result = &(od_results.results[i]);
    					/*printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
    							 det_result->box.left, det_result->box.top,
    							 det_result->box.right, det_result->box.bottom,
    							 det_result->prop);
    					*/
    					sX = (int)(det_result->box.left   );	
    					sY = (int)(det_result->box.top 	  );	
    					eX = (int)(det_result->box.right  );	
    					eY = (int)(det_result->box.bottom );
    					int centerX = (sX + eX) / 2;
    					int centerY = (sY + eY) / 2;
    					// printf("$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    					// 		 centerX,centerY,det_result->prop,
    					// 		 det_result->box.left,det_result->box.right,
    					// 		 det_result->box.top,det_result->box.bottom
    					// 		 );
    					sprintf(tx_buffer,"$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    							 centerX,centerY,det_result->prop,
    							 det_result->box.left,det_result->box.right,
    							 det_result->box.top,det_result->box.bottom
    							 );
    					//send rknn result
    					write(serial_fd,tx_buffer,sizeof(tx_buffer));
    					memset(tx_buffer,0,sizeof(tx_buffer));
    					mapCoordinates(&sX,&sY);
    					mapCoordinates(&eX,&eY);
    
    					cv::rectangle(frame,cv::Point(sX ,sY),
    								        cv::Point(eX ,eY),
    										cv::Scalar(0,255,0),3);
    					sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
    					cv::putText(frame,text,cv::Point(sX, sY - 8),
    												 cv::FONT_HERSHEY_SIMPLEX,1,
    												 cv::Scalar(0,255,0),2);
    					//draw circle
    					cv::circle(frame, cv::Point(centerX, centerY), 5, cv::Scalar(0, 0, 255), -1);
    				}
    			}
    
    			memcpy(data, frame.data, width * height * 3);					
    		}
    		
    
    		// send stream
    		// encode H264
    		RK_MPI_VENC_SendFrame(0, &stVpssFrame,-1);
    		// rtsp
    		s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			if(g_rtsplive && g_rtsp_session)
    			{
    				//printf("len = %d PTS = %d \n",stFrame.pstPack->u32Len, stFrame.pstPack->u64PTS);
    				
    				void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
    				rtsp_tx_video(g_rtsp_session, (uint8_t *)pData, stFrame.pstPack->u32Len,
    							  stFrame.pstPack->u64PTS);
    				rtsp_do_event(g_rtsplive);
    			}
    		}
    
    		// release frame 
    		s32Ret = RK_MPI_VPSS_ReleaseChnFrame(0, 0, &stVpssFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
    		}
    		s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
    			}
    		memset(text,0,8);
    		}
    	}else if(child_pid >0){
    		//UART handle
    		char rx_buffer[256];
    		int status;
    		while(1){
    		int ret = waitpid(child_pid, &status,WNOHANG);
    		int bytes_read=read(serial_fd,rx_buffer,sizeof(rx_buffer));
    		if(bytes_read < 0){
    		perror("receive error");
    		}else{
    			rx_buffer[bytes_read]='\0';
    			//printf("RX:%s\n",rx_buffer);
    			write(serial_fd,rx_buffer,sizeof(rx_buffer));
    			rx_buffer_Handle(rx_buffer);
    		}
    		memset(rx_buffer,0,sizeof(rx_buffer));
    		if(ret>0)
    		{
    			close(serial_fd);
    			exit(0);
    		}
    		}
    		
    	}
    
    	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
    	
    	RK_MPI_VI_DisableChn(0, 0);
    	RK_MPI_VI_DisableDev(0);
    	
    	RK_MPI_VPSS_StopGrp(0);
    	RK_MPI_VPSS_DestroyGrp(0);
    	
    	RK_MPI_VENC_StopRecvFrame(0);
    	RK_MPI_VENC_DestroyChn(0);
    
    	free(stFrame.pstPack);
    
    	if (g_rtsplive)
    	rtsp_del_demo(g_rtsplive);
    	SAMPLE_COMM_ISP_Stop(0);
    
    	RK_MPI_SYS_Exit();
    	// Release rknn model
        release_yolov5_model(&rknn_app_ctx);		
        deinit_post_process();
    	
    	return 0;
    }
    
    
    我添加了串口3打印的逻辑,并且分为了父子进程,父进程用来处理发送过来的串口数据并做出相应系统操作,子进程用于发送RKNN推理结果,并且加入了SIGINT(ctrl+c信号)的处理函数,用于释放while循环之后一直没有被释放的资源,并将涉及到释放的资源弄成了全局变量,也添加了一些子进程的回收操作,想问这个从串口三判断完数据后用system(“lINUX指令”)方式执行操作这样的方式可行吗如下代码

    Code: Select all

    void rx_buffer_Handle(char *p)
    {
    if(strncmp(p,"close",5)==0){
    	//close demo
    	exit(0);
    }else if(strncmp(p,"reboot",5)==0){
    	//reboot system
    	system("reboot");
    }else if(strncmp(p,"rkill",5)==0){
    	//killall rkipc
    	system("killall rkipc");
    }	
    还是需要写一些执行脚本(包含Linux指令)去调用脚本运行Linux指令呢?如果要写的话执行脚本是怎样的格式呢放在哪里比较合适呢?另外这个自启动想要直接运行这个程序的话可以在inid中写一个开机启动执行这个demo的话,格式有什么要求吗
    您好,rx_buffer_Handle 调用 system 来执行 shell 命令这种方式是可行的,exit(0) 会立刻结束程序并回收程序的内存空间但是不会回收 malloc 或者 rkmpi 申请的动态内存,这可能会导致内存泄漏的问题。建议还是使用退出 while 循环的方式使用 RKMPI 资源回收 API 来结束程序的运行。
    相应的方法可以参考 Linux 多线程编程中共享变量、管道、消息队列的方式,比如创建一个全局变量 quit ,循环程序在 while(!quit) 中运行,通过修改quit就可以退出 while 循环。

    开机启动程序的脚本请参考 shell 脚本编写,如果只需要简单的执行程序,可以在 init.d 文件夹下创建 S99code

    Code: Select all

    cd <可支持文件所在文件夹>
    ./<可执行文件>
    
    您好我看了/home/alientek/sdk_RV1106/luckfox-pico-main/media/samples/simple_test下面的simple_vi_venc_rtsp.c中的代码,并对我的代码运用线程和!quit全局变量进行了修改,虽然成功编译并运行但是一但运用ctrl+c信号阻断运行就会发现他会进入信号处理函数但是并且关闭了串口输出和程序输出,但是程序却不能停止下来了,如下图所示,尝试了好几回ctrl+c去阻止运行一直卡在了这里,不知道是哪里的问题,而且我想是不是这个ctrl+c时他只会仅信号处理函数但是不会再回到主函数进行运行,那么这个quit可能就没了作用
    Image
    我修改后的代码如下:

    Code: Select all

    #include <assert.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <getopt.h>
    #include <pthread.h>
    #include <signal.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/poll.h>
    #include <sys/types.h>
    #include <sys/wait.h> 
    #include <time.h>
    #include <unistd.h>
    #include <vector>
    #include <termios.h>
    
    #include "rtsp_demo.h"
    #include "sample_comm.h"
    #include "yolov5.h"
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    
    // disp size
    int width    = 720;
    int height   = 480;
    
    // model size
    int model_width = 640;
    int model_height = 640;	
    float scale ;
    int leftPadding ;
    int topPadding  ;
    //handle while function
    static bool quit=false;
    
    static RK_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) {
    	printf("%s\n",__func__);
    	VENC_RECV_PIC_PARAM_S stRecvParam;
    	VENC_CHN_ATTR_S stAttr;
    	memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S));
    
    	// RTSP H264	
    	stAttr.stVencAttr.enType = enType;
    	//stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stAttr.stVencAttr.enPixelFormat = RK_FMT_RGB888;	
    	stAttr.stVencAttr.u32Profile = H264E_PROFILE_MAIN;
    	stAttr.stVencAttr.u32PicWidth = width;
    	stAttr.stVencAttr.u32PicHeight = height;
    	stAttr.stVencAttr.u32VirWidth = width;
    	stAttr.stVencAttr.u32VirHeight = height;
    	stAttr.stVencAttr.u32StreamBufCnt = 2;
    	stAttr.stVencAttr.u32BufSize = width * height * 3 / 2;
    	stAttr.stVencAttr.enMirror = MIRROR_NONE;
    		
    	stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    	stAttr.stRcAttr.stH264Cbr.u32BitRate = 3 * 1024;
    	stAttr.stRcAttr.stH264Cbr.u32Gop = 1;
    	RK_MPI_VENC_CreateChn(chnId, &stAttr);
    
    	memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
    	stRecvParam.s32RecvPicNum = -1;
    	RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);
    
    	return 0;
    }
    
    
    // demo板dev默认都是0,根据不同的channel 来选择不同的vi节点
    int vi_dev_init() {
    	printf("%s\n", __func__);
    	int ret = 0;
    	int devId = 0;
    	int pipeId = devId;
    
    	VI_DEV_ATTR_S stDevAttr;
    	VI_DEV_BIND_PIPE_S stBindPipe;
    	memset(&stDevAttr, 0, sizeof(stDevAttr));
    	memset(&stBindPipe, 0, sizeof(stBindPipe));
    	// 0. get dev config status
    	ret = RK_MPI_VI_GetDevAttr(devId, &stDevAttr);
    	if (ret == RK_ERR_VI_NOT_CONFIG) {
    		// 0-1.config dev
    		ret = RK_MPI_VI_SetDevAttr(devId, &stDevAttr);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevAttr %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_SetDevAttr already\n");
    	}
    	// 1.get dev enable status
    	ret = RK_MPI_VI_GetDevIsEnable(devId);
    	if (ret != RK_SUCCESS) {
    		// 1-2.enable dev
    		ret = RK_MPI_VI_EnableDev(devId);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_EnableDev %x\n", ret);
    			return -1;
    		}
    		// 1-3.bind dev/pipe
    		stBindPipe.u32Num = pipeId;
    		stBindPipe.PipeId[0] = pipeId;
    		ret = RK_MPI_VI_SetDevBindPipe(devId, &stBindPipe);
    		if (ret != RK_SUCCESS) {
    			printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
    			return -1;
    		}
    	} else {
    		printf("RK_MPI_VI_EnableDev already\n");
    	}
    
    	return 0;
    }
    
    int vi_chn_init(int channelId, int width, int height) {
    	int ret;
    	int buf_cnt = 2;
    	// VI init
    	VI_CHN_ATTR_S vi_chn_attr;
    	memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
    	vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
    	vi_chn_attr.stIspOpt.enMemoryType =
    	    VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
    	vi_chn_attr.stSize.u32Width = width;
    	vi_chn_attr.stSize.u32Height = height;
    	vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
    	vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE; // COMPRESS_AFBC_16x16;
    	vi_chn_attr.u32Depth = 2;
    	ret = RK_MPI_VI_SetChnAttr(0, channelId, &vi_chn_attr);
    	ret |= RK_MPI_VI_EnableChn(0, channelId);
    	if (ret) {
    		printf("ERROR: create VI error! ret=%d\n", ret);
    		return ret;
    	}
    
    	return ret;
    }
    
    int test_vpss_init(int VpssChn, int width, int height) {
    	printf("%s\n",__func__);
    	int s32Ret;
    	VPSS_CHN_ATTR_S stVpssChnAttr;
    	VPSS_GRP_ATTR_S stGrpVpssAttr;
    
    	int s32Grp = 0;
    
    	stGrpVpssAttr.u32MaxW = 4096;
    	stGrpVpssAttr.u32MaxH = 4096;
    	stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
    	stGrpVpssAttr.stFrameRate.s32SrcFrameRate = -1;
    	stGrpVpssAttr.stFrameRate.s32DstFrameRate = -1;
    	stGrpVpssAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	stVpssChnAttr.enChnMode = VPSS_CHN_MODE_USER;
    	stVpssChnAttr.enDynamicRange = DYNAMIC_RANGE_SDR8;
    	stVpssChnAttr.enPixelFormat = RK_FMT_RGB888;
    	stVpssChnAttr.stFrameRate.s32SrcFrameRate = -1;
    	stVpssChnAttr.stFrameRate.s32DstFrameRate = -1;
    	stVpssChnAttr.u32Width = width;
    	stVpssChnAttr.u32Height = height;
    	stVpssChnAttr.enCompressMode = COMPRESS_MODE_NONE;
    
    	s32Ret = RK_MPI_VPSS_CreateGrp(s32Grp, &stGrpVpssAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_SetChnAttr(s32Grp, VpssChn, &stVpssChnAttr);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	s32Ret = RK_MPI_VPSS_EnableChn(s32Grp, VpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    
    	s32Ret = RK_MPI_VPSS_StartGrp(s32Grp);
    	if (s32Ret != RK_SUCCESS) {
    		return s32Ret;
    	}
    	return s32Ret;
    }
    
    cv::Mat letterbox(cv::Mat input)
    {
    	float scaleX = (float)model_width  / (float)width; //0.888
    	float scaleY = (float)model_height / (float)height; //1.125	
    	scale = scaleX < scaleY ? scaleX : scaleY;
    	
    	int inputWidth   = (int)((float)width * scale);
    	int inputHeight  = (int)((float)height * scale);
    
    	leftPadding = (model_width  - inputWidth) / 2;
    	topPadding  = (model_height - inputHeight) / 2;	
    	
    
    	cv::Mat inputScale;
        cv::resize(input, inputScale, cv::Size(inputWidth,inputHeight), 0, 0, cv::INTER_LINEAR);	
    	cv::Mat letterboxImage(640, 640, CV_8UC3,cv::Scalar(0, 0, 0));
        cv::Rect roi(leftPadding, topPadding, inputWidth, inputHeight);
        inputScale.copyTo(letterboxImage(roi));
    
    	return letterboxImage; 	
    }
    
    void mapCoordinates(int *x, int *y) {	
    	int mx = *x - leftPadding;
    	int my = *y - topPadding;
    
        *x = (int)((float)mx / scale);
        *y = (int)((float)my / scale);
    }
    void rx_buffer_Handle(char *p)
    {
    if(strncmp(p,"close",5)==0){
    	//close demo
    	//exit(0);
    }else if(strncmp(p,"reboot",5)==0){
    	//reboot system
    	system("reboot");
    }else if(strncmp(p,"rkill",5)==0){
    	//killall rkipc
    	system("killall rkipc");
    }	
    }
    
    
    rtsp_demo_handle g_rtsplive = NULL;
    rknn_app_context_t rknn_app_ctx;
    MPP_CHN_S stSrcChn, stvpssChn;
    VENC_STREAM_S stFrame;
    int serial_fd;
    //parameter release
    
    void sigint_handler(int sig){
    	//release
    	fprintf(stderr, "signal %d-------------------------------\n", sig);
    	quit=true;
    }
    static void *User_Handle(void *arg){
    		//UART handle
    		char rx_buffer[256];
    		while(!quit){
    		int bytes_read=read(serial_fd,rx_buffer,sizeof(rx_buffer));
    		if(bytes_read < 0){
    		perror("receive error");
    		}else{
    			rx_buffer[bytes_read]='\0';
    			//printf("RX:%s\n",rx_buffer);
    			write(serial_fd,rx_buffer,bytes_read);
    			rx_buffer_Handle(rx_buffer);
    		}
    		memset(rx_buffer,0,sizeof(rx_buffer));
    		}
    }
    
    
    int main(int argc, char *argv[]) {
    	
    
    
    	RK_S32 s32Ret = 0; 
    	int sX,sY,eX,eY; 
    		
    	// Rknn model
    	char text[16];
    		
    	object_detect_result_list od_results;
        int ret;
    	const char *model_path = "./model/yolov5.rknn";
        memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));	
        init_yolov5_model(model_path, &rknn_app_ctx);
    	printf("init rknn model success!\n");
        init_post_process();
    
    	//h264_frame	
    		
    	stFrame.pstPack = (VENC_PACK_S *)malloc(sizeof(VENC_PACK_S));
     	VIDEO_FRAME_INFO_S h264_frame;
     	VIDEO_FRAME_INFO_S stVpssFrame;
    
    	// rkaiq init
    	RK_BOOL multi_sensor = RK_FALSE;	
    	const char *iq_dir = "/etc/iqfiles";
    	rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
    	//hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
    	SAMPLE_COMM_ISP_Init(0, hdr_mode, multi_sensor, iq_dir);
    	SAMPLE_COMM_ISP_Run(0);
    
    	// rkmpi init
    	if (RK_MPI_SYS_Init() != RK_SUCCESS) {
    		RK_LOGE("rk mpi sys init fail!");
    		return -1;
    	}
    
    	// rtsp init	
    	
    	rtsp_session_handle g_rtsp_session;
    	g_rtsplive = create_rtsp_demo(554);
    	g_rtsp_session = rtsp_new_session(g_rtsplive, "/live/0");
    	rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);
    	rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());
    	
    	// vi init
    	vi_dev_init();
    	vi_chn_init(0, width, height);
    
    	// vpss init
    	test_vpss_init(0, width, height);
    
    	// bind vi to vpss
    	
    	stSrcChn.enModId = RK_ID_VI;
    	stSrcChn.s32DevId = 0;
    	stSrcChn.s32ChnId = 0;
    
    	stvpssChn.enModId = RK_ID_VPSS;
    	stvpssChn.s32DevId = 0;
    	stvpssChn.s32ChnId = 0;
    	printf("====RK_MPI_SYS_Bind vi0 to vpss0====\n");
    	s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stvpssChn);
    	if (s32Ret != RK_SUCCESS) {
    		RK_LOGE("bind 0 ch venc failed");
    		return -1;
    	}
    
    	// venc init
    	RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_AVC;
    	test_venc_init(0, width, height, enCodecType);
    	printf("venc init success\n");
    
    	//uart3 init
    	int serial_port_num;
        const char serial_port[] = "/dev/ttyS3";
        
    	signal(SIGINT, sigint_handler);
    
        serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
        if (serial_fd == -1) {
            perror("Failed to open serial port");
            return 1;
        }
    
        struct termios tty;
        memset(&tty, 0, sizeof(tty));
    
        if (tcgetattr(serial_fd, &tty) != 0) {
            perror("Error from tcgetattr");
            return 1;
        }
    
        cfsetospeed(&tty, B9600);
        cfsetispeed(&tty, B9600);
    
        tty.c_cflag &= ~PARENB;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CSIZE;
        tty.c_cflag |= CS8;
    
        if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
            perror("Error from tcsetattr");
            return 1;
        }
    
    	//init fork
    	char tx_buffer[256];
    	pthread_t Handle_thread;
    	pthread_create(&Handle_thread, NULL, User_Handle, NULL);
    	
    	while(!quit)
    	{	
    		// get vpss frame
    		s32Ret = RK_MPI_VPSS_GetChnFrame(0,0, &stVpssFrame,-1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);	
    			//opencv	
    			cv::Mat frame(height,width,CV_8UC3,data);			
    			//cv::Mat frame640;
            	//cv::resize(frame, frame640, cv::Size(640,640), 0, 0, cv::INTER_LINEAR);	
    			//letterbox
    			cv::Mat letterboxImage = letterbox(frame);	
    			memcpy(rknn_app_ctx.input_mems[0]->virt_addr, letterboxImage.data, model_width*model_height*3);		
    			inference_yolov5_model(&rknn_app_ctx, &od_results);
    
    			for(int i = 0; i < od_results.count; i++)
    			{					
    				//获取框的四个坐标 
    				if(od_results.count >= 1)
    				{
    					object_detect_result *det_result = &(od_results.results[i]);
    					/*printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
    							 det_result->box.left, det_result->box.top,
    							 det_result->box.right, det_result->box.bottom,
    							 det_result->prop);
    					*/
    					sX = (int)(det_result->box.left   );	
    					sY = (int)(det_result->box.top 	  );	
    					eX = (int)(det_result->box.right  );	
    					eY = (int)(det_result->box.bottom );
    					int centerX = (sX + eX) / 2;
    					int centerY = (sY + eY) / 2;
    					// printf("$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    					// 		 centerX,centerY,det_result->prop,
    					// 		 det_result->box.left,det_result->box.right,
    					// 		 det_result->box.top,det_result->box.bottom
    					// 		 );
    					sprintf(tx_buffer,"$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
    							 centerX,centerY,det_result->prop,
    							 det_result->box.left,det_result->box.right,
    							 det_result->box.top,det_result->box.bottom
    							 );
    					//send rknn result
    					write(serial_fd,tx_buffer,strlen(tx_buffer));
    					memset(tx_buffer,0,sizeof(tx_buffer));
    					mapCoordinates(&sX,&sY);
    					mapCoordinates(&eX,&eY);
    
    					cv::rectangle(frame,cv::Point(sX ,sY),
    								        cv::Point(eX ,eY),
    										cv::Scalar(0,255,0),3);
    					sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
    					cv::putText(frame,text,cv::Point(sX, sY - 8),
    												 cv::FONT_HERSHEY_SIMPLEX,1,
    												 cv::Scalar(0,255,0),2);
    					//draw circle
    					cv::circle(frame, cv::Point(centerX, centerY), 5, cv::Scalar(0, 0, 255), -1);
    				}
    			}
    			memcpy(data, frame.data, width * height * 3);					
    		}
    		
    
    		// send stream
    		// encode H264
    		RK_MPI_VENC_SendFrame(0, &stVpssFrame,-1);
    		// rtsp
    		s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
    		if(s32Ret == RK_SUCCESS)
    		{
    			if(g_rtsplive && g_rtsp_session)
    			{
    				//printf("len = %d PTS = %d \n",stFrame.pstPack->u32Len, stFrame.pstPack->u64PTS);
    				
    				void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
    				rtsp_tx_video(g_rtsp_session, (uint8_t *)pData, stFrame.pstPack->u32Len,
    							  stFrame.pstPack->u64PTS);
    				rtsp_do_event(g_rtsplive);
    			}
    		}
    		// release frame 
    		s32Ret = RK_MPI_VPSS_ReleaseChnFrame(0, 0, &stVpssFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
    		}
    		s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
    		if (s32Ret != RK_SUCCESS) {
    			RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
    			}
    		memset(text,0,8);
    		}
    	//release thread
    	pthread_join(Handle_thread, NULL);
    	printf("exit result enter--------------------------------------------------------------------------------------------\n");
    	close(serial_fd);
    	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
    	
    	RK_MPI_VI_DisableChn(0, 0);
    	RK_MPI_VI_DisableDev(0);
    	
    	RK_MPI_VPSS_StopGrp(0);
    	RK_MPI_VPSS_DestroyGrp(0);
    	
    	RK_MPI_VENC_StopRecvFrame(0);
    	RK_MPI_VENC_DestroyChn(0);
    
    	free(stFrame.pstPack);
    
    	if (g_rtsplive)
    	rtsp_del_demo(g_rtsplive);
    	SAMPLE_COMM_ISP_Stop(0);
    
    	RK_MPI_SYS_Exit();
    	// Release rknn model
        release_yolov5_model(&rknn_app_ctx);		
        deinit_post_process();
    	
    	return 0;
    }
    
    但是他有信号ctrl+c时卡死了并不会退出程序
    上述的应该是我的线程中while循环里面设置了read函数导致我串口没有输入时阻塞在了read函数中导致没有办法判断quit变量改变退出进行回收资源的处理,但是还有一个串口输出的问题就是他这个会有的时候多包一起发送这个该如何处理呢
    Image

    Code: Select all

    [10:48:11.041]收←◆$RV1106,tv,103,237,0.258,0,206,109,365
    
    [10:48:11.360]收←◆$RV1106,tv,105,236,0.301,0,210,106,366
    
    [10:48:11.521]收←◆$RV1106,tv,109,234,0.261,1,217,107,361
    
    [10:48:12.321]收←◆$RV1106,person,365,453,0.457,243,487,376,531
    $RV1106,person,281,207,0.329,217,346,108,307
    $RV1106,person,430,306,0.275,223,638,105,508
    $RV1106,person,441,311,0.346,245,637,110,513
    
    [10:48:17.594]收←◆$RV1106,tv,143,234,0.264,0,286,108,360
    
    [10:48:17.764]收←◆$RV1106,tv,146,234,0.252,0,292,104,365
    
    [11:21:07.874]发→◇reboot
    
    □
    [11:21:07.891]收←◆reboot
    
    
    
    reboot
    
    [11:21:12.204]收←◆\0
    Attachments
    串口输出.png
  • 首先恭喜您找到了while循环跳出失败的原因,对于串口输出的问题目前来看并不是在硬件通信或者模型推理上出现问题,目前来看您的程序还存在优化空间,可能会出现结果丢失等情况,建议尝试其他线程间通讯方式、引入同步与互斥机制来保证系统运行的稳定性。
    如果串口的接收端是单片机您获取可以尝试在接收端对输出的结果进行过滤,实现您需要的效果。

    注意:原代码在模型推理结束之后的的打印信息是针对 letterbox 处理后的图像的,如果要获取输入图像对应的被识别物体的坐标,请使用mapCoordinates 处理后的坐标作为结果而不是 det_result->box 的结果。

    希望您能顺利解决问题。
  • chenmodegaoyang wrote: 2024-02-26 9:33 好的,我试着用串口三进行另一个单片机的数据的读取和给另外一个单片机进行发送推理结果,这个阶段中我用了父子进程,这个时候是父进程回收子进程和不断循环读取数据进行判断,子进程是发送rknn推理结果,这个时候在处理子进程回收时,发现这个demo中的代码所有的回收资源处理都是在while循环之后进行但是我每次结束程序的时候却是用的CTRL+C进行的意外终止,这可能导致while后面的释放函数没有被调用,这个关于资源回收的话需要注意哪些方面呢,是不是需要把所有的释放资源的函数放入到信号处理函数中使用并且把对应参数弄成全局变量呢,或者有没有更简单的释放方法吗?
    Crocodile wrote: 2024-02-26 7:30
    chenmodegaoyang wrote: 2024-02-26 6:31

    您好很感谢您提出的解决方法,还想问一下这个串口的话官方给的串口调试是用的串口一,这个串口可以进入根文件系统调试,进入时需要输入密码和账号,函数中打印的函数输出的我发现串口一也有对应输出,但是因为有根文件系统的影响,还需要通过串口进行一些Linux指令的操作才可以运行程序和关闭程序等,这个如果单独就想当做串口输出和接收数据使用和判断,不做调试进入根文件系统,是在代码中写入开启其他的串口吗?还是都必须进入根文件系统进行操作?
    您好,调试串口理论上可以通过调整 printk 的打印等级来屏蔽等级信息,但是由于这是一个可交互的串口,直接用来实现您需要的功能可能因为各种问题导致您的控制失败。

    推荐使用不被系统占用的 串口三 和 串口四 来作为您进行控制的串口,串口三 和 串口四 可以单独做串口输出和接收数据判断,可以控制输出指定内容,调试串口的输出不仅包含了 printf 输出的内容也包含了其他模块的打印信息。

    用串口调试需要登录后才能进入根文件系统进行指令操作,但是在 rootfs 的加载结束阶段后立即执行 /etc/init.d/rcS 脚本,运行流程是在验证登录之前。

    您可以通过开机脚本来实现您需要的功能,假设您目前使用串口三,您可以将编译好的可执行文件放置在/usr/bin 中。添加开机脚本 S99uart3control (99表示打印的顺序,越大越晚执行)到 /etc/init.d 中,使 rootfs 加载后执行串口控制程序。您在 luckfox-pico 初始化后就可以直接使用其他单片机的串口来控制 luckfox-pico 。
    您好我用了您上述的所说的开机启动方法,并在usr/bin下把lib和model和luckfox_rtsp_yolov5可执行文件放入
    我的shell脚本如下

    Code: Select all

    # #!/bin/sh
    #
    # case $1 in
    >         start)
    >                 echo"-----------boot yolov5_demo_rtsp_on_uart3--------"
    >                 killall rkipc
    >                 cd /usr/bin
    >                 if [ "$PWD" = "/usr/bin" ]; then
    >                         ./luckfox_rtsp_yolov5
    >                 fi
    >                 ;;
    >         stop)
    >                 ;;
    >         *)
    >                 exit 1
    >                 ;;
    > esac
    
    并且chmod 775 给了执行权限,通过串口调试发现他没办法找到这个文件夹并且显示无法加载librockiva.so这个库
    Image
    这个要怎么解决呢
    Attachments
    启动脚本.png
  • chenmodegaoyang wrote: 2024-02-27 8:32
    chenmodegaoyang wrote: 2024-02-26 9:33 好的,我试着用串口三进行另一个单片机的数据的读取和给另外一个单片机进行发送推理结果,这个阶段中我用了父子进程,这个时候是父进程回收子进程和不断循环读取数据进行判断,子进程是发送rknn推理结果,这个时候在处理子进程回收时,发现这个demo中的代码所有的回收资源处理都是在while循环之后进行但是我每次结束程序的时候却是用的CTRL+C进行的意外终止,这可能导致while后面的释放函数没有被调用,这个关于资源回收的话需要注意哪些方面呢,是不是需要把所有的释放资源的函数放入到信号处理函数中使用并且把对应参数弄成全局变量呢,或者有没有更简单的释放方法吗?
    Crocodile wrote: 2024-02-26 7:30

    您好,调试串口理论上可以通过调整 printk 的打印等级来屏蔽等级信息,但是由于这是一个可交互的串口,直接用来实现您需要的功能可能因为各种问题导致您的控制失败。

    推荐使用不被系统占用的 串口三 和 串口四 来作为您进行控制的串口,串口三 和 串口四 可以单独做串口输出和接收数据判断,可以控制输出指定内容,调试串口的输出不仅包含了 printf 输出的内容也包含了其他模块的打印信息。

    用串口调试需要登录后才能进入根文件系统进行指令操作,但是在 rootfs 的加载结束阶段后立即执行 /etc/init.d/rcS 脚本,运行流程是在验证登录之前。

    您可以通过开机脚本来实现您需要的功能,假设您目前使用串口三,您可以将编译好的可执行文件放置在/usr/bin 中。添加开机脚本 S99uart3control (99表示打印的顺序,越大越晚执行)到 /etc/init.d 中,使 rootfs 加载后执行串口控制程序。您在 luckfox-pico 初始化后就可以直接使用其他单片机的串口来控制 luckfox-pico 。
    您好我用了您上述的所说的开机启动方法,并在usr/bin下把lib和model和luckfox_rtsp_yolov5可执行文件放入
    我的shell脚本如下

    Code: Select all

    # #!/bin/sh
    #
    # case $1 in
    >         start)
    >                 echo"-----------boot yolov5_demo_rtsp_on_uart3--------"
    >                 killall rkipc
    >                 cd /usr/bin
    >                 if [ "$PWD" = "/usr/bin" ]; then
    >                         ./luckfox_rtsp_yolov5
    >                 fi
    >                 ;;
    >         stop)
    >                 ;;
    >         *)
    >                 exit 1
    >                 ;;
    > esac
    
    并且chmod 775 给了执行权限,通过串口调试发现他没办法找到这个文件夹并且显示无法加载librockiva.so这个库
    Image
    这个要怎么解决呢
    上面帖子如果不用启动文件,直接去usr/bin下运行时可以运行的并且不报错,而且生成的demo文件夹下的lib文件夹中也没有这个上述说的连接的库也可以运行成功,但是已放到启动脚本中就会提示缺少这些库
  • chenmodegaoyang wrote: 2024-02-27 8:32
    chenmodegaoyang wrote: 2024-02-26 9:33 好的,我试着用串口三进行另一个单片机的数据的读取和给另外一个单片机进行发送推理结果,这个阶段中我用了父子进程,这个时候是父进程回收子进程和不断循环读取数据进行判断,子进程是发送rknn推理结果,这个时候在处理子进程回收时,发现这个demo中的代码所有的回收资源处理都是在while循环之后进行但是我每次结束程序的时候却是用的CTRL+C进行的意外终止,这可能导致while后面的释放函数没有被调用,这个关于资源回收的话需要注意哪些方面呢,是不是需要把所有的释放资源的函数放入到信号处理函数中使用并且把对应参数弄成全局变量呢,或者有没有更简单的释放方法吗?
    Crocodile wrote: 2024-02-26 7:30

    您好,调试串口理论上可以通过调整 printk 的打印等级来屏蔽等级信息,但是由于这是一个可交互的串口,直接用来实现您需要的功能可能因为各种问题导致您的控制失败。

    推荐使用不被系统占用的 串口三 和 串口四 来作为您进行控制的串口,串口三 和 串口四 可以单独做串口输出和接收数据判断,可以控制输出指定内容,调试串口的输出不仅包含了 printf 输出的内容也包含了其他模块的打印信息。

    用串口调试需要登录后才能进入根文件系统进行指令操作,但是在 rootfs 的加载结束阶段后立即执行 /etc/init.d/rcS 脚本,运行流程是在验证登录之前。

    您可以通过开机脚本来实现您需要的功能,假设您目前使用串口三,您可以将编译好的可执行文件放置在/usr/bin 中。添加开机脚本 S99uart3control (99表示打印的顺序,越大越晚执行)到 /etc/init.d 中,使 rootfs 加载后执行串口控制程序。您在 luckfox-pico 初始化后就可以直接使用其他单片机的串口来控制 luckfox-pico 。
    您好我用了您上述的所说的开机启动方法,并在usr/bin下把lib和model和luckfox_rtsp_yolov5可执行文件放入
    我的shell脚本如下

    Code: Select all

    # #!/bin/sh
    #
    # case $1 in
    >         start)
    >                 echo"-----------boot yolov5_demo_rtsp_on_uart3--------"
    >                 killall rkipc
    >                 cd /usr/bin
    >                 if [ "$PWD" = "/usr/bin" ]; then
    >                         ./luckfox_rtsp_yolov5
    >                 fi
    >                 ;;
    >         stop)
    >                 ;;
    >         *)
    >                 exit 1
    >                 ;;
    > esac
    
    并且chmod 775 给了执行权限,通过串口调试发现他没办法找到这个文件夹并且显示无法加载librockiva.so这个库
    Image
    这个要怎么解决呢
    您好,出现这种情况是因为启动脚本运行时找不到 oem 下面的动态链接库,尝试将 /oem/usr/lib 中的动态链接库移动到 /usr/lib 中。