国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux之V4L2驅(qū)動框架

這篇具有很好參考價值的文章主要介紹了Linux之V4L2驅(qū)動框架。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

一、V4L2簡介

二、V4L2操作流程

?1.打開攝像頭

2.查詢設備的屬性/能力/功能

3.獲取攝像頭支持的格式

4.設置攝像頭的采集通道

5.設置/獲取攝像頭的采集格式和參數(shù)

6.申請幀緩沖、內(nèi)存映射、入隊

(1)申請幀緩沖

(2)內(nèi)存映射

(3)入隊

7.開啟視頻采集

8.讀取數(shù)據(jù)、對數(shù)據(jù)進行處理

9.結(jié)束視頻采集

三、應用編程


一、V4L2簡介

V4L2(Video for linux two)是 Linux 內(nèi)核中視頻類設備的一套驅(qū)動框架,為視頻類設備驅(qū)動開發(fā)和應用層提供了一套統(tǒng)一的接口規(guī)范。使用 V4L2 設備驅(qū)動框架注冊的設備會在 Linux 系統(tǒng)/dev/目錄下生成對應的設備節(jié)點文件,設備節(jié)點的名稱通常為 videoX(X 標準一個數(shù)字編號:/dev/videox),每一個 videoX 設備文件就代表一個視頻類設備。應用程序通過對 videoX 設備文件進行 I/O 操作來配置、使用設備類設備。
?

二、V4L2操作流程

V4L2攝像頭驅(qū)動框架的訪問是通過系統(tǒng)IO的接口 ------ ioctl函數(shù),ioctl專用于硬件控制的系統(tǒng)IO的接口。

#include <sys/ioctl.h>? ? ?//包含頭文件
int ioctl(int fd, unsigned long request, ...);
fd: 文件描述符
request: 此參數(shù)與具體要操作的對象有關,?表示向文件描述符請求相應的操作
...: 可變參函數(shù), 第三個參數(shù)需要根據(jù) request 參數(shù)來決定,配合 request 來使用
返回值: 成功返回 0,失敗返回-1

ioctl()是一個文件 IO 操作的雜物箱,可以處理的事情非常雜、不統(tǒng)一,一般用于操作特殊文件或硬件外設,可以通過 ioctl 獲取外設相關信息。通過 ioctl()來完成,搭配不同的 V4L2 指令(request
參數(shù))請求不同的操作,這些指令定義在頭文件 linux/videodev2.h 中,常用的如下圖。

Linux之V4L2驅(qū)動框架

?1.打開攝像頭

視頻類設備對應的設備節(jié)點為/dev/videoX, X 為數(shù)字編號,通常從 0 開始,調(diào)用 open 打開,得到文件描述符 fd。

int fd = -1;
fd = open("/dev/video0", O_RDWR);
if (0 > fd) 
{
    perror( "open error");
    exit(-1);
}

2.查詢設備的屬性/能力/功能 ?

打開設備后,需要查詢設備的屬性,確定該設備是否是一個視頻采集類設備。通過 ioctl()將獲取到一個 struct v4l2_capability 類型數(shù)據(jù), struct v4l2_capability 數(shù)據(jù)結(jié)構(gòu)描述了設備的一些屬性,結(jié)構(gòu)體定義如下:

struct v4l2_capability {
    __u8 driver[16]; /* 驅(qū)動的名字 */
    __u8 card[32]; /* 設備的名字 */
    __u8 bus_info[32]; /* 總線的名字 */
    __u32 version; /* 版本信息 */
    __u32 capabilities; /* 設備擁有的能力 */
    __u32 device_caps;
    __u32 reserved[3]; /* 保留字段 */
};

這里關注capabilities 字段,該字段描述了設備擁有的能力,該字段的值如下

Linux之V4L2驅(qū)動框架

所以可以通過判斷 capabilities字段是否包含 V4L2_CAP_VIDEO_CAPTURE、 來確定它是否是一個攝像頭設備。

