日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

UVC (USB Video Class) 使用笔记 (转)

發(fā)布時間:2024/9/27 c/c++ 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UVC (USB Video Class) 使用笔记 (转) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

最近有個需求,要在ARM Linux上實現(xiàn)USB Camera 拍照功能。

0. 背景知識:

首先要確認的是,Kernel 是否支持 USB Camera。因為 Linux 下,USB 協(xié)議除了電氣協(xié)議和標準,還有很多 Class。 這些 Class 就是為了支持和定義某一類設(shè)備接口和交互數(shù)據(jù)格式。只要符合這類標準,則不同廠商的 USB 設(shè)備,不需要特定的 driver 就能在Linux下使用。

例如:USB Input class, 則使所有輸入設(shè)備都可以直接使用。還有類似 Audio Class,Pring Class,Mass Storage Class,Video class 等。

其中 Video Class 就是我們常說的 UVC(USB Video Class). 只要 USB Camera 符合 UVC 標準。理論上在 2.6 Kernel Linux 就可以正常使用。

網(wǎng)絡(luò)上有人談到怎樣判斷是否 UVC Camera 設(shè)備:

#lsusb

Bus 001 Device 010: ID 046d:0825 Logitech, Inc.

#lsusb -d 046d:0825 -v | grep "14 Video"

如果出現(xiàn):

bInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 Video

則說明是支持UVC.

1. Kernel配置:

Device Drivers ---> <*> Multimedia support ---> <M> Video For Linux

Device Drivers ---> <*> Multimedia support ---> [*] Video capture adapters ---> [*] V4L USB devices ---> <M> USB Video Class (UVC)

--- V4L USB devices: 這里還有很多特定廠商的 driver. 可供選擇。

分析:

"USB Video Class (UVC)":對應(yīng)的 driver 是:uvcvideo.ko

"Video For Linux": 對應(yīng) driver 是:videodev.ko

安裝 driver 順序如下:

insmod v4l1_compat.ko insmod videodev.ko insmod uvcvideo.ko

driver 會創(chuàng)建一個或多個主設(shè)備號為81,次設(shè)備號:0-255的設(shè)備。

除了camer a會創(chuàng)建為:/dev/videoX 之外,還有 VBI 設(shè)備 -/dev/vbiX. Radio 設(shè)備 --/dev/radioX.

2. V4L2一些概念:

2.1:Video Input and Output:

video input and output是指 device 物理連接。

只有 video 和 VBI capture 擁有 input.

Radio 設(shè)備則沒有 video input 和 output.

2.2: Video Standards:

Video Device支持一個或多個Video 標準。

3. 使用V4L2編程:

使用V4L2(Video for Linux 2) API的過程大致如下:

Opening the device Changing device properties, selecting a video and audio input, video standard, picture brightness a. o. Negotiating a data format Negotiating an input/output method The actual input/output loop Closing the device

3.1:打開設(shè)備:

fd = open ("/dev/video0", O_RDWR, 0); //以阻塞模式打開設(shè)想頭

3.2: 查詢設(shè)備能力:Querying Capabilities:

因為 V4L2 可以對多種設(shè)備編程,所以并不是所有 API 可以對所有設(shè)備編程,哪怕是同類型的設(shè)備,使用ioctl--VIDIOC_QUERYCAP 去詢問支持什么功能。

struct v4l2_capability cap; rel = ioctl(fdUsbCam, VIDIOC_QUERYCAP, &cap); if(rel != 0) {perror("ioctl VIDIOC_QUERYCAP");return -1; }

結(jié)構(gòu)體如下:

struct v4l2_capability {__u8 driver[16];__u8 card[32];__u8 bus_info[32];__u32 version;__u32 capabilities;__u32 reserved[4]; };

這里面最重要的是:capabilities:

頭文件 linux/videodev2.h 和 kernel 頭文件 linux/videodev2.h 中都有描述:

#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 #define V4L2_CAP_VIDEO_OUTPUT 0x00000002 #define V4L2_CAP_VIDEO_OVERLAY 0x00000004 #define V4L2_CAP_VBI_CAPTURE 0x00000010 #define V4L2_CAP_VBI_OUTPUT 0x00000020 #define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 #define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 #define V4L2_CAP_RDS_CAPTURE 0x00000100 #define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 #define V4L2_CAP_HW_FREQ_SEEK 0x00000400 #define V4L2_CAP_RDS_OUTPUT 0x00000800 #define V4L2_CAP_TUNER 0x00010000 #define V4L2_CAP_AUDIO 0x00020000 #define V4L2_CAP_RADIO 0x00040000 #define V4L2_CAP_MODULATOR 0x00080000 #define V4L2_CAP_READWRITE 0x01000000 #define V4L2_CAP_ASYNCIO 0x02000000 #define V4L2_CAP_STREAMING 0x04000000

