usb摄像头应用编程

news2024/10/22 5:35:47

作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生在读,研究方向无线联邦学习
擅长领域:驱动开发,嵌入式软件开发,BSP开发
作者主页:一个平凡而乐于分享的小比特的个人主页
文章收录专栏:IMX8MP,本专栏记录imx8mp开发板,学习开发过程中的问题及解决方法记录
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

usb摄像头应用编程

最近在京东上买了一个usb摄像头。想研究研究,应用到项目开发中。此文档记录我学习的过程。

1.V4L2简介

1.1 什么是v4l2

V4L2,即 Video for linux two ,是 Linux 内核中视频类设备的一套驱动框架,为视频类设备驱动开发和应用层提供了一套统一的接口规范使用 V4L2 设备驱动框架注册的设备会在 Linux 系统/dev/目录下生成对应的设备节点文件,设备节点的名称通常为 videoX(X为0、1、2…)

V4L2是Linux视频处理模块的最新标准代码,包括对视频输入设备的处理,如高频(即、电视信号输入端子)或摄像头,还包括视频处理输出装置。一般来说,最常见的是使用V4L2来处理相机数据采集的问题。我们通常使用的相机实际上是一个图像传感器,将捕捉到的光线通过视频芯片处理后,编码成JPG/MJPG或YUV格式输出。我们可以很容易地通过V4L2与第一台摄像机设备“通信”,如设置或获取它们的工作参数。

1.2 Video设备的V4L2框架

基于Video设备的V4L2框架

在这里插入图片描述

Linux系统中视频设备主要包括以下四个部分:

1.字符设备驱动程序核心:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间;用户空间可以通过Ioctl系统调用控制设备;在应用层,我们可以在 /dev 目录发现 videoxx 类似的设备节点。

2.V4L2驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数;

3.平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关V4L2驱动部分,包括注册video_device和v4l2_dev。

4.具体的sensor驱动:主要上电、提供工作时钟、视频图像裁剪、流IO开启等,实现各种设备控制方法供上层调用并注册v4l2_subdev。

1.3 V4L2支持的设备类型

4L2支持的设备十分广泛,但是其中只有很少一部分在本质上是真正的视频设备:

video capture interface:视频采集接口,从camera上获取视频数据,视频捕获是V4L2的基本应用;

video output interface:视频输出接口,允许应用程序驱动外设提供视频图像

video overlay interface:视频覆盖接口,是捕获接口的一个变体,其工作是便于捕获设备直接显示到显示器,无需经过CPU;Android拍照应用在进行预览时,可能就是这种模式。

VBI interfaces:基于电视场消隐实现远程传送文字的技术与设备;

radio interface:无线电接口,从AM和FM调谐器设备访问音频流。

Codec Interface:编解码接口,对视频数据流执行转换。

通常情况下V4L2的主设备号是81,次设备号为0~255;这些次设备号里又分为多类设备:视频设备、Radio(收音机)设备、Teletext on VBI等。因此V4L2设备对应的文件节点有:/dev/videoX、/dev/vbiX、/dev/radioX。对于Radio设备,即用于收发声音。但要提醒注意的是,对于声音的采集与处理,在我们的Android手持设备中常会有个Mic设备,它则是属于ALSA子系统的。我们主要讨论的是Video设备。

2.V4L2-utils、ffplay工具测试usb摄像头

详细操作讲解请参考:摄像头应用测试

输入密令,录制视频

v4l2-ctl --device=/dev/video0 --set-fmt-video=width=640,height=480,pixelformat=YUYV --stream-mmap --stream-to=video100.yuv --stream-count=100

将录制得到的video100.yuv拷贝到虚拟机上,利用ffplay工具播放

ffplay -video_size 640x480 -pixel_format yuyv422 -framerate 10 -i video100.yuv 

usb摄像头视频采集

说明USB摄像头工作是正常的

3. V4L2接口编程