struct v4l2_capability cap = {};
ioctl(fd,VIDIOC_QUERYCAP,&cap);
if(cap.capabilities&V4L2_CAP_VIDEO_CAPTURE)
{
    //是一個攝像頭
}

3.獲取攝像頭支持的格式

獲取支持的像素格式使用 VIDIOC_ENUM_FMT 指令

struct v4l2_fmtdesc {
	__u32		    index;             /*格式編號*/
	__u32		    type;              /*攝像頭的格式  V4L2_BUF_TYPE_VIDEO_CAPTURE*/
	__u32               flags;
	__u8		    description[32];   /*描述信息:描述 pixelformat 像素格式。*/
	__u32		    pixelformat;       /*類型格式 --- 4字節(jié):像素格式編號*/
	__u32		    reserved[4];
};

pixelfoemat像素格式:

//定義格式的宏
#define v4l2_fourcc(a, b, c, d)\
	((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
 
#define V4L2_PIX_FMT_YUYV    v4l2_fourcc('Y', 'U', 'Y', 'V')  /* 16 YUV 4:2:2 */ 
#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
#define V4L2_PIX_FMT_MJPEG   v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */
#define V4L2_PIX_FMT_JPEG    v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG   */ 

v4l2_fourcc是 宏定義,通過這個宏以及對應的參數(shù)合成的一個u32 類型數(shù)據(jù)。

type類型:

獲取設備的哪種功能對應的像素格式, 因為有些設備它可能即支持視頻采集功能、又支持視頻輸出等其它的功能;

enum v4l2_buf_type {
    V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, //視頻采集
    V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, //視頻輸出
    V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
    V4L2_BUF_TYPE_VBI_CAPTURE = 4,
    V4L2_BUF_TYPE_VBI_OUTPUT = 5,
    V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
    V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7,
    V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
    V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
    V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10,
    V4L2_BUF_TYPE_SDR_CAPTURE = 11,
    V4L2_BUF_TYPE_SDR_OUTPUT = 12,
    V4L2_BUF_TYPE_META_CAPTURE = 13,
    /* Deprecated, do not use */
    V4L2_BUF_TYPE_PRIVATE = 0x80,
};

type 字 段 需 要 在 調(diào) 用 ioctl() 之 前 設 置 它 的 值 , 對 于 攝 像 頭 , 需 要 將 type 字 段 設 置 為V4L2_BUF_TYPE_VIDEO_CAPTURE,指定將要獲取的是視頻采集的像素格式。

struct v4l2_fmtdesc fmt = {};
fmt.index = 0;//第一種格式
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//獲取攝像頭的格式
ioctl(fd,VIDIOC_ENUM_FMT,&fmt);

4.設置攝像頭的采集通道

int index = 0;//使用通道0
ioctl(fd,VIDIOC_S_INPUT,&index);

5.設置/獲取攝像頭的采集格式和參數(shù)

使用 VIDIOC_G_FMT 指令查看設備當期的格式和使用 VIDIOC_S_FMT 指令設置設備的格式;

int ioctl(int fd, VIDIOC_G_FMT, struct v4l2_format *fmt);
int ioctl(int fd, VIDIOC_S_FMT, struct v4l2_format *fmt);

ioctl()會將獲取到的數(shù)據(jù)寫入到 fmt 指針所指向的對象中或者會使用 fmt 所指對象的數(shù)據(jù)去設置設備的格式, struct v4l2_format 結(jié)構(gòu)體描述了格式相關的信息。

struct v4l2_format {
	__u32	 type;//V4L2_BUF_TYPE_VIDEO_CAPTURE
	union {
		struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
		struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
		struct v4l2_window		win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
		struct v4l2_vbi_format		vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
		struct v4l2_sliced_vbi_format	sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
		struct v4l2_sdr_format		sdr;     /* V4L2_BUF_TYPE_SDR_CAPTURE */
		__u8	raw_data[200];                   /* user-defined */
	} fmt;
};

struct v4l2_pix_format {
	__u32         		width;//像素寬度
	__u32			height;//像素高度
	__u32			pixelformat;//采集格式 V4L2_PIX_FMT_YVYU
	__u32			field;		/* V4L2_FIELD_NONE */
	__u32            	bytesperline;	/* for padding, zero if unused */
	__u32          		sizeimage;
	__u32			colorspace;	/* enum v4l2_colorspace */
	__u32			priv;		/* private data, depends on pixelformat */
	__u32			flags;		/* format flags (V4L2_PIX_FMT_FLAG_*) */
	__u32			ycbcr_enc;	/* enum v4l2_ycbcr_encoding */
	__u32			quantization;	/* enum v4l2_quantization */
	__u32			xfer_func;	/* enum v4l2_xfer_func */
};

type 字段依然與前面介紹的結(jié)構(gòu)體中的 type 字段意義相同,不管是獲取格式、還是設置格式都需要在調(diào)用 ioctl()函數(shù)之前設置它的值。接下來是一個 union 共用體,當 type 被設置為V4L2_BUF_TYPE_VIDEO_CAPTURE 時, pix 變量生效,它是一個 struct v4l2_pix_format 類型變量,記錄了視頻幀格式相關的信息。

獲取當前的格式、并設置格式:

struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = 640;
format.fmt.pix.height = 480;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
format.fmt.pix.field= V4L2_FIELD_NONE ;

ioctl(fd,VIDIOC_S_FMT,&format); //S:set

6.申請幀緩沖、內(nèi)存映射、入隊

(1)申請幀緩沖

讀取攝像頭數(shù)據(jù)的方式有兩種:一種是 read 方式,直接通過 read()系統(tǒng)調(diào)用讀取攝像頭采集到的數(shù)據(jù);另一種是 streaming 方式。使用 VIDIOC_QUERYCAP 指令查詢設備的屬性、得到一個 struct v4l2_capability 類型數(shù)據(jù), 其中 capabilities 字段記錄了設備擁有的能力,當該字段包含
V4L2_CAP_READWRITE 時,表示設備支持 read I/O 方式讀取數(shù)據(jù);當該字段包含V4L2_CAP_STREAMING時,表示設備支持 streaming I/O 方式;使用streaming I/O 方式,需要向設備申請幀緩沖,并將幀緩沖映射到應用程序進程地址空間中。

Linux之V4L2驅(qū)動框架

?使用 VIDIOC_REQBUFS 指令可申請幀緩沖:

ioctl(int fd, VIDIOC_REQBUFS, struct v4l2_requestbuffers *reqbuf);

調(diào)用 ioctl()需要傳入一個 struct v4l2_requestbuffers *指針, struct v4l2_requestbuffers 結(jié)構(gòu)體描述了申請幀緩沖的信息, ioctl()會根據(jù) reqbuf 所指對象填充的信息進行申請。
?

struct v4l2_requestbuffers {
	__u32			count;//緩沖區(qū)塊數(shù) ----- 4
	__u32			type;		/* enum v4l2_buf_type */
	__u32			memory;		/* enum v4l2_memory */
	__u32			reserved[2];
};

type 字段與前面所提及到的 type 字段意義相同,count 字段用于指定申請幀緩沖的數(shù)量
memory 字段可取值如下:

enum v4l2_memory {
    V4L2_MEMORY_MMAP = 1,
    V4L2_MEMORY_USERPTR = 2,
    V4L2_MEMORY_OVERLAY = 3,
    V4L2_MEMORY_DMABUF = 4,
};

通常將 memory 設置為 V4L2_MEMORY_MMAP 。
申請緩存:

struct v4l2_requestbuffers req = {};
req.count = 4;     //申請4個幀緩存
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;

ioctl(fd,VIDIOC_REQBUFS,&req);

streaming I/O 方式會在內(nèi)核空間中維護一個幀緩沖隊列, 驅(qū)動程序會將從攝像頭讀取的一幀數(shù)據(jù)寫入到隊列中的一個幀緩沖,接著將下一幀數(shù)據(jù)寫入到隊列中的下一個幀緩沖;當應用程序需要讀取一幀數(shù)據(jù)時,需要從隊列中取出一個裝滿一幀數(shù)據(jù)的幀緩沖,這個取出過程就叫做出隊;當應用程序處理完這一幀數(shù)據(jù)后,需要再把這個幀緩沖加入到內(nèi)核的幀緩沖隊列中,這個過程叫做入隊。

Linux之V4L2驅(qū)動框架

使用 VIDIOC_REQBUFS 指令申請幀緩沖, 該緩沖區(qū)是由內(nèi)核所維護的,應用程序不能直接讀取該緩沖區(qū)的數(shù)據(jù),需要將其映射到用戶空間中,應用程序讀取映射區(qū)的數(shù)據(jù)實際上是讀取內(nèi)核維護的幀緩沖中的數(shù)據(jù)。

(2)內(nèi)存映射

在映射之前,需要查詢幀緩沖的信息:幀緩沖的長度、偏移量。使用VIDIOC_QUERYBUF指令查詢:

ioctl(int fd, VIDIOC_QUERYBUF, struct v4l2_buffer *buf);

調(diào)用 ioctl()需要傳入一個 struct v4l2_buffer *指針, struct v4l2_buffer 結(jié)構(gòu)體描述了幀緩沖的信息, ioctl()會將獲取到的數(shù)據(jù)寫入到 buf 指針所指的對象中。

struct v4l2_buffer {
	__u32			index;//編號
	__u32			type;//V4L2_BUF_TYPE_VIDEO_CAPTURE
	__u32			bytesused;//使用的字節(jié)數(shù)
	__u32			flags;
	__u32			field;
	struct timeval		timestamp;
	struct v4l2_timecode	timecode;
	__u32			sequence;

	/* memory location */
	__u32			memory;//V4L2_MEMORY_MMAP
	union {
		__u32           offset;//偏移
		unsigned long   userptr;
		struct v4l2_plane *planes;
		__s32		fd;
	} m;
	__u32			length;//長度
	__u32			reserved2;
	__u32			reserved;
};


index 字段表示一個編號, 申請的多個幀緩沖、 每一個幀緩沖都有一個編號,從 0 開始。一次 ioctl()調(diào)用只能獲取指定編號對應的幀緩沖的信息,所以要獲取多個幀緩沖的信息,需要重復調(diào)用多次,每調(diào)用一次ioctl()、 index 加 1,指向下一個幀緩沖。

type 字段和memory 字段與前面介紹的一樣。length 字段表示幀緩沖的長度,共同體中的 offset 表示幀緩沖的偏移量。因為應用程序通過 VIDIOC_REQBUFS 指令申請幀緩沖時,內(nèi)核會向操作系統(tǒng)申請一塊內(nèi)存空間作為幀緩沖區(qū),內(nèi)存空間的大小就等于申請的幀緩沖數(shù)量 * 每一個幀緩沖的大小,每一個幀緩沖對應到這一塊內(nèi)存空間的某一段,所以它們都有一個地址偏移量。
?

申請幀緩沖后、調(diào)用 mmap()將幀緩沖映射到用戶地址空間
?

struct v4l2_buffer buf = {};
buf.index = xxx;//0~3
but.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;

ioctl(fd,VIDIOC_QUERYBUF,&buf);
//映射到用戶空間
mmap(NULL,buf.length,.......,fd,buf.m.offset);

(3)入隊

使用 VIDIOC_QBUF 指令將幀緩沖放入到內(nèi)核的幀緩沖隊列中,調(diào)用 ioctl()之前,需要設置 struct v4l2_buffer 類型對象的 memory、 type 字段

ioctl(fd,VIDIOC_QBUF,&buf);

7.開啟視頻采集

使用 VIDIOC_DQBUF 指令開啟視頻采集,

ioctl(int fd, VIDIOC_STREAMON, int *type); //開啟視頻采集
ioctl(int fd, VIDIOC_STREAMOFF, int *type); //停止視頻采集
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMON,&buf_type);

8.讀取數(shù)據(jù)、對數(shù)據(jù)進行處理

開啟視頻采集之后,便可以去讀取數(shù)據(jù)?,直接讀取每一個幀緩沖的在用戶空間的映射區(qū)即可讀取到攝像頭采集的每一幀圖像數(shù)據(jù)。在讀取數(shù)據(jù)之前,需要將幀緩沖從內(nèi)核的幀緩沖隊列中取出,這個操作叫做幀緩沖出隊。幀緩沖出隊,便可讀取數(shù)據(jù),對數(shù)據(jù)進行處理:將攝像頭采集的圖像顯示到 LCD屏上;數(shù)據(jù)處理完成之后,再將幀緩沖入隊,往復操作。

使用 VIDIOC_DQBUF 指令執(zhí)行出隊操作

ioctl(int fd, VIDIOC_DQBUF, struct v4l2_buffer *buf);
while(1){
    //從采集隊列中取出一幀
    ioctl(fd,VIDIOC_DQBUF,&buf);
    //將該幀的數(shù)據(jù)拷貝走
    memcpy(....);
    //將取出的一幀放回隊列
    ioctl(fd,VIDIOC_QBUF,&buf);
    
    //顯示,存儲......
}

9.結(jié)束視頻采集

結(jié)束視頻采集,使用 VIDIOC_STREAMOFF 指令文章來源地址http://www.zghlxwxcb.cn/news/detail-482779.html

enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMOFF,&buf_type);

