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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一文带你了解V4L2

發布時間:2023/12/20 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文带你了解V4L2 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、什么是v4l2

V4L2(Video4Linux的縮寫)是Linux下關于視頻采集相關設備的驅動框架,為驅動和應用程序提供了一套統一的接口規范。

V4L2支持的設備十分廣泛,但是其中只有很少一部分在本質上是真正的視頻設備:

?Video capture device :從攝像頭等設備上獲取視頻數據。對很多人來講,video capture是V4L2的基本應用。設備名稱為/dev/video,主設備號81,子設備號0~63?Video output device :將視頻數據編碼為模擬信號輸出。與video capture設備名相同。?Video overlay device :將同步鎖相視頻數據(如TV)轉換為VGA信號,或者將抓取的視頻數據直接存放到視頻卡的顯存中。?Video output overlay device :也被稱為OSD(On-Screen Display)?VBI device :提供對VBI(Vertical Blanking Interval)數據的控制,發送VBI數據或抓取VBI數據。設備名/dev/vbi0~vbi31,主設備號81,子設備號224~255?Radio device :FM/AM發送和接收設備。設備名 /dev/radio0~radio63,主設備號81,子設備號64~127

V4L2在Linux系統中的結構圖如下:

2、從應用層看V4L2

從V4L2簡單框圖可以看出,V4L2是一個字符設備,而V4L2的大部分功能都是通過設備文件的ioctl導出的。

可以將這些ioctl分類如下:

?Query Capability:查詢設備支持的功能,只有VIDIOC_QUERY_CAP一個。?優先級相關:包括VIDIOC_G_PRIORITY,VIDIOC_S_PRIORITY,設置優先級。?capture相關:視頻捕獲相關Ioctl。

capture ioctl list?ID 描述

VIDIOC_ENUM_FMT 枚舉設備所支持的所有數據格式 VIDIOC_S_FMT 設置數據格式 VIDIOC_G_FMT 獲取數據格式 VIDIOC_TRY_FMT 與VIDIOC_S_FMT一樣,但不會改變設備的狀態 VIDIOC_REQBUFS 向設備請求視頻緩沖區,即初始化視頻緩沖區 VIDIOC_QUERYBUF 查詢緩沖區的狀態 VIDIOC_QBUF 從設備獲取一幀視頻數據 VIDIOC_DQBUF 將視頻緩沖區歸回給設備, VIDIOC_OVERLAY 開始或者停止overlay VIDIOC_G_FBUF 獲取video overlay設備或OSD設備的framebuffer參數 VIDIOC_S_FBUF 設置framebuffer參數 VIDIOC_STREAMON 開始流I/O操作,capture or output device VIDIOC_STREAMOFF 關閉流I/O操作

?TV視頻標準:

TV Standard?ID 描述?VIDIOC_ENUMSTD 枚舉設備支持的所有標準 VIDIOC_G_STD 獲取當前正在使用的標準 VIDIOC_S_STD 設置視頻標準 VIDIOC_QUERYSTD 有的設備支持自動偵測輸入源的視頻標準,此時使用此ioctl查詢偵測到的視頻標準

?input/output:

Input / Output ID 描述

VIDIOC_ENUMINPUT 枚舉所有input端口 VIDIOC_G_INPUT 獲取當前正在使用的input端口 VIDIOC_S_INPUT 設置將要使用的input端口 VIDIOC_ENUMOUTPUT 枚舉所有output端口 VIDIOC_G_OUTPUT 獲取當前正在使用的output端口 VIDIOC_S_OUTPUT 設置將要使用的output端口 VIDIOC_ENUMAUDIO 枚舉所有audio input端口 VIDIOC_G_AUDIO 獲取當前正在使用的audio input端口 VIDIOC_S_AUDIO 設置將要使用的audio input端口 VIDIOC_ENUMAUDOUT 枚舉所有audio output端口 VIDIOC_G_AUDOUT 獲取當前正在使用的audio output端口 VIDIOC_S_AUDOUT 設置將要使用的audio output端口

?controls:設備特定的控制,例如設置對比度,亮度?controls ID 描述*

