usb摄像头应用编程

作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生在读,研究方向无线联邦学习
擅长领域:驱动开发,嵌入式软件开发,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 -vVideoStreaming Interface Descriptor:bLength                            15bDescriptorType                    36bDescriptorSubtype                  1 (INPUT_HEADER)bNumFormats                         2wTotalLength                      365bEndPointAddress                  130bmInfo                              0bTerminalLink                       3bStillCaptureMethod                 1bTriggerSupport                     0bTriggerUsage                       0bControlSize                        1bmaControls( 0)                    11bmaControls( 1)                    11VideoStreaming Interface Descriptor:bLength                            11bDescriptorType                    36bDescriptorSubtype                  6 (FORMAT_MJPEG)bFormatIndex                        1bNumFrameDescriptors                5bFlags                              1Fixed-size samples: YesbDefaultFrameIndex                  1bAspectRatioX                       0bAspectRatioY                       0bmInterlaceFlags                 0x00Interlaced stream or variable: NoFields per frame: 1 fieldsField 1 first: NoField pattern: Field 1 onlybCopyProtect                      0VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  7 (FRAME_MJPEG)bFrameIndex                         1bmCapabilities                   0x01Still image supportedwWidth                           1920wHeight                          1080dwMinBitRate                995328000dwMaxBitRate                995328000dwMaxVideoFrameBufferSize     4147200dwDefaultFrameInterval         333333bFrameIntervalType                  1dwFrameInterval( 0)            333333VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  7 (FRAME_MJPEG)bFrameIndex                         2bmCapabilities                   0x01Still image supportedwWidth                           1280wHeight                           720dwMinBitRate                442368000dwMaxBitRate                442368000dwMaxVideoFrameBufferSize     1843200dwDefaultFrameInterval         333333bFrameIntervalType                  1dwFrameInterval( 0)            333333VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  7 (FRAME_MJPEG)bFrameIndex                         3bmCapabilities                   0x01Still image supportedwWidth                            800wHeight                           600dwMinBitRate                230400000dwMaxBitRate                230400000dwMaxVideoFrameBufferSize      960000dwDefaultFrameInterval         333333bFrameIntervalType                  1dwFrameInterval( 0)            333333VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  7 (FRAME_MJPEG)bFrameIndex                         4bmCapabilities                   0x01Still image supportedwWidth                            640wHeight                           480dwMinBitRate                147456000dwMaxBitRate                147456000dwMaxVideoFrameBufferSize      614400dwDefaultFrameInterval         333333bFrameIntervalType                  1dwFrameInterval( 0)            333333VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  7 (FRAME_MJPEG)bFrameIndex                         5bmCapabilities                   0x01Still image supportedwWidth                            640wHeight                           360dwMinBitRate                110592000dwMaxBitRate                110592000dwMaxVideoFrameBufferSize      460800dwDefaultFrameInterval         333333bFrameIntervalType                  1dwFrameInterval( 0)            333333VideoStreaming Interface Descriptor:bLength                             6bDescriptorType                    36bDescriptorSubtype                 13 (COLORFORMAT)bColorPrimaries                     1 (BT.709,sRGB)bTransferCharacteristics            1 (BT.709)bMatrixCoefficients                 4 (SMPTE 170M (BT.601))VideoStreaming Interface Descriptor:bLength                            27bDescriptorType                    36bDescriptorSubtype                  4 (FORMAT_UNCOMPRESSED)bFormatIndex                        2bNumFrameDescriptors                5guidFormat                            {59555932-0000-1000-8000-00aa00389b71}bBitsPerPixel                      16bDefaultFrameIndex                  1bAspectRatioX                       0bAspectRatioY                       0bmInterlaceFlags                 0x00Interlaced stream or variable: NoFields per frame: 2 fieldsField 1 first: NoField pattern: Field 1 onlybCopyProtect                      0VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)bFrameIndex                         1bmCapabilities                   0x01Still image supportedwWidth                           1920wHeight                          1080dwMinBitRate                165888000dwMaxBitRate                165888000dwMaxVideoFrameBufferSize     4147200dwDefaultFrameInterval        2000000bFrameIntervalType                  1dwFrameInterval( 0)           2000000VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)bFrameIndex                         2bmCapabilities                   0x01Still image supportedwWidth                           1280wHeight                           720dwMinBitRate                147456000dwMaxBitRate                147456000dwMaxVideoFrameBufferSize     1843200dwDefaultFrameInterval        1000000bFrameIntervalType                  1dwFrameInterval( 0)           1000000VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)bFrameIndex                         3bmCapabilities                   0x01Still image supportedwWidth                            800wHeight                           600dwMinBitRate                153600000dwMaxBitRate                153600000dwMaxVideoFrameBufferSize      960000dwDefaultFrameInterval         500000bFrameIntervalType                  1dwFrameInterval( 0)            500000VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)bFrameIndex                         4bmCapabilities                   0x01Still image supportedwWidth                            640wHeight                           480dwMinBitRate                147456000dwMaxBitRate                147456000dwMaxVideoFrameBufferSize      614400dwDefaultFrameInterval         333333bFrameIntervalType                  1dwFrameInterval( 0)            333333VideoStreaming Interface Descriptor:bLength                            30bDescriptorType                    36bDescriptorSubtype                  5 (FRAME_UNCOMPRESSED)bFrameIndex                         5bmCapabilities                   0x01Still image supportedwWidth                            640wHeight                           360dwMinBitRate                110592000dwMaxBitRate                110592000dwMaxVideoFrameBufferSize      460800dwDefaultFrameInterval         333333bFrameIntervalType                  1dwFrameInterval( 0)            333333VideoStreaming Interface Descriptor:bLength                             6bDescriptorType                    36bDescriptorSubtype                 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,indexmapbuffer.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,indexmapbuffer.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.mzph.cn/bicheng/30877.shtml

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

