Hi3559AV100外接UVC/MJPEG相机实时采图设计(三):V4L2接口通过MPP平台输出

可以首先参考前面两篇文章:

Hi3559AV100外接UVC/MJPEG相机实时采图设计(一):Linux USB摄像头驱动分析:

https://www.cnblogs.com/iFrank/p/14399421.html

Hi3559AV100外接UVC/MJPEG相机实时采图设计(二):V4L2接口的实现(以YUV422为例):

https://www.cnblogs.com/iFrank/p/14403397.html

  下面将给出Hi3559AV100外接UVC/MJPEG相机实时采图设计的整体流程,主要实现是通过V4L2接口将UVC/MJPEG相机采集的数据送入至MPP平台,经过VDEC、VPSS、VO最后通过HDMI的输出,最后给出(三)V4L2接口通过MPP平台输出。

板载平台:BOXER-8410AI

芯片型号:Hi3559AV100

相机型号:Logitch c270

开发环境:VM15.5+ubuntu16.04+Hilinux

1、V4L2接口经MPP平台输出通路

  这一篇随笔是给出V4L2接口通过MPP平台下VDEC、VPSS、VO最后通过HDMI视频流输出,实现了如下通路:

Hi3559AV100外接UVC/MJPEG相机实时采图设计(三):V4L2接口通过MPP平台输出

 

  其中的SD Card改为mmap内存映射空间数据,经V4L2接口一帧一帧数据进行传输。其他相关介绍可以参考:

基于Hi3559AV100的视频采集(VDEC-VPSS-VO)整体框图设计

https://www.cnblogs.com/iFrank/p/14370575.html

 2、实现方案