VIDIOC_QUERYCTRL 查詢指定control的詳細信息 VIDIOC_G_CTRL 獲取指定control的值 VIDIOC_S_CTRL 設置指定control的值 VIDIOC_G_EXT_CTRLS 獲取多個control的值 VIDIOC_S_EXT_CTRLS 設置多個control的值 VIDIOC_TRY_EXT_CTRLS 與VIDIOC_S_EXT_CTRLS相同,但是不改變設備狀態 VIDIOC_QUERYMENU 查詢menu

?其他雜項:?controls ID 描述*

VIDIOC_G_MODULATOR VIDIOC_S_MODULATOR VIDIOC_G_CROP VIDIOC_S_CROP VIDIOC_G_SELECTION VIDIOC_S_SELECTION VIDIOC_CROPCAP VIDIOC_G_ENC_INDEX VIDIOC_ENCODER_CMD VIDIOC_TRY_ENCODER_CMD VIDIOC_DECODER_CMD VIDIOC_TRY_DECODER_CMD VIDIOC_G_PARM VIDIOC_S_PARM VIDIOC_G_TUNER VIDIOC_S_TUNER VIDIOC_G_FREQUENCY VIDIOC_S_FREQUENCY VIDIOC_G_SLICED_VBI_CAP VIDIOC_LOG_STATUS VIDIOC_DBG_G_CHIP_IDENT VIDIOC_S_HW_FREQ_SEEK VIDIOC_ENUM_FRAMESIZES VIDIOC_ENUM_FRAMEINTERVALS VIDIOC_ENUM_DV_PRESETS VIDIOC_S_DV_PRESET VIDIOC_G_DV_PRESET VIDIOC_QUERY_DV_PRESET VIDIOC_S_DV_TIMINGS VIDIOC_G_DV_TIMINGS VIDIOC_DQEVENT VIDIOC_SUBSCRIBE_EVENT VIDIOC_UNSUBSCRIBE_EVENT VIDIOC_CREATE_BUFS VIDIOC_PREPARE_BUF

v4l2設備的基本操作流程如下

1、打開設備,例如 fd = open("/dev/video0",0)

2、查詢設備能力. 例如:

struct capability cap; ioctl(fd,VIDIOC_QUERYCAP,&cap) 3、設置優先級(可選)

4、配置設備。

包括:

?視頻輸入源的視頻標準,VIDIOC_*_STD?視頻數據的格式 , VIDIOC_*_FMT?視頻輸入端口, VIDIOC_*_INPUT?視頻輸出端口,VIDIOC_*_OUTPUT

5、啟動設備開始I/O操作。V4L2支持一下三種I/O方式:

?Read/Write:通過調用設備節點文件的Read/Write函數,與設備交互數據。打開設備后,默認使用的是此方法。?Stream I/O:流操作,只傳遞數據緩沖區指針,不拷貝數據。使用此方法,需要調用VIDIOC_REQBUFS ioctl來通知設備。流操作I/O有兩種方式memory map和user buffer。(具體區別后面章節介紹)?overlay :也可以理解為memory to memory 傳輸。將數據從內存拷貝到顯存中。overlay設備獨有的。

對于Capture device可以以如下方式啟動設備:

?調用VIDIOC_REQBUFS ioctl來分配緩沖區隊列;?調用VIDIOC_STREAMON ioctl通知設備開始stream IO?調用VIDIOC_QBUF ioctl從設備獲取一幀視頻數據;?使用完數據后,調用VIDIOC_DQBUF將緩沖區還給設備,以便設備填充下一幀數據。

6、釋放資源并關閉設備。

1.3、從驅動層看V4L2

在驅動層,V4L2為驅動編寫者做了很多工作。只需要實現硬件相關的代碼,并且注冊相關設備即可。

硬件相關代碼的編寫,除了編寫具體硬件的控制代碼外,最主要的就是將代碼與V4L2框架綁定。綁定主要分為以下兩個部分:

?關系綁定:也就是要將我們自己的結構體,與V4L2框架中相關連的結構體綁定在一起。?iocontrol等函數綁定:將V4L2所定義的空的函數指針,與自己的函數綁定在一起。