//解除映射
//關閉設備文件

三、應用編程

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

typedef struct{
	char *start;
	size_t length;
}buffer_t;

buffer_t buffer[4];
buffer_t current;//保存當前取出的一幀

int lcd_fd;
int *memp;

unsigned int sign3 = 0;

int yuyv2rgb(int y, int u, int v)
{
     unsigned int pixel24 = 0;
     unsigned char *pixel = (unsigned char *)&pixel24;
     int r, g, b;
     static int  ruv, guv, buv;

     if(sign3)
     {
         sign3 = 0;
         ruv = 1159*(v-128);
         guv = 380*(u-128) + 813*(v-128);
         buv = 2018*(u-128);
     }

     r = (1164*(y-16) + ruv) / 1000;
     g = (1164*(y-16) - guv) / 1000;
     b = (1164*(y-16) + buv) / 1000;

     if(r > 255) r = 255;
     if(g > 255) g = 255;
     if(b > 255) b = 255;
     if(r < 0) r = 0;
     if(g < 0) g = 0;
     if(b < 0) b = 0;

     pixel[0] = r;
     pixel[1] = g;
     pixel[2] = b;

     return pixel24;
}


int yuyv2rgb0(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height)
{
     unsigned int in, out;
     int y0, u, y1, v;
     unsigned int pixel24;
     unsigned char *pixel = (unsigned char *)&pixel24;
     unsigned int size = width*height*2;

     for(in = 0, out = 0; in < size; in += 4, out += 6)
     {
          y0 = yuv[in+0];
          u  = yuv[in+1];
          y1 = yuv[in+2];
          v  = yuv[in+3];

          sign3 = 1;
          pixel24 = yuyv2rgb(y0, u, v);
          rgb[out+0] = pixel[0];    
          rgb[out+1] = pixel[1];
          rgb[out+2] = pixel[2];

          pixel24 = yuyv2rgb(y1, u, v);
          rgb[out+3] = pixel[0];
          rgb[out+4] = pixel[1];
          rgb[out+5] = pixel[2];

     }
     return 0;
}

