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;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; 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系统
+关注
关注
4文章
559浏览量
26844 -
嵌入式技术
+关注
关注
10文章
346浏览量
34162 -
USB摄像头
+关注
关注
0文章
22浏览量
11175
发布评论请先 登录
相关推荐
全志D1-H开发板USB摄像头拍照Demo
库如:FFmpeg和OpenCV对V4L2均支持。
本例就使用V4L2库完成摄像头对图片的捕捉,并将其保存为一张图片。
依照Tina SKD
发表于 03-04 10:48
如何在Raspberry Pi(树莓派)上调用V4L2来操纵摄像头拍照
如何在Raspberry Pi(树莓派)上调用V4L2来操纵摄像头拍照简单地说,它就是一个基于ARM CPU的、信用卡那么大的迷你计算机。我曾经写过一篇教程,展示了如何调用OpenCV,来控制摄像头
发表于 06-30 21:39
【WRTnode2R试用体验】使用V4L2获取摄像头的信息
V4L2全称是Video for Linux 2,通过它可以驱动摄像头。在Ubuntu中,已经内置了V4L2,因此不需要安装多余的东西。在W
发表于 10-26 20:36
CSI摄像头接口及在英创主板上的应用
加载相应的驱动,加载驱动后会自动生成设备节点:“/dev/video0",应用程序可以操作该设备节点对摄像头进行图像的采集和控制。 CSI摄像头都是用了V4L2驱动提供的标准API来操作
发表于 10-20 13:36
【100ASK_IMX6ULL(带屏) 开发板试用体验】基于samba v4l2库和libjpeg远程摄像头图像读取
100ms,这个效率对于网络监控行业来说完全没法达到及格水准,但是对于IMX6ULL这样性能入门的主控来说是这样的了。使用v4l2库进行摄像头图像采集的代码之前已经放出过了,今天放调用
发表于 11-07 16:33
香橙派OrangePi PC Plus开发板连接5MP摄像头测试
排线接到开发板的 CIS 摄像头接口上,接好摄 像头后再启动 linux 系统(不要在上电后再插入摄像头)3) 进入系统后查看下 ov5640 4
发表于 05-20 15:34
全志H3芯片香橙派OrangePi PC开发板连接USB摄像头测试说明
v4l2 中的 l 是小写字母 l,不是数字 1)命令查看下 USB 摄像头的设备节点,从下面的输出可知
发表于 06-08 11:34
全志H2芯片香橙派Zero开发板连接USB摄像头的使用方法
使用 lsmod 查看系统是否自动加载了 uvcvideo 内核模块3) 然后通过 v4l2-ctl(注意 v4l2 中的 l 是小写字母 l,不是数字 1)命令查看下
发表于 10-28 17:23
全志H5芯片开发板香橙派PC2在Linux系统下连接USB摄像头的使用方法
v4l2 中的 l 是小写字母 l,不是数字 1)命令查看下 USB 摄像头的设备节点,从下面的输出可知
发表于 11-16 11:41
【触觉智能 IDO-SBC2D06-V1B-12W开发板试用】USB接口UVC摄像头
识别到了摄像头,说明系统自带了UVC驱动:可见生成了/dev/video0节点。V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在
发表于 12-12 20:38
运行linuxtv官网的v4l2代码,capture摄像头时select超时怎么解决?
编译,运行linuxtv官网的v4l2代码,capture 摄像头时select超时,这怎么搞?
发表于 12-31 06:12
运行linuxtv官网的v4l2代码,capture摄像头时select超时怎么解决?
[td]编译,运行linuxtv官网的v4l2代码,capture 摄像头时select超时,这怎么搞?
发表于 01-14 07:02
如何在OKMX6UL-C上利用摄像头做图像采集呢
摄像头进行图像采集,大体的框架是什么? 底层驱动和顶层程序显示需要做些什么?3. 需要用到v4l2、OpenCV等这些程序吗?不了解利用摄像头进行图像采集的过程,感谢各位大神指教
发表于 12-02 06:49
评论