毕设系列之Linux V4L2(图形图像采集篇)

2024-06-16 07:08

本文主要是介绍毕设系列之Linux V4L2(图形图像采集篇),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#PS:要转载请注明出处,本人版权所有

#PS:这个只是 《 我自己 》理解,如果和你的

#原则相冲突,请谅解,勿喷

开发环境:Ubuntu 16.04 LTS

1 虽然介绍Linux V4L2的文章已经满大街了,但是这里我也还要讲一些基本的东西。

     1. v4l2 是Video for Linux 2的简称。2. v4l2 不仅仅支持图像类设备,还支持音频等设备类型。3. 能够使用v4l2的前提是Linux内核已经识别并注册了了相关的设备,常见的就是/dev/videox类似的设备文件存在。(如果是做图像类的采集,说白了你得有个摄像头,这个摄像头还得被Linux 内核识别)4. 从上文可知,一个设备要被内核识别必须要由驱动才行,而对于我们常用的图像采集来说,就是要有一个摄像头驱动才行。对于这个问题,linux内核工作者根据UVC这个标准开发了一个通用的驱动程序,并且整合到linux内核中。只要是支持UVC这个通用标准的摄像头芯片,就能够使用这个驱动。(非图像类也有类似的存在,具体这里不做多余阐述)5. 一般来说,常用的Linux平台是的内核是已经编译进去了UVC驱动的。如果是自己移植的嵌入式Linux 内核,请在配置内核选项时候打开UVC驱动的选项。如下图:

这里写图片描述

2 V4L2这个框架的原理简述(这里我们只需要关注几个结构体就可以,要深入,去看内核源代码)

1. struct v4l2_device v4l2框架中的根节点,主要是用来管理和遍历其它子节点。
2. struct v4l2_subdev v4l2框架中的子节点,在v4l2_device下可以有多个v4l2_subdev存在,这里主要是区分设备类型,如图像或者音频等等。
3. struct video_device 具体设备的结构体,并在/dev/下创建相关的设备文件。
4. struct v4l2_buffer 为设备数据交换提供空间。

原理(这里以USB摄像头为例):当一个设备接入内核,首先根据USB标准协议对USB进行初始化,最终完成USB设备信息探测。根据USB设备信息,内核给其分配相应的驱动。这里内核知道我们的USB设备是一个图像设备,这时内核开始初始化v4l2_subdev结构体,并且类型设置为图形图像设备。当初始化好后,内核继续初始化一个video_device结构体,并插入到v4l2_subdev的管理链表中。这里的初始化过程中,就要涉及摄像头驱动的加载,设备文件的创建等等。到这里,整个注册环节就结束了,意味着我们可以使用v4l2框架来操作我们的设备。操作的话,就是各种ops的调用就ok了。(这里涉及到usb设备驱动的初始化和字符型设备驱动等等相关知识,需要更多,自行查阅资料)

3 V4L2的使用(没啥可讲的,各种资料烂大街了,我直接贴源代码)
ym_v4l2.c文件