Hi3559AV100外接UVC/MJPEG相机实时采图设计(三):V4L2接口通过MPP平台输出

 

 

   给出具体的实现代码,下面为main函数:

  1 /******************************************************************************
  2 * function    : main()
  3 * Description : video ouput
  4 ******************************************************************************/
  5 #ifdef __HuaweiLite__
  6     int app_main(int argc, char *argv[])
  7 #else
  8     int main(int argc, char *argv[])
  9 #endif
 10 {
 11     HI_S32 s32Ret = HI_SUCCESS;
 12 
 13     // *******   V4L2    **********
 14     ///*
 15     if(init_v4l2() == FALSE) 
 16     {
 17     return(FALSE);
 18     }
 19     
 20     v4l2_mmap();
 21 
 22 
 23     if(start_v4l2() == FALSE)
 24     { 
 25     return(FALSE);
 26     }
 27     
 28     //*/
 29     //*********** **************
 30 
 31 
 32     if ((argc < 2) || (1 != strlen(argv[1])))
 33     {
 34         printf("\nInvaild input!  For examples:\n");
 35         SAMPLE_VDEC_Usage(argv[0]);
 36         return HI_FAILURE;
 37     }
 38 
 39     if ((argc > 2) && ('1' == *argv[2]))
 40     {
 41         g_enIntfSync = VO_OUTPUT_1080P60;
 42     }
 43     else
 44     {
 45         g_enIntfSync = VO_OUTPUT_3840x2160_30;
 46     }
 47 
 48 #ifndef __HuaweiLite__
 49     signal(SIGINT, SAMPLE_VDEC_HandleSig);
 50     signal(SIGTERM, SAMPLE_VDEC_HandleSig);
 51 #endif
 52 
 53     /******************************************
 54      choose the case
 55     ******************************************/
 56     switch (*argv[1])
 57     {
 58         case '0':
 59         {
 60             s32Ret = SAMPLE_H265_VDEC_VPSS_VO();
 61             break;
 62         }
 63         case '1':
 64         {
 65             s32Ret = SAMPLE_H264_VDEC_VPSS_VO();
 66             break;
 67         }
 68         case '2':
 69         {
 70             s32Ret = SAMPLE_JPEG_VDEC_VPSS_VO();
 71             break;
 72         }
 73         case '3':
 74         {
 75             s32Ret = SAMPLE_JPEG_VDEC_To_RGB();
 76             break;
 77         }
 78         case '4':
 79         {
 80             s32Ret = SAMPLE_H264_VDEC_VPSS_VO_MIPI_Tx();
 81             break;
 82         }
 83         default :
 84         {
 85             SAMPLE_PRT("the index is invaild!\n");
 86             SAMPLE_VDEC_Usage(argv[0]);
 87             s32Ret = HI_FAILURE;
 88             break;
 89         }
 90     }
 91 
 92     if (HI_SUCCESS == s32Ret)
 93     {
 94         SAMPLE_PRT("program exit normally!\n");
 95     }
 96     else
 97     {
 98         SAMPLE_PRT("program exit abnormally!\n");
 99     }
100 
101     return s32Ret;
102 }

  给出细节实现函数代码(其中图片像素为640×480,像素格式为PT_MJPEG,HDMI输出设置为1080p60):

  1 HI_S32 SAMPLE_JPEG_VDEC_VPSS_VO(HI_VOID)
  2 {
  3     VB_CONFIG_S stVbConfig;
  4     HI_S32 i, s32Ret = HI_SUCCESS;
  5     VDEC_THREAD_PARAM_S stVdecSend[VDEC_MAX_CHN_NUM];
  6     SIZE_S stDispSize;
  7     VO_LAYER VoLayer;
  8     HI_U32 u32VdecChnNum, VpssGrpNum;
  9     VPSS_GRP VpssGrp;
 10     pthread_t   VdecThread[2*VDEC_MAX_CHN_NUM];
 11     PIC_SIZE_E enDispPicSize;
 12     SAMPLE_VDEC_ATTR astSampleVdec[VDEC_MAX_CHN_NUM];
 13     VPSS_CHN_ATTR_S astVpssChnAttr[VPSS_MAX_CHN_NUM];
 14     SAMPLE_VO_CONFIG_S stVoConfig;
 15     VPSS_GRP_ATTR_S stVpssGrpAttr;
 16     HI_BOOL abChnEnable[VPSS_MAX_CHN_NUM];
 17     VO_INTF_SYNC_E enIntfSync;
 18 
 19     u32VdecChnNum = 1;
 20     VpssGrpNum    = u32VdecChnNum;
 21 
 22 
 23     /************************************************
 24     step1:  init SYS, init common VB(for VPSS and VO)
 25     *************************************************/
 26     if(VO_OUTPUT_3840x2160_30 == g_enIntfSync)
 27     {
 28         enDispPicSize = PIC_3840x2160;
 29         enIntfSync    = VO_OUTPUT_3840x2160_30;
 30     }
 31     else
 32     {
 33         enDispPicSize = PIC_1080P;
 34         enIntfSync    = VO_OUTPUT_1080P60;
 35     }
 36 
 37     s32Ret =  SAMPLE_COMM_SYS_GetPicSize(enDispPicSize, &stDispSize);
 38     if(s32Ret != HI_SUCCESS)
 39     {
 40         SAMPLE_PRT("sys get pic size fail for %#x!\n", s32Ret);
 41         goto END1;
 42     }
 43 
 44     memset(&stVbConfig, 0, sizeof(VB_CONFIG_S));
 45     stVbConfig.u32MaxPoolCnt             = 1;
 46     stVbConfig.astCommPool[0].u32BlkCnt  = 10*u32VdecChnNum;
 47     stVbConfig.astCommPool[0].u64BlkSize = COMMON_GetPicBufferSize(stDispSize.u32Width, stDispSize.u32Height,
 48                                                 PIXEL_FORMAT_YVU_SEMIPLANAR_420, DATA_BITWIDTH_8, COMPRESS_MODE_SEG, 0);
 49     s32Ret = SAMPLE_COMM_SYS_Init(&stVbConfig);
 50     if(s32Ret != HI_SUCCESS)
 51     {
 52         SAMPLE_PRT("init sys fail for %#x!\n", s32Ret);
 53         goto END1;
 54     }
 55 
 56     /************************************************
 57     step2:  init module VB or user VB(for VDEC)
 58     *************************************************/
 59     for(i=0; i<u32VdecChnNum; i++)
 60     {
 61         astSampleVdec[i].enType                            = PT_MJPEG;
 62         astSampleVdec[i].u32Width                          = 640;
 63         astSampleVdec[i].u32Height                         = 480;
 64         astSampleVdec[i].enMode                            = VIDEO_MODE_FRAME;
 65         astSampleVdec[i].stSapmleVdecPicture.enPixelFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
 66         astSampleVdec[i].stSapmleVdecPicture.u32Alpha      = 255;
 67         astSampleVdec[i].u32DisplayFrameNum                = 2;
 68         astSampleVdec[i].u32FrameBufCnt                    = astSampleVdec[i].u32DisplayFrameNum + 1;
 69     }
 70     s32Ret = SAMPLE_COMM_VDEC_InitVBPool(u32VdecChnNum, &astSampleVdec[0]);
 71     if(s32Ret != HI_SUCCESS)
 72     {
 73         SAMPLE_PRT("init mod common vb fail for %#x!\n", s32Ret);
 74         goto END2;
 75     }
 76 
 77     /************************************************
 78     step3:  start VDEC
 79     *************************************************/
 80     s32Ret = SAMPLE_COMM_VDEC_Start(u32VdecChnNum, &astSampleVdec[0]);
 81     if(s32Ret != HI_SUCCESS)
 82     {
 83         SAMPLE_PRT("start VDEC fail for %#x!\n", s32Ret);
 84         goto END3;
 85     }
 86 
 87     /************************************************
 88     step4:  start VPSS
 89     *************************************************/
 90     stVpssGrpAttr.u32MaxW = 640;
 91     stVpssGrpAttr.u32MaxH = 480;
 92     stVpssGrpAttr.stFrameRate.s32SrcFrameRate = -1;
 93     stVpssGrpAttr.stFrameRate.s32DstFrameRate = -1;
 94     stVpssGrpAttr.enDynamicRange = DYNAMIC_RANGE_SDR8;
 95     stVpssGrpAttr.enPixelFormat  = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
 96     stVpssGrpAttr.bNrEn   = HI_FALSE;
 97 
 98     memset(abChnEnable, 0, sizeof(abChnEnable));
 99     abChnEnable[0] = HI_TRUE;
100     astVpssChnAttr[0].u32Width                    = stDispSize.u32Width;
101     astVpssChnAttr[0].u32Height                   = stDispSize.u32Height;
102     astVpssChnAttr[0].enChnMode                   = VPSS_CHN_MODE_AUTO;
103     astVpssChnAttr[0].enCompressMode              = COMPRESS_MODE_SEG;
104     astVpssChnAttr[0].enDynamicRange              = DYNAMIC_RANGE_SDR8;
105     astVpssChnAttr[0].enPixelFormat               = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
106     astVpssChnAttr[0].stFrameRate.s32SrcFrameRate = -1;
107     astVpssChnAttr[0].stFrameRate.s32DstFrameRate = -1;
108     astVpssChnAttr[0].u32Depth                    = 0;
109     astVpssChnAttr[0].bMirror                     = HI_FALSE;
110     astVpssChnAttr[0].bFlip                       = HI_FALSE;
111     astVpssChnAttr[0].stAspectRatio.enMode        = ASPECT_RATIO_NONE;
112     astVpssChnAttr[0].enVideoFormat               = VIDEO_FORMAT_LINEAR;
113 
114     for(i=0; i<u32VdecChnNum; i++)
115     {
116         VpssGrp = i;
117         s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp, &abChnEnable[0], &stVpssGrpAttr, &astVpssChnAttr[0]);
118         if(s32Ret != HI_SUCCESS)
119         {
120             SAMPLE_PRT("start VPSS fail for %#x!\n", s32Ret);
121             goto END4;
122         }
123     }
124 
125 
126 
127     /************************************************
128     step5:  start VO
129     *************************************************/
130     stVoConfig.VoDev                 = SAMPLE_VO_DEV_UHD;
131     stVoConfig.enVoIntfType          = VO_INTF_HDMI;
132     stVoConfig.enIntfSync            = enIntfSync;
133     stVoConfig.enPicSize             = enDispPicSize;
134     stVoConfig.u32BgColor            = COLOR_RGB_BLUE;
135     stVoConfig.u32DisBufLen          = 3;
136     stVoConfig.enDstDynamicRange     = DYNAMIC_RANGE_SDR8;
137     stVoConfig.enVoMode              = VO_MODE_1MUX;
138     stVoConfig.enPixFormat           = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
139     stVoConfig.stDispRect.s32X       = 0;
140     stVoConfig.stDispRect.s32Y       = 0;
141     stVoConfig.stDispRect.u32Width   = stDispSize.u32Width;
142     stVoConfig.stDispRect.u32Height  = stDispSize.u32Height;
143     stVoConfig.stImageSize.u32Width  = stDispSize.u32Width;
144     stVoConfig.stImageSize.u32Height = stDispSize.u32Height;
145     stVoConfig.enVoPartMode          = VO_PART_MODE_SINGLE;
146     s32Ret = SAMPLE_COMM_VO_StartVO(&stVoConfig);
147     if(s32Ret != HI_SUCCESS)
148     {
149         SAMPLE_PRT("start VO fail for %#x!\n", s32Ret);
150         goto END5;
151     }
152 
153     /************************************************
154     step6:  VDEC bind VPSS
155     *************************************************/
156     for(i=0; i<u32VdecChnNum; i++)
157     {
158         s32Ret = SAMPLE_COMM_VDEC_Bind_VPSS(i, i);
159         if(s32Ret != HI_SUCCESS)
160         {
161             SAMPLE_PRT("vdec bind vpss fail for %#x!\n", s32Ret);
162             goto END6;
163         }
164     }
165 
166     /************************************************
167     step7:  VPSS bind VO
168     *************************************************/
169     VoLayer = stVoConfig.VoDev;
170     for(i=0; i<VpssGrpNum; i++)
171     {
172         s32Ret = SAMPLE_COMM_VPSS_Bind_VO(i, 0, VoLayer, i);
173         if(s32Ret != HI_SUCCESS)
174         {
175             SAMPLE_PRT("vpss bind vo fail for %#x!\n", s32Ret);
176             goto END7;
177         }
178     }
179 
180 
181 
182     /************************************************
183     step8:  send stream to VDEC
184     *************************************************/
185     for(i=0; i<u32VdecChnNum; i++)
186     {
187     ////snprintf(stVdecSend[i].cFileName, sizeof(stVdecSend[i].cFileName), "3840x2160.jpg");
188         snprintf(stVdecSend[i].cFileName, sizeof(stVdecSend[i].cFileName), "txtjpeg.txt");
189 
190     //#define SAMPLE_STREAM_PATH "./source_file"
191         snprintf(stVdecSend[i].cFilePath, sizeof(stVdecSend[i].cFilePath), "%s", "/nfsroot");
192         stVdecSend[i].enType          = astSampleVdec[i].enType;
193         stVdecSend[i].s32StreamMode   = astSampleVdec[i].enMode;
194         stVdecSend[i].s32ChnId        = i;
195         stVdecSend[i].s32IntervalTime = 1000;
196         stVdecSend[i].u64PtsInit      = 0;
197         stVdecSend[i].u64PtsIncrease  = 0;
198         stVdecSend[i].eThreadCtrl     = THREAD_CTRL_START;
199         stVdecSend[i].bCircleSend     = HI_TRUE;
200         stVdecSend[i].s32MilliSec     = 0;
201         stVdecSend[i].s32MinBufSize   = (astSampleVdec[i].u32Width * astSampleVdec[i].u32Height * 3)>>1;
202     }
203             
204 
205 
206     SAMPLE_COMM_VDEC_StartSendStream(u32VdecChnNum, &stVdecSend[0], &VdecThread[0]);
207 
208     SAMPLE_COMM_VDEC_CmdCtrl(u32VdecChnNum, &stVdecSend[0], &VdecThread[0]);
209 
210     SAMPLE_COMM_VDEC_StopSendStream(u32VdecChnNum, &stVdecSend[0], &VdecThread[0]);
211 
212 END7:
213     for(i=0; i<VpssGrpNum; i++)
214     {
215         s32Ret = SAMPLE_COMM_VPSS_UnBind_VO(i, 0, VoLayer, i);
216         if(s32Ret != HI_SUCCESS)
217         {
218             SAMPLE_PRT("vpss unbind vo fail for %#x!\n", s32Ret);
219         }
220     }
221 
222 END6:
223     for(i=0; i<u32VdecChnNum; i++)
224     {
225         s32Ret = SAMPLE_COMM_VDEC_UnBind_VPSS(i, i);
226         if(s32Ret != HI_SUCCESS)
227         {
228             SAMPLE_PRT("vdec unbind vpss fail for %#x!\n", s32Ret);
229         }
230     }
231 
232 END5:
233     SAMPLE_COMM_VO_StopVO(&stVoConfig);
234 
235 END4:
236     for(i = VpssGrp; i >= 0; i--)
237     {
238         VpssGrp = i;
239         SAMPLE_COMM_VPSS_Stop(VpssGrp, &abChnEnable[0]);
240     }
241 
242 END3:
243     SAMPLE_COMM_VDEC_Stop(u32VdecChnNum);
244 
245 END2:
246     SAMPLE_COMM_VDEC_ExitVBPool();
247 
248 END1:
249     SAMPLE_COMM_SYS_Exit();
250 
251     return s32Ret;
252 }

  参考了sample_vdec.c、sample_common_vdec.c、sample_common_vpss.csample_common_vo.c等,定义了V4L2如下参数:

 1 /*******************************************************
 2     function announce
 3 *******************************************************/
 4 
 5 //@@@@@@@@@@@@@   V4L2  @@@@@@@@@@@
 6 #define  TRUE    1
 7 #define  FALSE    0
 8 
 9 