3.1 v4l2接口编程流程

  1. 首先是打开摄像头设备;
  2. 查询设备的属性或功能;
  3. 设置设备的参数,譬如像素格式、 帧大小、 帧率;
  4. 申请帧缓冲、 内存映射;
  5. 帧缓冲入队;
  6. 开启视频采集;
  7. 帧缓冲出队、对采集的数据进行处理;
  8. 处理完后,再次将帧缓冲入队,往复;
  9. 结束采集。

在这里插入图片描述

可以看到 V4L2 的应用编程的内容并不复杂,其实就是 open,ioctl,mmap,munmap,close 这几个调用,其中只有 ioctl 的使用稍微复杂。

VIDIOC_QUERYCAP		// 查询设备属性和功能
VIDIOC_ENUM_FMT		// 列举数据帧格式
VIDIOC_G_FMT		// 获取数据帧格式
VIDIOC_S_FMT		// 设置数据帧格式
VIDIOC_REQBUFS		// 申请帧缓冲区
VIDIOC_QUERYBUF		// 查询帧缓冲区
VIDIOC_STREAMON		// 开始视频采集
VIDIOC_DQBUF		// 帧缓冲出队
VIDIOC_QBUF			// 帧缓冲入队
VIDIOC_STREAMOFF	// 停止视频采集

3.2 v4l2视频采集原理

通过 V4L2 采集图像之前,我们需要做的很多,但是很重要的一步是分配帧缓冲区,并将分配的帧缓冲区从内核空间映射到用户空间,然后将申请到的帧缓冲区在视频采集输入队列排队,剩下的就是等待视频数据的到来。

其具体过程为,当启动视频采集后,驱动程序开始采集一帧图像数据,会把采集的图像数据放入视频采集输入队列的第一个帧缓冲区,一阵图像数据就算采集完成了。第一个帧缓冲区存满一帧图像数据后,驱动程序将该帧缓冲区移至视频采集输出队列,等待应用程序从输出队列取出,应用程序取出图像数据可以对图像数据进行处理或存储操作,然后将帧该缓冲区放入视频采集输入队列的尾部。驱动程序接下来采集下一帧数据,放入第二个缓冲区,同样的帧缓冲区存满一帧数据后,驱动程序将该缓冲区移至视频采集输出队列,应用程序将该帧缓冲区的图像数据取出后又将该帧缓冲区放入视频输入队列尾部,这样循环往复就实现了循环采集。

在这里插入图片描述

不同的 USB 摄像头所支持的种类不同,所支持的种类数量也不相同,以本章的 USB 摄像头为例,可以查看摄像头支持的视频帧尺寸。

