V4L2 编程

Jun 07, 2016 pm 03:43 PM
for l video 定義 程式設計

V4L2 编程 1. 定义 V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。 2. 工作流程: 打开设备- 检查和设置设备属性- 设置帧式- 设置一种输入输出方法(缓冲区管理)- 循环获取数据- 关闭设备。 3. 设备的打开和关闭: #inc

V4L2 编程 


1. 定义 

V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。


2. 工作流程: 

打开设备-> 检查和设置设备属性-> 设置帧格式-> 设置一种输入输出方法(缓冲区管理)-> 循环获取数据-> 关闭设备。

3. 设备的打开和关闭: 


#include  

int open(const char *device_name, int flags); 


#include  

int close(int fd); 

例: 

int fd=open(“/dev/video0”,O_RDWR);// 打开设备

close(fd);// 关闭设备

注意:V4L2 的相关定义包含在头文件 中. 


4. 查询设备属性: VIDIOC_QUERYCAP 

相关函数:

int ioctl(int fd, int request, struct v4l2_capability *argp); 

相关结构体:

struct v4l2_capability 


__u8 driver[16]; // 驱动名字

__u8 card[32]; // 设备名字

__u8 bus_info[32]; // 设备在系统中的位置

__u32 version; // 驱动版本号

__u32 capabilities; // 设备支持的操作

__u32 reserved[4]; // 保留字段


}; 

capabilities 常用值: 

V4L2_CAP_VIDEO_CAPTURE // 是否支持图像获取

例:显示设备信息 

struct v4l2_capability cap; 

ioctl(fd,VIDIOC_QUERYCAP,&cap); 

printf(“Driver Name:%s/nCard Name:%s/nBus info:%s/nDriver Version:%u.%u.%u/n”,cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&OXFF); 


5. 帧格式: 

VIDIOC_ENUM_FMT // 显示所有支持的格式

int ioctl(int fd, int request, struct v4l2_fmtdesc *argp); 

struct v4l2_fmtdesc 


__u32 index; // 要查询的格式序号,应用程序设置

enum v4l2_buf_type type; // 帧类型,应用程序设置

__u32 flags; // 是否为压缩格式

__u8 description[32]; // 格式名称

__u32 pixelformat; // 格式

__u32 reserved[4]; // 保留

}; 

例:显示所有支持的格式 

struct v4l2_fmtdesc fmtdesc; 

fmtdesc.index=0; 

fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 

printf("Support format:/n"); 

while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1) 


printf("/t%d.%s/n",fmtdesc.index+1,fmtdesc.description); 

fmtdesc.index++; 



// 查看或设置当前格式

VIDIOC_G_FMT, VIDIOC_S_FMT 

// 检查是否支持某种格式

VIDIOC_TRY_FMT 

int ioctl(int fd, int request, struct v4l2_format *argp); 

struct v4l2_format 

enum v4l2_buf_type type;// 帧类型,应用程序设置

union fmt 


struct v4l2_pix_format pix;// 视频设备使用

struct v4l2_window win; 

struct v4l2_vbi_format vbi; 

struct v4l2_sliced_vbi_format sliced; 

__u8 raw_data[200]; 

}; 

}; 

struct v4l2_pix_format 


__u32 width; // 帧宽,单位像素

__u32 height; // 帧高,单位像素

__u32 pixelformat; // 帧格式

enum v4l2_field field; 

__u32 bytesperline; 

__u32 sizeimage; 

enum v4l2_colorspace colorspace; 

__u32 priv; 

}; 

例:显示当前帧的相关信息 

struct v4l2_format fmt; 

fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 

ioctl(fd,VIDIOC_G_FMT,&fmt); 

printf(“Current data format information:/n/twidth:%d/n/theight:%d/n”,fmt.fmt.width,fmt.fmt.height); 

struct v4l2_fmtdesc fmtdesc; 

fmtdesc.index=0; 

fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 

while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1) 


if(fmtdesc.pixelformat & fmt.fmt.pixelformat) 


printf(“/tformat:%s/n”,fmtdesc.description); 

break; 


fmtdesc.index++; 



例:检查是否支持某种帧格式 

struct v4l2_format fmt; 

fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 

fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_RGB32; 

if(ioctl(fd,VIDIOC_TRY_FMT,&fmt)==-1) 

if(errno==EINVAL) 

printf(“not support format RGB32!/n”); 

6. 图像的缩放 

VIDIOC_CROPCAP 

int ioctl(int fd, int request, struct v4l2_cropcap *argp); 

struct v4l2_cropcap 


enum v4l2_buf_type type;// 应用程序设置

struct v4l2_rect bounds;// 最大边界

struct v4l2_rect defrect;// 默认值

struct v4l2_fract pixelaspect; 

}; 