相关文章

conda install xformers -c xformers/label/dev 的安装问题

在StableSR项目框架中&#xff0c;需要执行 conda install xformers -c xformers/label/dev 但是报错&#xff0c;错误显示&#xff0c;版本不匹配&#xff0c;如下所示&#xff1a; 我改用pip来安装&#xff0c;好像就不报错了&#xff1a; pip install xformers

javaWeb项目-ssm+vue企业台账管理平台功能介绍

本项目源码&#xff1a;javaweb项目ssm-vue企业台账管理平台源码-说明文档资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboo…

vue项目——前端CryptoJS加密、解密

1、vue项目需要安装CryptoJS安装包 npm install crypto-js 2、在项目中引入CryptoJS import CryptoJS from crypto-js 3、使用&#xff0c;代码如下 // 此处key为16进制let key jiajiajiajiajiajiajiajia;console.log(密钥&#xff1a;, key);// key格式化处理key Crypt…

【前端开发工具】VS Code安装和使用

文章目录 一、前言二、下载三、安装四、配置五、使用5.1 导入项目5.2 本地运行项目5.3 修改界面文案&#xff0c;验证效果5.4 添加日志打印5.5 代码调试5.6 代码提交到Git仓库 六、总结 一、前言 本文介绍一下在前端vue项目中&#xff0c;VS Code的安装和配置。 什么是VS Code…

【干货分享】25地学考研推免夏令营汇总表

​ 25考研学子们&#xff0c;考研准备要赶早。 小编给大家整合准备了25地信考研夏令营时间信息表&#xff0c;需要的宝子收藏起来。 ​ 话不多说&#xff0c;需要的小伙伴直接评论区留言 25地信考研择校信息表&#xff1a;

IT入门知识第一部分《IT基础知识》(1/10)

目录 IT入门知识第一部分《IT基础知识》&#xff08;1/10&#xff09; 1.引言 2.第一部分&#xff1a;IT基础知识 2.1 计算机硬件 CPU&#xff1a;计算机的心脏 内存&#xff1a;数据的临时居所 存储设备&#xff1a;数据的长期仓库 输入输出设备&#xff1a;与计算机的…

[Mysql] 的基础知识和sql 语句.教你速成(上)——逻辑清晰,涵盖完整

目录 前言 上篇的内容概况 下篇的内容概况 数据库的分类 关系型数据库 常见的关系型数据库系统 非关系型数据库 1. 键值对数据库&#xff08;Key-Value Stores&#xff09; 特点&#xff1a; 常见的键值对数据库&#xff1a; 2. 文档数据库&#xff08;Document Store…

【React】Axios请求头注入token

业务背景: Token作为用户的数据标识&#xff0c;在接口层面起到了接口权限控制的作用&#xff0c;也就是说后端有很多接口都需要通过查看当前请求头信息中是否含有token数据&#xff0c;来决定是否正常返回数据 // 添加请求拦截器 request.interceptors.request.use(config …

填坑-celery正常启动后能收到任务但不执行任务的解决办法