tjf@ubuntu16:~$ lsusb -v
	  VideoStreaming Interface Descriptor:
        bLength                            15
        bDescriptorType                    36
        bDescriptorSubtype                  1 (INPUT_HEADER)
        bNumFormats                         2
        wTotalLength                      365
        bEndPointAddress                  130
        bmInfo                              0
        bTerminalLink                       3
        bStillCaptureMethod                 1
        bTriggerSupport                     0
        bTriggerUsage                       0
        bControlSize                        1
        bmaControls( 0)                    11
        bmaControls( 1)                    11
      VideoStreaming Interface Descriptor:
        bLength                            11
        bDescriptorType                    36
        bDescriptorSubtype                  6 (FORMAT_MJPEG)
        bFormatIndex                        1
        bNumFrameDescriptors                5
        bFlags                              1
          Fixed-size samples: Yes
        bDefaultFrameIndex                  1
        bAspectRatioX                       0
        bAspectRatioY                       0
        bmInterlaceFlags                 0x00
          Interlaced stream or variable: No
          Fields per frame: 1 fields
          Field 1 first: No
          Field pattern: Field 1 only
          bCopyProtect                      0
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  7 (FRAME_MJPEG)
        bFrameIndex                         1
        bmCapabilities                   0x01
          Still image supported
        wWidth                           1920
        wHeight                          1080
        dwMinBitRate                995328000
        dwMaxBitRate                995328000
        dwMaxVideoFrameBufferSize     4147200
        dwDefaultFrameInterval         333333
        bFrameIntervalType                  1
        dwFrameInterval( 0)            333333
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  7 (FRAME_MJPEG)
        bFrameIndex                         2
        bmCapabilities                   0x01
          Still image supported
        wWidth                           1280
        wHeight                           720
        dwMinBitRate                442368000
        dwMaxBitRate                442368000
        dwMaxVideoFrameBufferSize     1843200
        dwDefaultFrameInterval         333333
        bFrameIntervalType                  1
        dwFrameInterval( 0)            333333
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  7 (FRAME_MJPEG)
        bFrameIndex                         3
        bmCapabilities                   0x01
          Still image supported
        wWidth                            800
        wHeight                           600
        dwMinBitRate                230400000
        dwMaxBitRate                230400000
        dwMaxVideoFrameBufferSize      960000
        dwDefaultFrameInterval         333333
        bFrameIntervalType                  1
        dwFrameInterval( 0)            333333
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  7 (FRAME_MJPEG)
        bFrameIndex                         4
        bmCapabilities                   0x01
          Still image supported
        wWidth                            640
        wHeight                           480
        dwMinBitRate                147456000
        dwMaxBitRate                147456000
        dwMaxVideoFrameBufferSize      614400
        dwDefaultFrameInterval         333333
        bFrameIntervalType                  1
        dwFrameInterval( 0)            333333
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  7 (FRAME_MJPEG)
        bFrameIndex                         5
        bmCapabilities                   0x01
          Still image supported
        wWidth                            640
        wHeight                           360
        dwMinBitRate                110592000
        dwMaxBitRate                110592000
        dwMaxVideoFrameBufferSize      460800
        dwDefaultFrameInterval         333333
        bFrameIntervalType                  1
        dwFrameInterval( 0)            333333
      VideoStreaming Interface Descriptor:
        bLength                             6
        bDescriptorType                    36
        bDescriptorSubtype                 13 (COLORFORMAT)
        bColorPrimaries                     1 (BT.709,sRGB)
        bTransferCharacteristics            1 (BT.709)
        bMatrixCoefficients                 4 (SMPTE 170M (BT.601))
      VideoStreaming Interface Descriptor:
        bLength                            27
        bDescriptorType                    36
        bDescriptorSubtype                  4 (FORMAT_UNCOMPRESSED)
        bFormatIndex                        2
        bNumFrameDescriptors                5
        guidFormat                            {59555932-0000-1000-8000-00aa00389b71}
        bBitsPerPixel                      16
        bDefaultFrameIndex                  1
        bAspectRatioX                       0
        bAspectRatioY                       0
        bmInterlaceFlags                 0x00
          Interlaced stream or variable: No
          Fields per frame: 2 fields
          Field 1 first: No
          Field pattern: Field 1 only
          bCopyProtect                      0
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)
        bFrameIndex                         1
        bmCapabilities                   0x01
          Still image supported
        wWidth                           1920
        wHeight                          1080
        dwMinBitRate                165888000
        dwMaxBitRate                165888000
        dwMaxVideoFrameBufferSize     4147200
        dwDefaultFrameInterval        2000000
        bFrameIntervalType                  1
        dwFrameInterval( 0)           2000000
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)
        bFrameIndex                         2
        bmCapabilities                   0x01
          Still image supported
        wWidth                           1280
        wHeight                           720
        dwMinBitRate                147456000
        dwMaxBitRate                147456000
        dwMaxVideoFrameBufferSize     1843200
        dwDefaultFrameInterval        1000000
        bFrameIntervalType                  1
        dwFrameInterval( 0)           1000000
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)
        bFrameIndex                         3
        bmCapabilities                   0x01
          Still image supported
        wWidth                            800
        wHeight                           600
        dwMinBitRate                153600000
        dwMaxBitRate                153600000
        dwMaxVideoFrameBufferSize      960000
        dwDefaultFrameInterval         500000
        bFrameIntervalType                  1
        dwFrameInterval( 0)            500000
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)
        bFrameIndex                         4
        bmCapabilities                   0x01
          Still image supported
        wWidth                            640
        wHeight                           480
        dwMinBitRate                147456000
        dwMaxBitRate                147456000
        dwMaxVideoFrameBufferSize      614400
        dwDefaultFrameInterval         333333
        bFrameIntervalType                  1
        dwFrameInterval( 0)            333333
      VideoStreaming Interface Descriptor:
        bLength                            30
        bDescriptorType                    36
        bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)
        bFrameIndex                         5
        bmCapabilities                   0x01
          Still image supported
        wWidth                            640
        wHeight                           360
        dwMinBitRate                110592000
        dwMaxBitRate                110592000
        dwMaxVideoFrameBufferSize      460800
        dwDefaultFrameInterval         333333
        bFrameIntervalType                  1
        dwFrameInterval( 0)            333333
      VideoStreaming Interface Descriptor:
        bLength                             6
        bDescriptorType                    36
        bDescriptorSubtype                 13 (COLORFORMAT)
        bColorPrimaries                     1 (BT.709,sRGB)
        bTransferCharacteristics            1 (BT.709)
        bMatrixCoefficients                 4 (SMPTE 170M (BT.601))