3.1 關系綁定

提到關系綁定,就必須介紹下V4L2幾個重要結構體。

?struct video_device:主要的任務就是負責向內核注冊字符設備?struct v4l2_device:一個硬件設備可能包含多個子設備,比如一個電視卡除了有capture設備,可能還有VBI設備或者FM tunner。而v4l2_device就是所有這些設備的根節點,負責管理所有的子設備。?struct v4l2_subdev:子設備,負責實現具體的功能。

v4l2_device,v4l2_subdev可以看作所有設備和子設備的基類。我們在編寫自己的驅動時,往往需要繼承這些設備基類,添加一些自己的數據成員。例如第三章要講到的soc_camera_host結構體,就是繼承v4l2_device,并添加了互斥鎖、子設備列表等成員變量。

綁定的基本流程

根據需要”重載”v4l2_device或v4l2_subdev結構體,添加需要的結構體成員。例如 :

?linux/include/media/soc_camera.h文件中soc_camera_host重載了v4l2_device:

struct soc_camera_host { struct v4l2_device v4l2_dev; struct list_head list; struct mutex host_lock; /* Protect during probing */ unsigned char nr; /* Host number */ void *priv; const char *drv_name; struct soc_camera_host_ops *ops; };

?linux/drivers/media/video/Ml86v7667.c中ml86v7667_priv結構體”重載”了v4l2_subdev:

struct ml86v7667_priv {struct v4l2_subdev sd;struct v4l2_ctrl_handler hdl;v4l2_std_id std; }; v4l2_device與V4L2框架的綁定:通過調用v4l2_device_register函數實現。例如,上面提到的soc_camera_host的綁定:int soc_camera_host_register(struct soc_camera_host *ici) {struct soc_camera_host *ix;int ret;if (!ici || !ici->ops ||!ici->ops->try_fmt ||!ici->ops->set_fmt ||!ici->ops->set_bus_param ||!ici->ops->querycap ||((!ici->ops->init_videobuf ||!ici->ops->reqbufs) &&!ici->ops->init_videobuf2) ||!ici->ops->add ||!ici->ops->remove ||!ici->ops->poll ||!ici->v4l2_dev.dev)return -EINVAL;if (!ici->ops->set_crop)ici->ops->set_crop = default_s_crop;if (!ici->ops->get_crop)ici->ops->get_crop = default_g_crop;if (!ici->ops->cropcap)ici->ops->cropcap = default_cropcap;if (!ici->ops->set_parm)ici->ops->set_parm = default_s_parm;if (!ici->ops->get_parm)ici->ops->get_parm = default_g_parm;if (!ici->ops->enum_fsizes)ici->ops->enum_fsizes = default_enum_fsizes;mutex_lock(&list_lock);list_for_each_entry(ix, &hosts, list) {if (ix->nr == ici->nr) {ret = -EBUSY;goto edevreg;}}ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);if (ret < 0)goto edevreg;list_add_tail(&ici->list, &hosts);mutex_unlock(&list_lock);mutex_init(&ici->host_lock);scan_add_host(ici);return 0;edevreg:mutex_unlock(&list_lock);return ret;}

v4l2_subdev與v4l2_device的綁定:通過v4l2_device_register_subdev函數,將subdev注冊到根節點上。例如:

static int soc_camera_platform_probe(struct platform_device *pdev) {struct soc_camera_host *ici;struct soc_camera_platform_priv *priv;struct soc_camera_platform_info *p = pdev->dev.platform_data;struct soc_camera_device *icd;int ret;if (!p)return -EINVAL;if (!p->icd) {dev_err(&pdev->dev,"Platform has not set soc_camera_device pointer!\n");return -EINVAL;}priv = kzalloc(sizeof(*priv), GFP_KERNEL);if (!priv)return -ENOMEM;icd = p->icd;/* soc-camera convention: control's drvdata points to the subdev */platform_set_drvdata(pdev, &priv->subdev);/* Set the control device reference */icd->control = &pdev->dev;ici = to_soc_camera_host(icd->parent);v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);v4l2_set_subdevdata(&priv->subdev, p);strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);if (ret)goto evdrs;return ret;evdrs:platform_set_drvdata(pdev, NULL);kfree(priv);return ret; }