场景 Flask开发中用celery 6正常启动后能收到任务但不执行任务的解决办法&#xff0c;也没有错误提示…… INFO/MainProcess] Task app.add_together[ce406ed8-71b3-49e6-8556-f44bfe66549c] received [2024-06-20 19:38:10,632: INFO/SpawnPoolWorker-36] child process 2244…

求最小生成树的新算法

不管 prim 算法还是 kruskal 算法都基于 “当前可见最短边” 作贪心策略&#xff0c;但这并不适合分布式并行操作&#xff0c;比方说所有节点一起构建最小生成树&#xff0c;这些算法都显得同步开销过大&#xff0c;甚至导出错误的结果。 最近研究并构建最大流多路径传输协议的…

如何获得一个Oracle 23ai数据库(vagrant box)

准确的说&#xff0c;是Oracle 23ai Free Developer版&#xff0c;因为企业版目前只在云上&#xff08;OCI和Azure&#xff09;和ECC上提供。 前面我博客介绍了3种方法&#xff1a; Virtual ApplianceRPM安装Docker 今天介绍最近新出的一种方法&#xff0c;也是我最为推荐的…

Debugger的使用

断点调试 1.打断点 2.以debug模式运行 3.流程控制

SQL注入-sqlmap使用

sqlmap简介 一款自动化的SQL注入工具&#xff0c;其主要功能是扫描&#xff0c;发现并利用给定的URL的SQL注入漏洞&#xff0c;目前支持的数据库是MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2, SQLite, Firebird, Sybase和SAP MaxDB Sqlma…

图像处理:Python使用OpenCV 减少图片噪音

文章目录 1. 均值滤波 (Mean Filtering)2. 高斯滤波 (Gaussian Filtering)3. 中值滤波 (Median Filtering)4.代码实现示例5.效果展示 在图像处理中&#xff0c;均值滤波、高斯滤波和中值滤波是三种常用的降噪方法。它们的实现原理各有不同&#xff1a; 1. 均值滤波 (Mean Filte…

Object类hashCode方法和equals方法源码

hashCode方法 顶级类Object里面的方法&#xff0c;所有类都是继承Object的&#xff0c;返回值int类型 根据一定的hash规则&#xff08;存储地址、字段、或者长度等&#xff09;&#xff0c;映射成一个数值&#xff0c;即散列值 public static int hashCode(Object a[]) {if (a…

wps要会员才能把pdf分开,这不纯属智商税吗

我有一个文档 然后 我给你们写好了一个代码 from PyPDF2 import PdfReader, PdfWriterdef split_pdf(file_path, ranges, output_names):# Open the input PDF filewith open(file_path, rb) as pdf_file:reader = PdfReader(pdf_file)total_pages = len(reader.pages)if len…

Cookie、Session、Token的关系和区别

关系 Session与Cookie&#xff1a;Session通常依赖于Cookie来工作。当服务器为客户端创建一个Session时&#xff0c;它会在服务器上存储与客户端相关的信息&#xff0c;并将一个唯一的SessionID通过Cookie发送给客户端。客户端在后续的请求中会携带这个Cookie&#xff08;包含…

北航数据结构与程序设计查找与排序编程题

查找与排序编程题 单词查找&#xff08;查找——基本题&#xff09;排座位&#xff08;简&#xff09;a 单词查找&#xff08;查找——基本题&#xff09; 【问题描述】 从标准输入中读入一个英文单词及查找方式&#xff0c;在一个给定的英文常用单词字典文件dictionary3000.…

如何使用SQL工具批量执行SQL文件?(以MySQL和SQLynx为例)

目录 1. 配置MySQL数据源 2. 打开 SQL 文件 3. 执行 SQL 文件 4. 检查执行结果 5. SQL文件示例 6. 注意事项 7. 总结 在现代数据库管理和操作中&#xff0c;批量执行 SQL 文件在 MySQL 中显现出其巨大的价值和不可替代的作用。通过将多个 SQL 语句集成在一个文件中进行批…

MySQL安装教程,包含root账户密码的修改(绿色版安装)---超简单好用

1、下载(mysql-8.0.27-winx64) 2、下载地址:https://dev.mysql.com/downloads/mysql/ 3、已经将 mysql-8.0.27-winx64 文件放在了文章最后,有需要的自取(解压配置即可用)。 4、配置环境变量: 右键点击我的电脑->属性->高级系统设置->高级->环境变量->系…