可以看到打印的信息很多,我们需要找到 VideoStreaming Interface Descriptor 就是用于 USB 数据传输的接口,然后查看 wWidth 和 wHeight 这两个属性就可以知道摄像头所支持的视频帧的尺寸,本章选用的是 640 * 480 的视频帧大小。

3.3 v4l2设备操作流程

V4L2支持多种接口:capture(捕获)output(输出)overlay(预览)等等

这里讲解如何使用capture功能,下面讲解操作流程

step1:打开设备

在Linux中,视频设备节点为/dev/videox,使用open函数将其打开

	//1.打开设备
	int fd = open("/dev/video0",O_RDWR);
	if(fd < 0)
	{
		perror("打开设备失败");
		return -1;
	}

step 2:获取摄像头支持的格式

有的摄像头支持多种像素格式,有的摄像头只支持一种像素格式,在设置格式之前,要先枚举出所有的格式,看一看是否支持要设置的格式,然后再进一步设置

struct v4l2_fmtdesc v4fmt;
v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集

int i =0;
while(1)
{
	v4fmt.index = i++;
	int ret = ioctl(fd,VIDIOC_ENUM_FMT,&v4fmt);
	if(ret < 0)
	{
		perror("获取失败");
		break;
	}	
	printf("index=%d\n",v4fmt.index);
	printf("flags=%d\n",v4fmt.flags);
	printf("description=%s\n",v4fmt.description);
	unsigned char *p = (unsigned char *)&v4fmt.pixelformat;
	printf("pixelformat=%c%c%c%c\n",p[0],p[1],p[2],p[3]);
	printf("reserved=%d\n",v4fmt.reserved[0]);		
}

step 3:设置/获取采集格式

	struct v4l2_format vfmt;
	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
	vfmt.fmt.pix.width = 640;//设置宽
    vfmt.fmt.pix.height = 480;//设置高
    vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//设置视频采集格式
	int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
	if(ret < 0)
	{
		perror("设置格式失败");
		close(fd);
		return -1;
	}
	

	memset(&vfmt, 0, sizeof(vfmt));
	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 确保type字段正确设置
	ret = ioctl(fd, VIDIOC_G_FMT, &vfmt);
	if(ret < 0)
	{
		perror("获取格式失败");
        close(fd);
        return -1;
	}

	if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
	{
		printf("设置成功\n");
	}
	else
	{
		printf("设置失败\n");
        close(fd);
        return -1;
	}

step 4:申请内核空间

v4l2设备读取数据的方式有两种,一种是read方式,一种是streaming方式,具体需要看v4l2_capability是支持V4L2_CAP_READWRITE还是V4L2_CAP_STREAMING

看一看v4l2_capability