10 #define FILE_VIDEO     "/dev/video0"
11 
12  
13 #define  IMAGEWIDTH    640
14 #define  IMAGEHEIGHT   480
15  
16 int      video_fd;
17 struct   v4l2_capability   cap;
18 
19 struct v4l2_fmtdesc fmtdesc;
20 struct v4l2_format fmt;
21 struct v4l2_streamparm setfps;  
22 struct v4l2_requestbuffers req;
23 struct v4l2_buffer buf,readbuffer;
24 struct v4l2_buffer queuebuffer;
25 
26 int my_type;
27 
28 
29 //for v4l2_mmap function,to cache data
30 struct buffer
31 {
32     void * start;
33     unsigned int length;
34 }*buffers;
35 
36 
37 
38 int init_v4l2(void);
39 int start_v4l2(void);
40 int v4l2_mmap(void);
41 int stop_v4l2(void);
42 int close_v4l2(void);
43 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

3、视频流输出结果

  通过上述步骤最终实现了视频流通路,摄像头采集的图形能够实时的显示在显示屏上,具有良好的效果,现象如下(用手机进行了6s视频的录制,因为博客上不能上传视频,所以以截图进行表示,从结果可以看出,很好实现了视频流的输出且不卡帧):

Hi3559AV100外接UVC/MJPEG相机实时采图设计(三):V4L2接口通过MPP平台输出

 

上一篇:Go语言中的接口


下一篇:2021-02-19