video_device與v4l2_device的綁定:將v4l2_device的地址賦值給video_device的v4l2_dev即可。

3.2 函數綁定

在v4l2 framework 簡略版圖中,綠色的方框都是需要我們綁定并實現的。

其中v4l2_file_operations和v4l2_ioctl_ops是必須實現的。而v4l2_subdev_ops下的八類ops中,v4l2_subdev_core_ops是必須實現的,其余需要根據設備類型選擇實現的。比如video capture類設備需要實現v4l2_subdev_core_ops, v4l2_subdev_video_ops。

?v4l2_file_operations:實現文件類操作,比如open,close,read,write,mmap等。但是ioctl是不需要實現的,一般都是用video_ioctl2代替。例如linux/drivers/media/video/soc_camera.c文件中soc_camera_fops的實現:

static struct v4l2_file_operations soc_camera_fops = {.owner = THIS_MODULE,.open = soc_camera_open,.release = soc_camera_close,.unlocked_ioctl = video_ioctl2,.read = soc_camera_read,.mmap = soc_camera_mmap,.poll = soc_camera_poll, };

?v4l2_ioctl_ops:V4L2導出給應用層使用的所有ioctl都是在這個地方實現的。但不必全部實現,只實現自己相關的ioctl即可。例如linux/drivers/media/video/soc_camera.c中soc_camera_ioctl_ops的實現:

static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {.vidioc_querycap = soc_camera_querycap,.vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,.vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,.vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,.vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,.vidioc_enum_input = soc_camera_enum_input,.vidioc_g_input = soc_camera_g_input,.vidioc_s_input = soc_camera_s_input,.vidioc_s_std = soc_camera_s_std,.vidioc_g_std = soc_camera_g_std,.vidioc_enum_framesizes = soc_camera_enum_fsizes,.vidioc_reqbufs = soc_camera_reqbufs,.vidioc_querybuf = soc_camera_querybuf,.vidioc_qbuf = soc_camera_qbuf,.vidioc_dqbuf = soc_camera_dqbuf,.vidioc_create_bufs = soc_camera_create_bufs,.vidioc_prepare_buf = soc_camera_prepare_buf,.vidioc_streamon = soc_camera_streamon,.vidioc_streamoff = soc_camera_streamoff,.vidioc_cropcap = soc_camera_cropcap,.vidioc_g_crop = soc_camera_g_crop,.vidioc_s_crop = soc_camera_s_crop,.vidioc_g_parm = soc_camera_g_parm,.vidioc_s_parm = soc_camera_s_parm,.vidioc_g_chip_ident = soc_camera_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG.vidioc_g_register = soc_camera_g_register,.vidioc_s_register = soc_camera_s_register, #endif };

?v4l2_subdev_ops:v4l2_subdev有可能需要實現的ops的總合。分為8類,core,audio,video,vbi,tuner......等。例如, linuxdriversmediavideosoc_camera_platform.c中platform_subdev_ops的實現

static struct v4l2_subdev_video_ops platform_subdev_video_ops = {.s_stream = soc_camera_platform_s_stream,.enum_mbus_fmt = soc_camera_platform_enum_fmt,.cropcap = soc_camera_platform_cropcap,.g_crop = soc_camera_platform_g_crop,.try_mbus_fmt = soc_camera_platform_fill_fmt,.g_mbus_fmt = soc_camera_platform_fill_fmt,.s_mbus_fmt = soc_camera_platform_fill_fmt,.g_mbus_config = soc_camera_platform_g_mbus_config, };static struct v4l2_subdev_ops platform_subdev_ops = {.core = &platform_subdev_core_ops,.video = &platform_subdev_video_ops, };

函數綁定只是將驅動所實現的函數賦值給相關的變量即可。


掃碼或長按關注

回復「?加群?」進入技術群聊

總結

以上是生活随笔為你收集整理的一文带你了解V4L2的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。