這里要說到 VBI,Vertical Blanking Interval 的縮寫。 電視信號包括一部分非可視信號,它不傳送可視信息,因此被稱為ⅦI(垂直消隱期間)。VBI 可以用于傳送其他信息,通常是一種專用字幕信號, 這和 Blog 重顯率中所說暗合。

在這里,V4L2_CAP_VIDEO_CAPTURE 說明設(shè)備是個圖像采集設(shè)備,V4L2_CAP_STREAMING 說明是個 Streaming 設(shè)備。 通常,攝像頭都支持以上兩個能力。

3.3:查詢當前捕獲格式:

memset(&fmt, 0, sizeof(struct v4l2_format)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (ioctl(fdUsbCam, VIDIOC_G_FMT, &fmt) < 0) {printf("get format failed\n");return -1; }

注意,此處,fmt 是個 in/out 參數(shù)。

參見 Kernel 代碼 v4l2_ioctl.c 中。此 ioctl,它會首先判斷 fmt.type.

type 類型和含義如下:

V4L2_BUF_TYPE_VIDEO_CAPTURE :vid-cap V4L2_BUF_TYPE_VIDEO_OVERLAY :vid-overlay V4L2_BUF_TYPE_VIDEO_OUTPUT : vid-out V4L2_BUF_TYPE_VBI_CAPTURE : vbi-cap V4L2_BUF_TYPE_VBI_OUTPUT : vbi-out V4L2_BUF_TYPE_SLICED_VBI_CAPTURE : sliced-vbi-cap V4L2_BUF_TYPE_SLICED_VBI_OUTPUT : sliced-vbi-out V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY : vid-out-overlay

咱們是使用 Video Cam 的。所以用 V4L2_BUF_TYPE_VIDEO_CAPTURE

struct v4l2_format {enum v4l2_buf_type type;union{struct v4l2_pix_format pix;struct v4l2_window win;struct v4l2_vbi_format vbi;struct v4l2_sliced_vbi_format sliced;__u8 raw_data[200];} fmt; };

我們得到的信息在 v4l2_pix_format 中。

你可以看到,寬,高,像素格式。

其中像素格式包括:

#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') #define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') #define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') #define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') #define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') #define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') #define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') #define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') #define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') #define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1') #define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2') #define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5')

請注意,此時取到的寬,高,像素格式均正確。但不知為何,bytesperline 卻為 0。

3.4:設(shè)置當前捕獲格式

fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; rel = ioctl(fdUsbCam, VIDIOC_S_FMT, &fmt); if (rel < 0) {printf("\nSet format failed\n");return -1; }

此時,再取當前捕獲格式,則一切正常。包括 bytesperline

3.5:讀取 Stream 設(shè)置。

struct v4l2_streamparm *setfps; setfps = (struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm)); memset(setfps, 0, sizeof(struct v4l2_streamparm)); setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; rel = ioctl(fdUsbCam, VIDIOC_G_PARM, setfps); if(rel == 0) {printf("\n Frame rate: %u/%u\n",setfps->parm.capture.timeperframe.denominator,setfps->parm.capture.timeperframe.numerator); } else {perror("Unable to read out current frame rate");return -1; }

注意: ioctl(fdUsbCam, VIDIOC_G_PARM, setfps); 參數(shù) 3 也是 i/o 參數(shù)。必須要首先其 type.

struct v4l2_streamparm {enum v4l2_buf_type type;union{struct v4l2_captureparm capture;struct v4l2_outputparm output;__u8 raw_data[200];} parm; };

type 字段描述的是在涉及的操作的類型。對于視頻捕獲設(shè)備,應(yīng)該為 V4L2_BUF_TYPE_VIDEO_CAPTURE。對于輸出設(shè)備應(yīng)該為V4L2_BUF_TYPE_VIDEO_OUTPUT。它的值也可以是 V4L2_BUF_TYPE_PRIVATE,在這種情況下,raw_data字段用來傳遞一些私有的,不可移植的,甚至是不鼓勵的數(shù)據(jù)給內(nèi)核 。

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_PRIVATE = 0x80, };

咱們當然選用V4L2_BUF_TYPE_VIDEO_CAPTURE

對于捕獲設(shè)備而言,parm.capture 字段是要關(guān)注的內(nèi)容,這個結(jié)構(gòu)體如下:

struct v4l2_captureparm {__u32 capability;__u32 capturemode;struct v4l2_fract timeperframe;__u32 extendedmode;__u32 readbuffers;__u32 reserved[4]; };

timeperframe 字段用于指定想要使用的幀頻率,它又是一個結(jié)構(gòu)體:

