0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-12-17 15:37 次阅读

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.运行效果

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center








审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 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芯片开发板香橙派PC2Linux系统连接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

    什么是V4L2?有何作用

    1.什么是V4L2Video for(4) Linux 2 的简称,V4L的升级版。V4L2
    发表于 01-17 09:05

    Linux驱动的使用

    图片的保存4、浏览功能的实现三、视频监控代码分析1、实时监控2、抓拍图片3、浏览四、家电控制1、家电控制内容2、LED控制方法3、
    发表于 02-16 07:19

    如何在OKMX6UL-C上利用摄像头做图像采集呢

    摄像头进行图像采集,大体的框架是什么? 底层驱动和顶层程序显示需要做些什么?3. 需要用到v4l2、OpenCV等这些程序吗?不了解利用摄像头进行图像采集的过程,感谢各位大神指教
    发表于 12-02 06:49