// 设置缩放

VIDIOC_G_CROP,VIDIOC_S_CROP 

int ioctl(int fd, int request, struct v4l2_crop *argp); 

int ioctl(int fd, int request, const struct v4l2_crop *argp); 

struct v4l2_crop 


enum v4l2_buf_type type;// 应用程序设置

struct v4l2_rect c; 

} ;

7. 申请和管理缓冲区,应用程序和设备有三种交换数据的方法,直接 read/write ,内存映射 (memory mapping) ,用户指针。这里只讨论 memory mapping. 

// 向设备申请缓冲区

VIDIOC_REQBUFS 

int ioctl(int fd, int request, struct v4l2_requestbuffers *argp); 

struct v4l2_requestbuffers 


__u32 count; // 缓冲区内缓冲帧的数目

enum v4l2_buf_type type; // 缓冲帧数据格式

enum v4l2_memory memory; // 区别是内存映射还是用户指针方式

__u32 reserved[2]; 

}; 

enum v4l2_memoy {V4L2_MEMORY_MMAP,V4L2_MEMORY_USERPTR}; 

//count,type,memory 都要应用程序设置

例:申请一个拥有四个缓冲帧的缓冲区 

struct v4l2_requestbuffers req; 

req.count=4; 

req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 

req.memory=V4L2_MEMORY_MMAP; 

ioctl(fd,VIDIOC_REQBUFS,&req); 


获取缓冲帧的地址,长度:

VIDIOC_QUERYBUF 

int ioctl(int fd, int request, struct v4l2_buffer *argp); 

struct v4l2_buffer 



__u32 index; //buffer 序号 

enum v4l2_buf_type type; //buffer 类型

__u32 byteused; //buffer 中已使用的字节数

__u32 flags; // 区分是MMAP 还是USERPTR 

enum v4l2_field field; 

struct timeval timestamp;// 获取第一个字节时的系统时间

struct v4l2_timecode timecode; 

__u32 sequence; // 队列中的序号

enum v4l2_memory memory;//IO 方式,被应用程序设置

union m 

__u32 offset;// 缓冲帧地址,只对MMAP 有效

unsigned long userptr; 

}; 

__u32 length;// 缓冲帧长度

__u32 input; 

__u32 reserved; 

}; 

MMAP ,定义一个结构体来映射每个缓冲帧。

Struct buffer 


void* start; 

unsigned int length; 

}*buffers; 


#include  

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 

//addr 映射起始地址,一般为NULL ,让内核自动选择

//length 被映射内存块的长度

//prot 标志映射后能否被读写,其值为PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONE 

//flags 确定此内存映射能否被其他进程共享,MAP_SHARED,MAP_PRIVATE 

//fd,offset, 确定被映射的内存地址

返回成功映射后的地址,不成功返回MAP_FAILED ((void*)-1); 

int munmap(void *addr, size_t length);// 断开映射

//addr 为映射后的地址,length 为映射后的内存长度
 
例:将四个已申请到的缓冲帧映射到应用程序,用buffers 指针记录。 

buffers = (buffer*)calloc (req.count, sizeof (*buffers)); 