struct v4l2_capability {
	__u8	driver[16];	/* i.e. "bttv" */
	__u8	card[32];	/* i.e. "Hauppauge WinTV" */
	__u8	bus_info[32];	/* "PCI:" + pci_name(pci_dev) */
	__u32   version;        /* should use KERNEL_VERSION() */
	__u32	capabilities;	/* Device capabilities */
	__u32	reserved[4];
};

其中最重要的是capabilities字段,这个字段标记着v4l2设备的功能,capabilities有以下部分标记位

ID描述符
V4L2_CAP_VIDEO_CAPTURE设备支持捕获功能
V4L2_CAP_VIDEO_OUTPUT设备支持输出功能
V4L2_CAP_VIDEO_OVERLAY设备支持预览功能
V4L2_CAP_STREAMING设备支持流读写
V4L2_CAP_READWRITE设备支持read、write方式读写

read方式很容易理解,就是通过read函数读取,那么streaming是什么意思呢?

streaming就是在内核空间中维护一个缓存队列,然后将内存映射到用户空间,应用读取图像数据就是一个不断地出队列入队列的过程,如下图所示

在这里插入图片描述

	struct v4l2_requestbuffers reqbuffer;
	reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuffer.count = 4;//申请4个缓冲区
	reqbuffer.memory = V4L2_MEMORY_MMAP;//映射方式
	ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuffer);
	if(ret < 0)
	{
		perror("申请队列空间失败");
        close(fd);
        return -1;
	}

step 5:映射内存

为什么要映射缓存?

因为如果使用read方式读取的话,图像数据是从内核空间拷贝会应用空间,而一副图像的数据一般来讲是比较大的,所以效率会比较低。而如果使用映射的方式,讲内核空间的内存应用到用户空间,那么用户空间读取数据就想在操作内存一样,不需要经过内核空间到用户空间的拷贝,大大提高效率

	unsigned char *mptr[4];//保存映射后用户空间的首地址
	unsigned int size[4];	

	struct v4l2_buffer mapbuffer;
	//初始化type,index
	mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	for(int i=0; i<4; i++)
	{
		mapbuffer.index = i;
		ret = ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer);//从内核空间中查询一个空间做映射
		if(ret < 0)
		{
			perror("查询内核空间队列失败");
			close(fd);
        	return -1;
		}

		mptr[i] = (unsigned char *)mmap(NULL, mapbuffer.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mapbuffer.m.offset);
		size[i] = mapbuffer.length;

		//通知使用完毕--‘放回去’
		ret = ioctl(fd, VIDIOC_QBUF, &mapbuffer);
		if(ret < 0)
		{
			perror("放回失败");
        	close(fd);
        	return -1;
		}		
	}

step 6:开始采集

	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd, VIDIOC_STREAMON, &type);
	if(ret < 0)
	{
		perror("开启失败");
	}

step 7:从队列中提取一帧数据

	struct v4l2_buffer readbuffer;
	readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd, VIDIOC_DQBUF, &readbuffer);
	if(ret < 0)
	{
		perror("提取数据失败");
	}

	FILE *file=fopen("my.jpg","w+");
	
	fwrite(mptr[readbuffer.index],readbuffer.length,1,file);
	fclose(file);

	//通知内核已经使用完毕
	ret = ioctl(fd, VIDIOC_QBUF, &readbuffer);
	if(ret < 0)
	{
		perror("放回队列失败");
		return -1;
	}

step 8:停止采集

	ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
    if(ret < 0)
    {   
        perror("停止采集失败");
		return -1;
    }  

step 9:释放映射

	for(int i=0; i<4; i++)
	{
		munmap(mptr[i],size[i]);
	}

step 10:关闭设备

	close(fd);

完整代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>