struct v4l2_fract {__u32 numerator;__u32 denominator; };

numerator 和 denominator 所描述的系數(shù)給出的是成功的幀之間的時間間隔。

numerator 分子, denominator 分母。主要表達每次幀之間時間間隔。 numerator/denominator 秒一幀。

3.6:設(shè)置 Stream 參數(shù)。(主要是采集幀數(shù))

setfps->parm.capture.timeperframe.numerator = 1; setfps->parm.capture.timeperframe.denominator = 60; rel = ioctl(fdUsbCam, VIDIOC_S_PARM, setfps); if (rel != 0) {printf("\nUnable to Set FPS");return -1; }

當然,setfps 的其它項目,都是之前使用 VIDIOC_G_PARM 取得的。

3.7:創(chuàng)建一組緩沖區(qū)(buf)

struct v4l2_requestbuffers rb; memset(&rb, 0, sizeof(struct v4l2_requestbuffers)); rb.count = 3; rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; rb.memory = V4L2_MEMORY_MMAP; rel = ioctl(fdUsbCam, VIDIOC_REQBUFS, &rb); if (rel < 0) {printf("Unable to allocate buffers: %d.\n", errno);return -1; }

其中參數(shù) rb 為:struct v4l2_requestbuffers:

struct v4l2_requestbuffers {__u32 count;enum v4l2_buf_type type;enum v4l2_memory memory;__u32 reserved[2]; };

type 字段描述的是完成的 I/O 操作的類型。通常它的值要么是視頻獲得設(shè)備的 V4L2_BUF_TYPE_VIDEO_CAPTURE,要么是輸出設(shè)備的 V4L2_BUF_TYPE_VIDEO_OUTPUT

struct v4l2_memory: enum v4l2_memory {V4L2_MEMORY_MMAP = 1,V4L2_MEMORY_USERPTR = 2,V4L2_MEMORY_OVERLAY = 3, };

想要使用內(nèi)存映謝的緩沖區(qū),它將會把 memory 字段置為 V4L2_MEMORY_MMAP,count 置為它想要使用的緩沖區(qū)的數(shù)目。

順便看看 USB TO Serail:

Device Drivers --->[*] USB support ---> USB Serial Converter support ---> USB Prolific 2303 Single Port Serial Driver

USB Prolific 2303 Single Port Serial Driver 是指出支持 pl2303 芯片的 USB 2 serial.

pl2303.ko

USB Serial Converter support 是基礎(chǔ) driver. 對應(yīng) usbserial.ko

注1:ioctl 中常用的 cmd.

VIDIOC_REQBUFS:分配內(nèi)存 VIDIOC_QUERYBUF:把 VIDIOC_REQBUFS 中分配的數(shù)據(jù)緩存轉(zhuǎn)換成物理地址 VIDIOC_QUERYCAP:查詢驅(qū)動功能 VIDIOC_ENUM_FMT:獲取當前驅(qū)動支持的視頻格式 VIDIOC_S_FMT:設(shè)置當前驅(qū)動的頻捕獲格式 VIDIOC_G_FMT:讀取當前驅(qū)動的頻捕獲格式 VIDIOC_TRY_FMT:驗證當前驅(qū)動的顯示格式 VIDIOC_CROPCAP:查詢驅(qū)動的修剪能力 VIDIOC_S_CROP:設(shè)置視頻信號的邊框 VIDIOC_G_CROP:讀取視頻信號的邊框 VIDIOC_QBUF:把數(shù)據(jù)從緩存中讀取出來 VIDIOC_DQBUF:把數(shù)據(jù)放回緩存隊列 VIDIOC_STREAMON:開始視頻顯示函數(shù) VIDIOC_STREAMOFF:結(jié)束視頻顯示函數(shù) VIDIOC_QUERYSTD:檢查當前視頻設(shè)備支持的標準,例如 PAL 或 NTSC。 VIDIOC_G_PARM:得到 Stream 信息。如幀數(shù)等。 VIDIOC_S_PARM: 設(shè)置 Stream 信息。如幀數(shù)等。

注2:

如何判斷某 ioctl cmd 所用參數(shù)類型:

例如:

ioctl-cmd: VIDIOC_QUERYCAP.

它的返回參數(shù)類型 ioctl(fd, cmd, 參數(shù))。

首先想到的是從 kernel Source v4l2_ioctl.c 中看。但這比較麻煩,又個簡單辦法:可以在 video2dev.h 中看到:

#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability)

即使用 cmd 為 VIDIOC_QUERYCAP 時,參數(shù)為 struct v4l2_capability

總結(jié)

以上是生活随笔為你收集整理的UVC (USB Video Class) 使用笔记 (转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。