/*FileName:m_v4l2.cVersion:1.5Description:Created On: 2017-2-21Modified date:2017-3-14Author:Sky
*/
#include <ym_v4l2.h>
int yInitMV4l2(const char * pathname, yMV4L2 * mv4l2){//mv4l2 = mvl;//request alloc IMG_BUFF_NUM DATA_BUF size memif ( (mv4l2->img_buf = (IMG_BUF *)calloc(IMG_BUFF_NUM, sizeof(IMG_BUF))) == NULL){printf("calloc  failed\n");return -1;}if ( (mv4l2->camera_fd = open(pathname, O_RDWR | O_NONBLOCK)) < 0){//open video deviceperror("Open video device faild");return -1;}return 0;
}
int yIoctlV4l2(enum yV4l2Cmd cmd,...){va_list arg;va_start(arg,cmd);yMV4L2 *mv4l2;mv4l2 = va_arg(arg,yMV4L2 *);va_end(arg);switch(cmd){case yVIDIOC_QUERYCAP:{if ( ioctl(mv4l2->camera_fd, VIDIOC_QUERYCAP, &mv4l2->cap) < 0){perror("QUERY VIDEO CAP FAILED");return -1;}printf("DriverName:%s/nCard Name:%s/nBusinfo:%s/nDriverVersion:%u.%u.%u\n",mv4l2->cap.driver,mv4l2->cap.card,mv4l2->cap.bus_info,(mv4l2->cap.version>>16)&0XFF,(mv4l2->cap.version>>8)&0xFF,mv4l2->cap.version&0xFF);if ( !(mv4l2->cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE) ){printf("The device is not a video capture\n");return -1;}if ( !(mv4l2->cap.capabilities & V4L2_CAP_STREAMING) ){printf("The device can not support streaming i/o\n");return -1;}break;} case yVIDIOC_ENUM_FMT:{CLEAR_MEM(mv4l2->desc_fmt);mv4l2->desc_fmt.index = 0;mv4l2->desc_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;while( ioctl(mv4l2->camera_fd, VIDIOC_ENUM_FMT,&mv4l2->desc_fmt) == 0 ){printf("index : %d, format:%s \n", mv4l2->desc_fmt.index,mv4l2->desc_fmt.description);mv4l2->desc_fmt.index++;}break;} case yVIDIOC_S_FMT:{// set data format for devmv4l2->stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;mv4l2->stream_fmt.fmt.pix.width = IMAGE_WIDTH;mv4l2->stream_fmt.fmt.pix.height = IMAGE_HEIGHT;mv4l2->stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//mv4l2->stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;mv4l2->stream_fmt.fmt.pix.field = V4L2_FIELD_ANY;if ( ioctl(mv4l2->camera_fd, VIDIOC_S_FMT, &mv4l2->stream_fmt)  ){perror("Set data format failed");return -1;}break;} case yVIDIOC_G_FMT:{CLEAR_MEM(mv4l2->stream_fmt);mv4l2->stream_fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;  ioctl(mv4l2->camera_fd,VIDIOC_G_FMT,&mv4l2->stream_fmt);  printf("Currentdata format information: width:%d   height:%d\n",mv4l2->stream_fmt.fmt.pix.width,mv4l2->stream_fmt.fmt.pix.height); break;} case yVIDIOC_REQBUFS:{//bzero(&reqbuf, sizeof(reqbuf));CLEAR_MEM(mv4l2->reqbuf);mv4l2->reqbuf.count = IMG_BUFF_NUM;mv4l2->reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;mv4l2->reqbuf.memory = V4L2_MEMORY_MMAP;if ( ioctl(mv4l2->camera_fd, VIDIOC_REQBUFS, &mv4l2->reqbuf) < 0 ){perror("ioctl REQBUFS failed");return -1;}break;}    case yVIDIOC_STREAMON:{mv4l2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if ( ioctl(mv4l2->camera_fd, VIDIOC_STREAMON,&mv4l2->type)< 0){perror("Failed to ioctl:VIDIOC_STREAMON");return -1;}break;}case yVIDIOC_STREAMOFF:{mv4l2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if ( ioctl(mv4l2->camera_fd, VIDIOC_STREAMOFF,&mv4l2->type)< 0){perror("Failed to ioctl:VIDIOC_STREAMOFF");return -1;}break;} case yVIDIOC_S_PARM:{CLEAR_MEM(mv4l2->stream_parm);mv4l2->stream_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mv4l2->stream_parm.parm.capture.timeperframe.numerator = 1;mv4l2->stream_parm.parm.capture.timeperframe.denominator = 10;if ( ioctl(mv4l2->camera_fd, VIDIOC_S_PARM, &mv4l2->stream_parm) < 0){perror("Failed to ioctl:VIDIOC_S_PARM");return -1;}break;} case yVIDIOC_G_PARM:{CLEAR_MEM(mv4l2->stream_parm);mv4l2->stream_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if ( ioctl(mv4l2->camera_fd, VIDIOC_G_PARM, &mv4l2->stream_parm) < 0){perror("Failed to ioctl:VIDIOC_G_PARM");return -1;}if (  mv4l2->stream_parm.parm.capture.capability == V4L2_CAP_TIMEPERFRAME ){printf("This Video Support Set Fps,Now-Fps is : %d\n",mv4l2->stream_parm.parm.capture.timeperframe.denominator);}else{printf("This Video Un-Support Set Fps\n");}break;}case yVIDIOC_DQBUF:{//bzero(&normal_buf, sizeof(normal_buf));CLEAR_MEM(mv4l2->normal_buf);mv4l2->normal_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;mv4l2->normal_buf.memory = V4L2_MEMORY_MMAP;if ( ioctl(mv4l2->camera_fd, VIDIOC_DQBUF, &mv4l2->normal_buf) < 0){perror("Failed to ioctl:VIDIOC_DQBUF");return -1;} break;} case yVIDIOC_QBUF:{if ( ioctl(mv4l2->camera_fd, VIDIOC_QBUF, &mv4l2->normal_buf) < 0){perror("Failed to ioctl:VIDIOC_QBUF");return -1;} break;}case yMMAPTOVEDIOBUF:{for ( int i=0; i < IMG_BUFF_NUM; i++ ){//bzero(&normal_buf, sizeof(normal_buf));CLEAR_MEM(mv4l2->normal_buf);mv4l2->normal_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;mv4l2->normal_buf.memory = V4L2_MEMORY_MMAP;mv4l2->normal_buf.index = i;//get kernel cache informationif ( ioctl(mv4l2->camera_fd, VIDIOC_QUERYBUF,&mv4l2->normal_buf) < 0){perror("Failed to ioctl:VIDIOC_QUERYBUF");return -1;}mv4l2->img_buf[i].len = mv4l2->normal_buf.length;mv4l2->img_buf[i].start = mmap(NULL,mv4l2->normal_buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,mv4l2->camera_fd,mv4l2->normal_buf.m.offset);if ( MAP_FAILED == mv4l2->img_buf[i].start){perror("Failed to mmap");return -1;}}break;}case yPUTVEDIOALLBUFTOQUEUE:{//bzero(&normal_buf, sizeof(normal_buf));for ( int i = 0; i < IMG_BUFF_NUM;i++){CLEAR_MEM(mv4l2->normal_buf);mv4l2->normal_buf.index = i;mv4l2->normal_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;mv4l2->normal_buf.memory = V4L2_MEMORY_MMAP;if ( ioctl(mv4l2->camera_fd, VIDIOC_QBUF,&mv4l2->normal_buf) < 0){perror("Failed to ioctl:VIDIOC_QBUF");return -1;}}  break;}case yUNMMAPTOVEDIOBUF:{for (int i = 0; i < IMG_BUFF_NUM; i++){if ( munmap(mv4l2->img_buf[i].start,mv4l2->img_buf[i].len) < 0){perror("Failed to munmap");return -1;}}  break;}default :{return -1;break;} }return 0;
}int yDestroyMV4l2(yMV4L2 *mv4l2){//StopStream();yIoctlV4l2(yVIDIOC_STREAMOFF,mv4l2);//UnMMapToVedioBUf(mv4l2);yIoctlV4l2(yUNMMAPTOVEDIOBUF,mv4l2);close(mv4l2->camera_fd);free(mv4l2->img_buf);return 0;
}

ym_v4l2.h

/*FileName:ym_v4l2.hVersion:1.5Description:Created On: 2017-2-21Modified date:2017-3-14Author:Sky
*/#ifndef _YM_V4L2_H
#define _YM_V4L2_H#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */#include <ym_v4l2_config.h>
//open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//memset
#include <string.h>
//v4l2
#include <linux/videodev2.h>
//errno
#include <errno.h>
//perror
#include <stdio.h>
//calloc,free
#include <stdlib.h>
//close
#include <unistd.h>
//ioctl
#include <sys/ioctl.h>
//mmap,munmap
#include <sys/mman.h>#include <stdarg.h>#define CLEAR_MEM(x) memset(&(x),0,sizeof(x))enum yV4l2Cmd{yVIDIOC_QUERYCAP = 0,//Get Camera CapabilityyVIDIOC_ENUM_FMT = 1,//Get Camera all support-formatyVIDIOC_S_FMT = 2,//Set Img FormatyVIDIOC_G_FMT = 3,//Get Img FormatyVIDIOC_REQBUFS = 4,//Req Video bufyVIDIOC_STREAMON = 5,//Start streamyVIDIOC_STREAMOFF = 6,//Stop streamyVIDIOC_S_PARM = 7,//Set Fps infoyVIDIOC_G_PARM = 8,//Get Fps infoyVIDIOC_DQBUF = 9,//delete buf from out queueyVIDIOC_QBUF = 10,//put buf to in queueyMMAPTOVEDIOBUF = 11,yUNMMAPTOVEDIOBUF = 12,yPUTVEDIOALLBUFTOQUEUE = 13,};typedef struct {void * start;long len;
} IMG_BUF;typedef struct ymv4l2{int camera_fd;//camara file descriptor IMG_BUF *img_buf;//img buf headstruct v4l2_buffer normal_buf;struct v4l2_fmtdesc desc_fmt;struct v4l2_capability cap;struct v4l2_format stream_fmt;struct v4l2_requestbuffers reqbuf;struct v4l2_streamparm stream_parm;enum v4l2_buf_type type;}yMV4L2; int yInitMV4l2(const char * pathname, yMV4L2 * mvl);
int yDestroyMV4l2(yMV4L2 * mvl);
int yIoctlV4l2(enum yV4l2Cmd cmd,...);//int OpenCamera(const char * pathname);
//int GetCapability(void);
//int GetAllSupportFormat(void);
//int SetFrameInfo(void);//to set fps
//int GetFrameInfo(void);
//int SetImgFormat(void);
//int GetImgFormat(void);
//int RequestVedioBuf(void);
//int MMapToVedioBuf(void);
//int PutVedioBufToQueue(void);
//int UnMMapToVedioBUf(void);
//int StartStream(void);
//int StopStream(void);
//int ConfigV4l2(void);
//int GetVedioBufFromQueue(void);
//int PutVedioBufToQueue(void);#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */ #endif

#PS:请尊重原创,不喜勿喷

#PS:要转载请注明出处,本人版权所有.

有问题请留言,看到后我会第一时间回复

这篇关于毕设系列之Linux V4L2(图形图像采集篇)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1065774

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n