int main(void)
{
	//1.打开设备
	int fd = open("/dev/video0",O_RDWR);
	if(fd < 0)
	{
		perror("打开设备失败");
		return -1;
	}

	//2.获取摄像头支持的格式
	struct v4l2_fmtdesc v4fmt;
	v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集

	int i =0;
	while(1)
	{
		v4fmt.index = i++;
		int ret = ioctl(fd,VIDIOC_ENUM_FMT,&v4fmt);
		if(ret < 0)
		{
			perror("获取失败");
			break;
		}	
		printf("index=%d\n",v4fmt.index);
		printf("flags=%d\n",v4fmt.flags);
		printf("description=%s\n",v4fmt.description);
		unsigned char *p = (unsigned char *)&v4fmt.pixelformat;
		printf("pixelformat=%c%c%c%c\n",p[0],p[1],p[2],p[3]);
		printf("reserved=%d\n",v4fmt.reserved[0]);		
	}

	//3设置采集格式
	struct v4l2_format vfmt;
	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
	vfmt.fmt.pix.width = 640;//设置宽
    vfmt.fmt.pix.height = 480;//设置高
    vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//设置视频采集格式
	int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
	if(ret < 0)
	{
		perror("设置格式失败");
		close(fd);
		return -1;
	}
	

	memset(&vfmt, 0, sizeof(vfmt));
	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 确保type字段正确设置
	ret = ioctl(fd, VIDIOC_G_FMT, &vfmt);
	if(ret < 0)
	{
		perror("获取格式失败");
        close(fd);
        return -1;
	}

	if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
	{
		printf("设置成功\n");
	}
	else
	{
		printf("设置失败\n");
        close(fd);
        return -1;
	}

	//4.申请内核空间
	struct v4l2_requestbuffers reqbuffer;
	reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuffer.count = 4;//申请4个缓冲区
	reqbuffer.memory = V4L2_MEMORY_MMAP;//映射方式
	ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuffer);
	if(ret < 0)
	{
		perror("申请队列空间失败");
        close(fd);
        return -1;
	}

	//5.映射
	unsigned char *mptr[4];//保存映射后用户空间的首地址
	unsigned int size[4];	

	struct v4l2_buffer mapbuffer;
	//初始化type,index
	mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	for(int i=0; i<4; i++)
	{
		mapbuffer.index = i;
		ret = ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer);//从内核空间中查询一个空间做映射
		if(ret < 0)
		{
			perror("查询内核空间队列失败");
			close(fd);
        	return -1;
		}

		mptr[i] = (unsigned char *)mmap(NULL, mapbuffer.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mapbuffer.m.offset);
		size[i] = mapbuffer.length;

		//通知使用完毕--‘放回去’
		ret = ioctl(fd, VIDIOC_QBUF, &mapbuffer);
		if(ret < 0)
		{
			perror("放回失败");
        	close(fd);
        	return -1;
		}		
	}

	//6.开始采集
	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd, VIDIOC_STREAMON, &type);
	if(ret < 0)
	{
		perror("开启失败");
	}

	//7.从队列中提取一帧数据
	struct v4l2_buffer readbuffer;
	readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd, VIDIOC_DQBUF, &readbuffer);
	if(ret < 0)
	{
		perror("提取数据失败");
	}

	FILE *file=fopen("my.jpg","w+");
	
	fwrite(mptr[readbuffer.index],readbuffer.length,1,file);
	fclose(file);

	//通知内核已经使用完毕
	ret = ioctl(fd, VIDIOC_QBUF, &readbuffer);
	if(ret < 0)
	{
		perror("放回队列失败");
		return -1;
	}
	
	//8.停止采集
	ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
    if(ret < 0)
    {   
        perror("停止采集失败");
		return -1;
    }   
    
	//9.释放映射
	for(int i=0; i<4; i++)
	{
		munmap(mptr[i],size[i]);
	}
	//10.关闭设备
	close(fd);
	return 0;
	
}

4.运行测试

在ubuntu上编译程序,并运行

gcc -o video video.c
./video

在这里插入图片描述

可以看到测usb摄像头支持JPEG和YUYV 4:2:2 两种格式,并生成my.jpg格式图片

输入eog my.jpg使用图像查看器来查看它

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1843473.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JUC并发编程-第二天:线程高级部分