//LCD初始化
void lcd_init()
{
	lcd_fd = open("/dev/fb0",O_RDWR);
	if(lcd_fd==-1){
		perror("open");;
		exit(-1);
	}
	
	//映射
	memp = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
	if(memp==MAP_FAILED){
		perror("mmap");;
		exit(-1);
	}
}

void lcd_uninit()
{
	munmap(memp,800*480*4);
	close(lcd_fd);
}

int main()
{
	lcd_init();
	
	//1.打開攝像頭
	int fd = open("/dev/video7",O_RDWR);
	if(fd==-1){
		perror("open");
		exit(-1);
	}
	
	//2.獲取功能參數(shù)
	struct v4l2_capability cap = {};
	int res = ioctl(fd,VIDIOC_QUERYCAP,&cap);
	if(res==-1){
		perror("ioctl cap");
		exit(-1);
	}
	
	if(cap.capabilities&V4L2_CAP_VIDEO_CAPTURE){
		//設備是一個攝像頭
		printf("capture device!\n");
	}
	else{
		printf("not a capture device!\n");
		exit(-1);
	}
	
	//3.獲取攝像頭支持的格式
	struct v4l2_fmtdesc fmt = {};
	fmt.index = 0;//第一種格式
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//獲取攝像頭的格式
	
	while((res=ioctl(fd,VIDIOC_ENUM_FMT,&fmt))==0){
		printf("pixformat=%c%c%c%c,description=%s\n",fmt.pixelformat&0xff,(fmt.pixelformat>>8)&0xff,
			   (fmt.pixelformat>>16)&0xff,(fmt.pixelformat>>24)&0xff,fmt.description);
		fmt.index++;
	}
	
	//4.設置采集通道
	int index = 0;//使用通道0
	res = ioctl(fd,VIDIOC_S_INPUT,&index);
	if(res==-1){
		perror("ioctl s_input");
		exit(-1);
	}
	
	//5.設置攝像頭的采集格式
	struct v4l2_format format = {};
	format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	format.fmt.pix.width = 640;
	format.fmt.pix.height = 480;
	format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//YUYV格式
	format.fmt.pix.field= V4L2_FIELD_NONE;
	res = ioctl(fd,VIDIOC_S_FMT,&format);
	if(res==-1){
		perror("ioctl s_fmt");
		exit(-1);
	}
	
	//6.申請緩存空間
	struct v4l2_requestbuffers req = {};
	req.count = 4;
	req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	req.memory = V4L2_MEMORY_MMAP;
	res = ioctl(fd,VIDIOC_REQBUFS,&req);
	if(res==-1){
		perror("ioctl reqbufs");
		exit(-1);
	}
	
	//7.分配,映射,入隊
	size_t i,max_len = 0;
	for(i=0;i<4;i++){
		struct v4l2_buffer buf = {};
		buf.index = i;//0~3
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		res = ioctl(fd,VIDIOC_QUERYBUF,&buf);
		if(res==-1){
			perror("ioctl querybuf");
			exit(-1);
		}
		
		//記錄最大長度
		if(buf.length>max_len)
			max_len = buf.length;
		
		//映射
		buffer[i].length = buf.length;
		buffer[i].start = mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);
		if(buffer[i].start==MAP_FAILED){
			perror("mmap");
			exit(-1);
		}
		
		//入隊
		res = ioctl(fd,VIDIOC_QBUF,&buf);
		if(res==-1){
			perror("ioctl qbuf");
			exit(-1);
		}
	}
	
	//申請臨時緩沖區(qū)
	current.start = malloc(max_len);
	if(current.start==NULL){
		perror("malloc");
		exit(-1);
	}
	
	//8.啟動攝像頭
	enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	res = ioctl(fd,VIDIOC_STREAMON,&buf_type);
	if(res==-1){
			perror("ioctl streamon");
			exit(-1);
	}
	
	//延時
	sleep(1);
	
	//RGB緩沖區(qū)
	char rgb[640*480*3];
	//9.采集數(shù)據(jù)
	while(1){
		struct v4l2_buffer buf = {};
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		//出隊
		res = ioctl(fd,VIDIOC_DQBUF,&buf);
		if(res==-1){
			perror("ioctl dqbuf");
		}
		
		//拷貝數(shù)據(jù)
		memcpy(current.start,buffer[buf.index].start,buf.bytesused);
		current.length = buf.bytesused;
		
		//入隊
		res = ioctl(fd,VIDIOC_QBUF,&buf);
		if(res==-1){
			perror("ioctl qbuf");
		}
		
		//顯示 保存 傳輸.....
		//YUYV轉(zhuǎn)RGB
		yuyv2rgb0(current.start,rgb,640,480);
		//顯示到LCD
		int x,y;
		for(y=0;y<480;y++){
			for(x=0;x<640;x++){
				*(memp+y*800+x) = rgb[3*(y*640+x)]<<16 | rgb[3*(y*640+x)+1]<<8 | rgb[3*(y*640+x)+2];
			}
		}
	}
	
	//10.關閉攝像頭采集
	buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	res = ioctl(fd,VIDIOC_STREAMOFF,&buf_type);
	if(res==-1){
			perror("ioctl streamoff");
			exit(-1);
	}
	
	//解除映射
	for(i=0;i<4;i++){
		munmap(buffer[i].start,buffer[i].length);
	}
	free(current.start);
	
	close(fd);
	lcd_uninit();
	return 0;
}

