Linux下V4L2框架基于SDL库本地USB摄像头监控

1.摄像头框架编程步骤
      (1)打开摄像头设备(/dev/video0 、/dev/video1 );
      (2)设置图像格式:vidioc_s_fmt(视频捕获格式、图像颜色数据格式、图像宽和高);
      (3)申请缓冲区:vidioc_reqbufs(缓冲区数量、缓冲映射方式、视频捕获格式);
      (4)将缓冲区映射到进程空间:vidioc_querybuf(要映射的缓冲区下标、缓冲映射方式、视频捕获格式);
      (5)将缓冲区添加到队列中:vidioc_qbuf(映射的缓冲区下标、缓冲映射方式、视频捕获格式);
      (6)开启摄像头采集:vidioc_streamon (视频捕获格式) (7)从采集队列中取出图像数据,通过sdl图像渲染;
2.摄像头v4l2框架应用编程示例
#include #include #include #include #include struct video{ int width;//摄像头采集图像宽 int height;//摄像头采集图像高 char *mmapbuf[4];//保存映射的地址 int mmap_size;/*映射缓冲区大小*/};/*摄像头应用编程框架*/int video_init(u8 *dev,int video_fd,struct video *video_info){ /*1.打开摄像设备文件*/ video_fd=open(dev,o_rdwr); if(video_fdwidth=video_format.fmt.pix.width; video_info->height=video_format.fmt.pix.height; printf(图像尺寸:%d * %dn,video_info->width,video_info->height); /*3.申请空间*/ struct v4l2_requestbuffers video_requestbuffers; memset(&video_requestbuffers,0,sizeof(struct v4l2_requestbuffers)); video_requestbuffers.count=4;//缓冲区个数 video_requestbuffers.type=v4l2_buf_type_video_capture;//v4l2捕获框架格式 video_requestbuffers.memory=v4l2_memory_mmap;//内存映射 if(ioctl(video_fd,vidioc_reqbufs,&video_requestbuffers))return -3; printf(缓冲区个数:%dn,video_requestbuffers.count); /*4.将缓冲映射到进程空间*/ int i=0; struct v4l2_buffer video_buffer; for(i=0;immap_size=video_buffer.length;/*映射大小*/ video_info->mmapbuf[i]=mmap(null,video_buffer.length,prot_read|prot_write,map_shared,video_fd,video_buffer.m.offset); } /*5.将缓冲区添加到采集队列*/ for(i=0;i  
3.摄像头采集图像处理线程
/*线程清理函数*/void pth_routine(void *arg){ /*关闭摄像头*/ free(arg); pthread_mutex_lock(&fastmutex);//互斥锁上锁 pthread_cond_broadcast(&cond);//广播唤醒所有线程 pthread_mutex_unlock(&fastmutex);//互斥锁解锁 video_flag=0; printf(资源清理完成n);}/*摄像头处理线程*/void *video_collectimage(void *arg){ u8 *rgb=malloc(video_info.height*video_info.width*3);//申请图像数据缓冲区 if(rgb==null) { pthread_exit(null);/*结束线程*/ } pthread_cleanup_push(pth_routine,rgb); struct pollfd fds; fds.fd=video_fd;//监听摄像头描述符 fds.events=pollin;//读事件 fds.revents=0; struct v4l2_buffer video_buff; while(video_flag) { poll(&fds,1,-1); /*1.从队列中取数据*/ memset(&video_buff,0,sizeof(struct v4l2_buffer)); video_buff.memory=v4l2_memory_mmap;//内存映射 video_buff.type=v4l2_buf_type_video_capture;//v4l2视频捕获 if(ioctl(video_fd,vidioc_dqbuf,&video_buff))break; /*yuv转rgb*/ yuv_to_rgb(video_info.mmapbuf[video_buff.index],rgb,video_info.width,video_info.height);//颜色数据转换 pthread_mutex_lock(&fastmutex);//互斥锁上锁 memcpy(rgb_buff,rgb,video_info.height*video_info.width*3); pthread_cond_broadcast(&cond);//广播唤醒所有线程 pthread_mutex_unlock(&fastmutex);//互斥锁解锁 /*3.将缓冲区添加到队列*/ if(ioctl(video_fd,vidioc_qbuf,&video_buff))break; } pthread_cleanup_pop(1);/*注销清理函数*/}  
4.yuyv(yuv422)转rgb888
/*yuyv转rgb888*/void yuv_to_rgb(unsigned char *yuv_buffer,unsigned char *rgb_buffer,int iwidth,int iheight){ int x; int z=0; unsigned char *ptr = rgb_buffer; unsigned char *yuyv= yuv_buffer; for (x = 0; x < iwidth*iheight; x++) { int r, g, b; int y, u, v; if (!z) y = yuyv[0] << 8; else y = yuyv[2] 8; g = (y - (88 * u) - (183 * v)) >> 8; r = (y + (454 * u)) >> 8; *(ptr++) = (b > 255) ? 255 : ((b 255) ? 255 : ((g 255) ? 255 : ((r < 0) ? 0 : r); if(z++) { z = 0; yuyv += 4; } }}  
5.主函数main.c
#include #include #include #include #include #include #include #include #include video.h#define camera_dev /dev/video0 //摄像头设备节点int video_fd;/*摄像头描述符*/struct video video_info;/*摄像头结构体信息*/void *video_collectimage(void *arg);/*摄像头图像采集*/u8 *rgb_buff=null;u8 video_flag=1;pthread_mutex_t fastmutex = pthread_mutex_initializer;//互斥锁pthread_cond_t cond = pthread_cond_initializer;//条件变量typedef enum{ false=0, true,}bool;int main(){ /*初始化摄像头*/ video_fd=video_init(camera_dev,video_fd,&video_info); if(video_fd<=0) { printf(摄像头初始化失败,res=%dn,video_fd); return 0; } /*创建窗口 */ sdl_window *window=sdl_createwindow(sdl_video, sdl_windowpos_centered,sdl_windowpos_centered,800,480,sdl_window_allow_highdpi|sdl_window_resizable); /*创建渲染器*/ sdl_renderer *render=sdl_createrenderer(window,-1,sdl_renderer_accelerated); /*清空渲染器*/ sdl_renderclear(render); printf(图像尺寸:%d * %dn,video_info.width,video_info.height); /*创建纹理*/ sdl_texture*sdltext=sdl_createtexture(render,sdl_pixelformat_rgb24,sdl_textureaccess_streaming,video_info.width,video_info.height); /*创建摄像头采集线程*/ u8 *rgb_data=malloc(video_info.height*video_info.width*3); rgb_buff=malloc(video_info.height*video_info.width*3);//保存rgb颜色数据 //printf(size=%dn,video_info.mmap_size); video_flag=1;/*摄像头采集标志*/ pthread_t pthid; pthread_create(&pthid,null,video_collectimage, null); bool quit=true; sdl_event event; sdl_rect rect; while(quit) { while(sdl_pollevent(&event))/*事件监测*/ { if(event.type==sdl_quit)/*退出事件*/ { quit=false; video_flag=0; pthread_cancel(pthid);/*杀死指定线程*/ continue; } } if(!video_flag) { quit=false; continue; } pthread_mutex_lock(&fastmutex);//互斥锁上锁 pthread_cond_wait(&cond,&fastmutex); memcpy(rgb_data,rgb_buff,video_info.height*video_info.width*3); pthread_mutex_unlock(&fastmutex);//互斥锁解锁 sdl_updatetexture(sdltext,null,rgb_data, video_info.width*3); //sdl_rendercopy(render, sdltext, null,null); // 拷贝纹理到渲染器 sdl_rendercopyex(render, sdltext,null,null,0,null,sdl_flip_none); sdl_renderpresent(render); // 渲染 } sdl_destroytexture(sdltext);/*销毁纹理*/ sdl_destroyrenderer(render);/*销毁渲染器*/ sdl_destroywindow(window);/*销毁窗口 */ sdl_quit();/*关闭sdl*/ pthread_mutex_destroy(&fastmutex);/*销毁互斥锁*/ pthread_cond_destroy(&cond);/*销毁条件变量*/ free(rgb_buff); free(rgb_data);}  
6.运行效果


2020年智能联网汽车达2.5亿辆 磐仪成功打入无人载具市场
公司希望能在物联网寻求企业四个领域的解决方法
在笔记本电脑中切换LVDS图形
带有饱和处理功能的并行乘加单元设计
360推出新款旗舰扫地机器人产品X90,新升级了超声波避障传感器
Linux下V4L2框架基于SDL库本地USB摄像头监控
VR一体机出货量创新高
LPL春季赛战火重燃,三星玄龙骑士陪JDG战队再踏征程
LTE测试电路图设计集锦 —电路图天天读(66)
机器人复工复产已逾六成 中国经济将很快就会反弹
华为P30 Pro参数提前曝:8GB运存/超级四摄
&quot;开新一夏&quot;来啦,新机抽签购、超值买赠等,一起到来酷门店开抢
智能家电助力中国AIGC走向世界
台积电已大规模生产第六代晶圆级芯片封装技术
igbt的工作原理图详解
智能电动汽车充电桩的安装条件以及工作原理
基于ARM内核处理器的的实时测控系统开发平台设计与实现
免开发打造Zigbee水浸传感器,相关方案的介绍
音乐闪光灯制作图解
【世说芯品】旅游重启,蝶变重生 | 5G赋能文化旅游