线程高级部分 线程不安全原子性可见性有序性&#xff08;指令重排&#xff09;更多的解决线程安全 线程不安全 多线程下并发同时对共享数据进行读写&#xff0c;会造成数据混乱线程不安全 当多线程下并发访问临界资源时&#xff0c;如果破坏其原子性、可见性、有序性&#xff…

账号和权限的管理

文章目录 管理用户账号和组账号用户账号的分类超级用户普通用户程序用户 UID&#xff08;用户id)和(组账号)GIDUID用户识别号GID组标识号 用户账号文件添加用户账号设置/更改用户口令 管理用户账号和组账号 用户账号的分类 超级用户 root 用户是 Linux 操作系统中默认的超级…

《米小圈动画汉字》汉字教育动画化:传统与创新的完美融合!

汉字&#xff0c;作为中华文化的瑰宝&#xff0c;承载着千百年来中华民族的智慧和思想。每一个汉字不仅仅是一个符号&#xff0c;更是一段历史的见证&#xff0c;一种文化的传承。在当今全球化的背景下&#xff0c;汉字教育面临着新的挑战与机遇。在这种背景下&#xff0c;如何…

LabVIEW程序退出后线程仍在运行问题

LabVIEW程序退出后&#xff0c;线程仍在运行的问题可能源于资源管理不当、未正确终止循环、事件结构未处理、并发编程错误以及外部库调用未结束等方面。本文将从这些角度详细分析&#xff0c;探讨可能的原因和解决方案&#xff0c;并提供预防措施&#xff0c;帮助开发者避免类似…

FPGA PCIe加载提速方案

目录 1.bit流压缩 2.flash加载速度 3.Tandem模式 1.bit流压缩 set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] 2.flash加载速度 打开bitstream setting&#xff0c;设置SPI的线宽和速率&#xff08;线宽按原理图设置&#xff0c;速率尽可能高&#xff09…

redis-基础篇(2)

黑马redis-基础篇笔记 3. redis的java客户端-Jedis 在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a;https://redis.io/docs/clients/ 标记为❤的就是推荐使用的java客户端&#xff0c;包括&#xff1a; Jedis和Lettuce&#xff1a;这两个主要是提供了Redi…

Vant2组件库的基础应用

目录 一、Picker 选择器 1.1、数组对象处理 1.2、每个选项颜色设置 二、滚动分页加载列表 三、Calendar 日历(可选范围限制) 四、input值过滤 官网&#xff1a;Vant 2 - Mobile UI Components built on Vue 一、Picker 选择器 官网示例数据&#xff1a; columns: [杭州…

有趣的 Oracle JDBC 驱动包命名问题 - ojdbc6 和 ojdbc14 哪个新?!

有趣的 Oracle JDBC 驱动包命名问题 - ojdbc6 和 ojdbc14 哪个新?! 1 背景概述 最近协助一个小兄弟排查了某作业使用 sqoop 采集 oracle 数据的失败问题&#xff0c;问题现象&#xff0c;问题原因和解决方法都挺直观&#xff0c;但在此过程中发现了一个有趣的 Oracle JDBC 驱…

JAVA每日作业day6.20

ok了家人们&#xff0c;今天学习了面向对象的继承&#xff0c;话不多说让我们看看怎么个事。 我们先把昨天学 面向对象-封装 的温习一下&#xff0c;来个例子 1&#xff0c;综合案例 做一个关于学生的随机点名器 定义了两个变量&#xff0c;name和age&#xff0c;给他们封装一…

java封装模块为jar包- FUSE 智能BPM低代码平台-企业级

第一种方法 将打好的项目模块jar放入lib文件夹内 操作后 项目便有了此jar包的依赖 第二种方法 使用 maven引入 可以参考我之前发的博客 IDEA导入jar包_idea导入jar包方法-CSDN博客

简单分享github