到了這里,關于Linux之V4L2驅(qū)動框架的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Linux + 香橙派 + V4L2 + http 實現(xiàn)遠程監(jiān)控攝像頭在網(wǎng)頁端顯示

    Linux + 香橙派 + V4L2 + http 實現(xiàn)遠程監(jiān)控攝像頭在網(wǎng)頁端顯示

    項目需求,需要做一個基于邊緣端的人臉識別遠程監(jiān)控攝像頭并在網(wǎng)頁前端展示 ,這里采用國產(chǎn)香橙派作為邊緣計算終端,安裝ubuntu系統(tǒng),系統(tǒng)中采用v4l2接口對攝像頭進行獲取,當客戶端通過網(wǎng)頁進行請求時,服務器通過http服務的形式將一幀幀圖像發(fā)送給客戶端,只要一秒

    2024年02月15日
    瀏覽(20)
  • V4L2常用調(diào)試命令

    這篇文章簡單記錄一下RK平臺基于V4L2框架camera調(diào)試過程中常用的一些命令: (1)查看拓撲結(jié)構(gòu):查看media0的pipeline (2)抓數(shù)據(jù)流命令: 對video0節(jié)點,設置格式為NV12,分辨率為1920x1080,不裁剪,4個buf輪轉(zhuǎn),--verbose的作用是刷出幀率。 (3)抓圖命令: 類似上面的,將圖像保

    2024年02月03日
    瀏覽(19)
  • V4L2 攝像頭應用編程

    V4L2 攝像頭應用編程

    ALPHA/Mini I.MX6U 開發(fā)板配套支持多種不同的攝像頭,包括正點原子的ov5640(500W 像素)、 ov2640(200W 像素)以及ov7725(不帶FIFO、30W 像素)這三款攝像頭,在開發(fā)板出廠系統(tǒng)上,可以使用這些攝像頭;當然,除此之外我們還可以使用USB 攝像頭,直接將USB 攝像頭插入到開發(fā)板上的

    2024年02月11日
    瀏覽(21)
  • linux v4l2架構(gòu)分析之異步注冊v4l2_async_subdev_notifier_register、v4l2_async_register_subdev、v4l2_async_notifie

    ? ? ? ? 在camera驅(qū)動注冊中,v4l2_async_subdev_notifier_register、v4l2_async_register_subdev、v4l2_async_notifier_register這幾個函數(shù)都會被使用到,三者在異步注冊的實現(xiàn)中是緊密關聯(lián)的,所以本文將三者放在一起進行分析。本文主要介紹異步注冊的功能的整體實現(xiàn)框架,為了更好把握整體思

    2024年02月14日
    瀏覽(36)
  • 汽車IVI中控開發(fā)入門及進階(十二):V4L2視頻

    前言 ? ? IVI,In-Vehicle Infotainment,智能座艙信息娛樂系統(tǒng),或稱車載信息娛樂系統(tǒng), 汽車中控也被稱為車機、車載多媒體、車載娛樂等, 它是智能座艙的重要組成部分。IVI 采用車載專用中央處理器,基于車身總線系統(tǒng)和聯(lián)網(wǎng)服務提供車載綜合信息處理功能,包括音頻播放、

    2024年02月04日
    瀏覽(21)
  • 內(nèi)存不足V4L2 申請DMC緩存報錯問題

    當內(nèi)存不足時,V4L2可能存在申請DMA緩存報錯,如下日志:

    2024年02月12日
    瀏覽(17)
  • c 攝像頭利用v4l2直接生成avi視頻(不利用ffmpeg)

    自定義avi結(jié)構(gòu)頭文件?,F(xiàn)在不能實時顯示攝像頭畫面,準備參照fim(終端中顯示圖片),直接對顯示framebuffer操作,顯示視頻。不用qt等。 生成的視頻根據(jù)機子的性能不同,詁計要手動調(diào)一下生成視頻的幀率。 播放: $ aplay ?musicdemo.wmv 錄音: $ arecord -c 2 -r 44100 -f S16_LE musicd

    2024年02月08日
    瀏覽(21)
  • opencv-python調(diào)用攝像頭失敗 global /io/opencv/modules/videoio/src/cap_v4l.cpp (1000) tryIoctl VIDEOIO(V4L2

    Ubuntu 18.04 aarch64 Python 3.7.15 opencv-python 4.6.0 插入USB攝像頭后, /dev/video0 會正常出現(xiàn),使用 fswebcam 也能正常拍攝照片。但運行 opencv-python 的視頻拍攝例程時出錯,例程如下。 如果例程正確運行,屏幕窗口中將顯示灰度處理后的攝像頭實時視頻。 報錯信息如下 單步調(diào)試后,發(fā)現(xiàn)

    2023年04月24日
    瀏覽(22)
  • 【Linux驅(qū)動】Linux--V4L2視頻驅(qū)動框架

    【Linux驅(qū)動】Linux--V4L2視頻驅(qū)動框架

    v4l2驅(qū)動框架主要的對象有video_device、v4l2_device、v4l2_subdev、videobuf video_device 一個字符設備,為用戶空間提供設備節(jié)點(/dev/videox),提供系統(tǒng)調(diào)用的相關操作(open、ioctl…) v4l2_device 嵌入到video_device中,表示一個v4l2設備的實例 v4l2_subdev 依附在v4l2_device之下,并表示一個v4l2設備的子

    2024年02月14日
    瀏覽(18)
  • Ubuntu下python-opencv無法打開攝像頭,open VIDEOIO(V4L2:/dev/video0): can‘t open camera by index

    Ubuntu下python-opencv無法打開攝像頭,open VIDEOIO(V4L2:/dev/video0): can‘t open camera by index

    我們在ubuntu下使用opencv獲取攝像頭畫面是,報錯 open VIDEOIO(V4L2:/dev/video0): can‘t open camera by index 然后觀察虛擬機桌面的右下角,如果出現(xiàn)攝像頭有小綠點表示連接成功 然后我們來測試一下,攝像頭的畫面 ####### 這是攝像頭傳輸回來的畫面

    2024年02月16日
    瀏覽(52)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包