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_fd<0)return -1; /*2.图像数据格式*/ struct v4l2_format video_format; memset(&video_format,0,sizeof(struct v4l2_format)); video_format.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//捕获格式 video_format.fmt.pix.width=1920; video_format.fmt.pix.height=1080; video_format.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV; if(ioctl(video_fd,VIDIOC_S_FMT,&video_format))return -2; video_info->width=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;i3.摄像头采集图像处理线程
/*线程清理函数*/ 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; u = yuyv[1] – 128; v = yuyv[3] – 128; b = (y + (359 * v)) >> 8; g = (y – (88 * u) – (183 * v)) >> 8; r = (y + (454 * u)) >> 8; *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (r > 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.运行效果
审核编辑:刘清
免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:Linux下V4L2框架基于SDL库本地USB摄像头监控-linux mipi摄像头驱动 https://www.yhzz.com.cn/a/5619.html