一、官网 GitHub: Let’s build from here GitHub 二、注册 通过简单的注册步骤&#xff0c;你就可以拥有一个属于自己的GitHub账号。再简单注册完成之后会需要验证你所输入的邮箱才能正常使用你的GitHub。 三、设置自己的库 在注册完成之后&#xff0c;完成一些简单的设置之…

PS给logo加白色描边

步骤1&#xff1a;打开你的Logo文件 步骤2&#xff1a;选择Logo层 在“图层”面板中找到你的Logo所在的图层。如果你的Logo是在背景图层上&#xff0c;可以将它转换为普通图层&#xff08;右键点击背景图层&#xff0c;选择“从背景图层转换”&#xff09;&#xff08;此处也…

【转载】TIOBE 编程指数 6 月排行榜公布,vb.net排第九

原文地址&#xff1a;https://baijiahao.baidu.com/s?id1801368030428902126&wfrspider&forpc IT之家 6 月 9 日消息&#xff0c;TIOBE 编程社区指数是一个衡量编程语言受欢迎程度的指标&#xff0c;评判的依据来自世界范围内的工程师、课程、供应商及搜索引擎&#…

【服务器02】之阿里云平台

百度一下阿里云官网 点击注册直接使用支付宝注册可以跳过认证 成功登录后&#xff0c;点击产品 点击免费试用 点击勾选 选一个距离最近的 点满GB 注意&#xff1a;一般试用的时用的是【阿里云】&#xff0c;真正做项目时用的是【腾讯云】 现在开始学习使用&#xff1a; 首先…

Samtec制造理念系列二 | 差异变量管理的意义与挑战

【摘要/前言】 制造高端电子产品是非常复杂精密的过程。制作用于演示或原型的一次性样品可能具有挑战性&#xff0c;但真正的挑战在于如何以盈利的方式持续生产。 这就是Samtec风险投资研发工程总监Aaron Tucker在一次关于生产高密度微小型连接器的挑战的演讲中所强调的观点。…

使用宝塔面板搭建Flask项目保姆级喂饭教程

目录 零.前言 一.准备工作 1.1创建requirements.txt文件 1.2将项目打包为压缩文件 1.3租一台服务器 1.4部署宝塔面板 二.宝塔面板(服务器)上的操作 2.1将本地Flask项目上传到服务器 2.2添加Python项目 2.3配置Python项目 2.4配置Nginx 2.5宝塔面板放行端口 2.6在服…

2024年一建报名汇总和常见问题答疑!

2024年一级建造师报名通知全国32个地区均已发布&#xff0c;考试100汇总如下&#xff0c;大家务必及时报名&#xff0c;千万不要错过&#xff01; ​ 报名问题 01、时间不多了&#xff0c;今年可以先考部分学科吗&#xff1f;分两年考完&#xff1f; 可以的&#xff0c;一建…

视觉SLAM14精讲——相机与图像3.3

视觉SLAM14精讲 三维空间刚体运动1.0三维空间刚体运动1.1三维空间刚体运动1.2李群与李代数2.1相机与图像3.1相机与图像3.2 视觉SLAM14精讲——相机与图像3.3 视觉SLAM14精讲相机投影流程双目相机模型 相机投影流程 至此&#xff0c;有关相机三维刚体变换的所有因素已经汇集。…

朗科HD10M2Pr震撼上市,自带风扇极速降温,匹敌私有云

近日,存储领域的领军企业朗科旗下全资子公司朗科创新宣布,其最新款磁吸硬盘盒HD10M2Pr正式上市。这款产品凭借超薄设计、极速降温、高速传输等多项优势,迅速成为了行业内的讨论焦点。 随着移动设备使用的普及和短视频内容的日益丰富,对于存储空间不断增长的需求逐渐成为日常生活…

react项目中如何书写css

一&#xff1a;问题&#xff1a; 在 vue 项目中&#xff0c;我们书写css的方式很简单&#xff0c;就是在 .vue文件中写style标签&#xff0c;然后加上scope属性&#xff0c;就可以隔离当前组件的样式&#xff0c;但是在react中&#xff0c;是没有这个东西的&#xff0c;如果直…