if (!buffers) { 

fprintf (stderr, "Out of memory/n"); 

exit (EXIT_FAILURE); 


// 映射

for (unsigned int n_buffers = 0; n_buffers
struct v4l2_buffer buf; 

memset(&buf,0,sizeof(buf)); 

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

buf.memory = V4L2_MEMORY_MMAP; 

buf.index = n_buffers; 

// 查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小

if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) 

exit(-1); 

buffers[n_buffers].length = buf.length; 

// 映射内存

buffers[n_buffers].start =mmap (NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd, buf.m.offset); 

if (MAP_FAILED == buffers[n_buffers].start) 

exit(-1); 



8. 缓冲区处理好之后,就可以开始获取数据了 

// 启动/ 停止数据流

VIDIOC_STREAMON,VIDIOC_STREAMOFF 

int ioctl(int fd, int request, const int *argp); 

//argp 为流类型指针,如V4L2_BUF_TYPE_VIDEO_CAPTURE. 

在开始之前,还应当把缓冲帧放入缓冲队列:

VIDIOC_QBUF// 把帧放入队列

VIDIOC_DQBUF// 从队列中取出帧

int ioctl(int fd, int request, struct v4l2_buffer *argp); 

例:把四个缓冲帧放入队列,并启动数据流 

unsigned int i; 

enum v4l2_buf_type type; 

// 将缓冲帧放入队列

for (i = 0; i { 

struct v4l2_buffer buf; 

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

buf.memory = V4L2_MEMORY_MMAP; 

buf.index = i; 

ioctl (fd, VIDIOC_QBUF, &buf); 



type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

ioctl (fd, VIDIOC_STREAMON, &type); 

// 这有个问题,这些buf 看起来和前面申请的buf 没什么关系,为什么呢? 


例:获取一帧并处理 

struct v4l2_buffer buf; 

CLEAR (buf); 

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

buf.memory = V4L2_MEMORY_MMAP; 

// 从缓冲区取出一个缓冲帧

ioctl (fd, VIDIOC_DQBUF, &buf); 

// 图像处理

process_image (buffers[buf.index].start); 

// 将取出的缓冲帧放回缓冲区

ioctl (fd, VIDIOC_QBUF, &buf); 

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1670
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1273
29
C# 教程
1256
24
摩托羅拉 Razr 50 Ultra 出現在洩露的預告視頻中,配有防水外殼和巨大的副顯示屏 摩托羅拉 Razr 50 Ultra 出現在洩露的預告視頻中,配有防水外殼和巨大的副顯示屏 Jun 20, 2024 pm 09:31 PM

過去幾週,摩托羅拉 Razr 50 和 Razr 50 Ultra 最重要的規格和歐元價格已經洩露。現在,極其可靠的洩密者 @MysteryLupin 能夠發布下面嵌入的預告視頻,其中

使用正規表示式去除 PHP 數組中的重複值 使用正規表示式去除 PHP 數組中的重複值 Apr 26, 2024 pm 04:33 PM

使用正規表示式從PHP數組中移除重複值的方法:使用正規表示式/(.*)(.+)/i匹配並取代重複項。遍歷數組元素,使用preg_match檢查匹配情況。如果匹配,請跳過值;否則,將其添加到無重複值的新數組中。

Pixel 9 Pro XL 與 iPhone 15 Pro Max 相機比較顯示谷歌在視頻和變焦性能方面取得了令人驚訝的勝利 Pixel 9 Pro XL 與 iPhone 15 Pro Max 相機比較顯示谷歌在視頻和變焦性能方面取得了令人驚訝的勝利 Aug 24, 2024 pm 12:32 PM

Google Pixel 9 Pro 和 Pro XL 是Google對三星 Galaxy S24 Ultra 和蘋果 iPhone 15 Pro 和 Pro Max 等產品的回應。 YouTube 上的 Daniel Sin(請觀看下文)將 Google Pixel 9 Pro XL 與 iPhone 15 Pro Max 進行了一些比較

在 Vivobook S15 基準測試中,Snapdragon X Elite CPU 的電池效能和插入效能幾乎相同 在 Vivobook S15 基準測試中,Snapdragon X Elite CPU 的電池效能和插入效能幾乎相同 Jun 20, 2024 pm 03:59 PM

儘管圍繞著高通 Snapdragon X Elite 進行了大肆宣傳,但它的發布卻相當平庸。在我們的評論中,我們發現搭載 Qualcomm Snapdragon X Elite X1E-78-100 的華碩 Vivobook S 15 最令人印象深刻的部分是無縫連接

Panasonic Lumix S9 供應短缺,儘管有負面報道,但仍完成富士 X100VI 的冒充行為 Panasonic Lumix S9 供應短缺,儘管有負面報道,但仍完成富士 X100VI 的冒充行為 Jun 14, 2024 am 09:36 AM

自從今年早些時候推出以來,松下 Lumix S9 就一直陷入爭議。

釋放你內心的程式設計師:C 絕對初學者 釋放你內心的程式設計師:C 絕對初學者 Oct 11, 2024 pm 03:50 PM

C語言是初學者學習程式設計的理想選擇,其優點包括效率、多功能性和可移植性。學習C語言需要:安裝C編譯器(如MinGW或Cygwin)了解變數、資料型別、條件語句和迴圈語句編寫包含主函數和printf()函數的第一個程式透過實戰案例(如計算平均數)練習C語言知識

程式設計是乾啥的,學了有什麼用 程式設計是乾啥的,學了有什麼用 Apr 28, 2024 pm 01:34 PM

1、程式設計可用於開發各種軟體和應用程序,包括網站、手機應用程式、遊戲和數據分析工具等。它的應用領域非常廣泛,幾乎涵蓋了所有行業,包括科學研究、醫療保健、金融、教育、娛樂等。 2.學習程式設計可以幫助我們提升問題解決能力和邏輯思考能力。在程式設計過程中,我們需要分析和理解問題,找出解決方案,並將其轉換為程式碼。這種思維方式能夠培養我們的分析和抽象能力,提升我們解決實際問題的能力。

使用 Python 解決問題:作為初學者,解鎖強大的解決方案 使用 Python 解決問題:作為初學者,解鎖強大的解決方案 Oct 11, 2024 pm 08:58 PM

Python 讓初學者能夠解決問題。

See all articles