Android裝置驅動之——V4L2
阿新 • • 發佈:2019-01-24
Video for Linux Two
V4L2的是V4L的第二個版本。原來的V4L被引入到Linux核心2.1.x的開發週期後期。Video4Linux2修正了一些設計缺陷,並開始出現在2.5.X核心。Video4Linux2驅動程式包括Video4Linux1應用的相容模式,但實際上,支援是不完整的,並建議V4L2的裝置使用V4L2的模式。現在,該專案的DVB-Wiki託管在LinuxTV的網站上。
要想了解 V4l2 有幾個重要的文件是必須要讀的,Documentation/video4linux目錄下的和videobuf、V4L2的官方API文件、drivers/media/video目錄下的vivi.c(虛擬視訊驅動程式 -此程式碼模擬一個真正的視訊裝置V4L2 API)。
V4l2可以支援多種裝置,它可以有以下幾種介面:
1. 視訊採集介面(video capture interface):這種應用的裝置可以是高頻頭或者攝像頭.V4L2的最初設計就是應用於這種功能的.
2. 視訊輸出介面(video output interface):可以驅動計算機的外圍視訊影象裝置--像可以輸出電視訊號格式的裝置.
3. 直接傳輸視訊介面(video overlay interface):它的主要工作是把從視訊採集裝置採集過來的訊號直接輸出到輸出裝置之上,而不用經過系統的CPU.
4. 視訊間隔消隱訊號介面(VBI interface):它可以使應用可以訪問傳輸消隱期的視訊訊號.
5. 收音機介面(radio interface):可用來處理從AM或FM高頻頭裝置接收來的音訊流.
V4L2 驅動核心
V4L2 的驅動原始碼在 drivers/media/video目錄下,主要核心程式碼有:
v4l2-dev.c //linux版本2視訊捕捉介面,主要結構體 video_device 的註冊
v4l2-common.c //在Linux作業系統體系採用低級別的操作一套裝置structures/vectors的通用視訊裝置介面。
//此檔案將替換videodev.c的檔案配備常規的核心分配。
v4l2-device.c //V4L2的裝置支援。註冊v4l2_device
v4l22-ioctl.c //處理V4L2的ioctl命令的一個通用的框架。
v4l2-subdev.c //v4l2子裝置
v4l2-mem2mem.c //記憶體到記憶體為Linux和videobuf視訊裝置的框架。裝置的輔助函式,使用其源和目的地videobuf緩衝區。
標頭檔案linux/videodev2.h、media/v4l2-common.h、media/v4l2-device.h、media/v4l2-ioctl.h、media/v4l2-dev.h、media/v4l2-ioctl.h等。
V4l2相關結構體
1.V4l2_device
struct V4l2_device{
/* DEV-> driver_data指向這個結構。 注:DEV可能是空的,如果沒有父裝置是如同ISA裝置。 */
struct device *dev;
/* 用於跟蹤註冊的subdevs */
struct list_head subdevs;
/*鎖定此結構體;可以使用的驅動程式以及如果這個結構嵌入到一個更大的結構。 */
spinlock_t lock;
/* 獨特的裝置名稱,預設情況下,驅動程式姓名+匯流排ID */
char name[V4L2_DEVICE_NAME_SIZE];
/*報告由一些子裝置呼叫的回撥函式。 */
void (*notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
};
v4l2_device註冊和登出
v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
第一個引數‘dev’通常是一個pci_dev的struct device的指標,但它是ISA裝置或一個裝置建立多個PCI裝置時這是罕見的DEV為NULL,因此makingit不可能聯想到一個特定的父母v4l2_dev。 您也可以提供一個notify()回撥子裝置,可以通過呼叫通知你的事件。取決於你是否需要設定子裝置。一個子裝置支援的任何通知必須在標頭檔案中定義 .
註冊時將初始化 v4l2_device 結構體. 如果 dev->driver_data欄位是空, 它將連線到 v4l2_dev.
v4l2_device_unregister(struct v4l2_device *v4l2_dev);
登出也將自動登出裝置所有子裝置。
2.video_device
在/dev目錄下的裝置節點使用的 struct video_device(v4l2_dev.h)建立。
struct video_device
{
/*裝置操作函式 */
const struct v4l2_file_operations *fops;
/* 虛擬檔案系統 */
struct device dev; /* v4l 裝置 */
struct cdev *cdev; /* 字元裝置 */
struct device *parent; /*父裝置 */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */
/* 裝置資訊 */
char name[32];
int vfl_type;
/* 'minor' is set to -1 if the registration failed */
int minor;
u16 num;
/* use bitops to set/clear/test flags */
unsigned long flags;
/*屬性來區分一個物理裝置上的多個索引 */
int index;
/* V4L2 檔案控制代碼 */
spinlock_t fh_lock; /*鎖定所有的 v4l2_fhs */
struct list_head fh_list; /* List of struct v4l2_fh */
int debug; /* Activates debug level*/
/* Video standard vars */
v4l2_std_id tvnorms; /* Supported tv norms */
v4l2_std_id current_norm; /* Current tvnorm */
/* 釋放的回撥函式 */
void (*release)(struct video_device *vdev);
/* 控制的回撥函式 */
const struct v4l2_ioctl_ops *ioctl_ops;
}
動態分配:
struct video_device *vdev = video_device_alloc();
結構體配置:
fops:設定這個v4l2_file_operations結構,file_operations的一個子集。v4l2_dev: 設定這個v4l2_device父裝置
name:
ioctl_ops:使用v4l2_ioctl_ops簡化的IOCTL,然後設定v4l2_ioctl_ops結構。
lock:如果你想要做的全部驅動程式鎖定就保留為NULL。否則你給它一個指標指向一個mutex_lock結構體和任何v4l2_file_operations被呼叫之前核心應該釋放釋放鎖。
parent:一個硬體裝置有多個PCI裝置,都共享相同v4l2_device核心時,設定註冊使用NULL v4l2_device作為父裝置結構。
flags:可選的。設定到V4L2_FL_USE_FH_PRIO如你想讓框架處理VIDIOC_G/ S_PRIORITY的ioctl。這就需要您使用結構v4l2_fh。這個標誌最終會消失,一旦所有的驅動程式使用的核心優先處理。但現在它必須明確設定。
如果使用v4l2_ioctl_ops,那麼你應該設定。unlocked_ioctlvideo_ioctl2在v4l2_file_operations結構。
註冊/登出 video_device:
video_register_device(struct video_device *vdev, int type, int nr);
__video_register_device(struct video_device *vdev, int type, int nr,int warn_if_nr_in_use)
引數:
vdev:我們要註冊的視訊裝置結構。
type:裝置型別註冊
nr:裝置號(0==/dev/video0,1== /dev/video1,...-1==釋放第一個)
warn_if_nr_in_use:如果所需的裝置節點號碼已經在使用另一個號碼代替選擇。
註冊程式分配次裝置號和裝置節點的數字根據請求的型別和註冊到核心新裝置節點。如果無法找到空閒次裝置號或裝置節點編號,或者如果裝置節點註冊失敗,就返回一個錯誤。
video_unregister_device(struct video_device *vdev);
3.v4l2_subdev
每個子裝置驅動程式必須有一個v4l2_subdev結構。這個結構可以獨立簡單的裝置或者如果需要儲存更多的狀態資訊它可能被嵌入在一個更大的結構。由於子裝置可以做很多不同的東西,你不想結束一個巨大的OPS結構其中只有少數的OPS通常執行,函式指標進行排序按類別,每個類別都有其自己的OPS結構。頂層OPS結構包含的類別OPS結構,這可能是NULL如果在subdev驅動程式不支援任何從該類別指標。
V4L2的是V4L的第二個版本。原來的V4L被引入到Linux核心2.1.x的開發週期後期。Video4Linux2修正了一些設計缺陷,並開始出現在2.5.X核心。Video4Linux2驅動程式包括Video4Linux1應用的相容模式,但實際上,支援是不完整的,並建議V4L2的裝置使用V4L2的模式。現在,該專案的DVB-Wiki託管在LinuxTV的網站上。
要想了解 V4l2 有幾個重要的文件是必須要讀的,Documentation/video4linux目錄下的和videobuf、V4L2的官方API文件、drivers/media/video目錄下的vivi.c(虛擬視訊驅動程式 -此程式碼模擬一個真正的視訊裝置V4L2 API)。
V4l2可以支援多種裝置,它可以有以下幾種介面:
1. 視訊採集介面(video capture interface):這種應用的裝置可以是高頻頭或者攝像頭.V4L2的最初設計就是應用於這種功能的.
2. 視訊輸出介面(video output interface):可以驅動計算機的外圍視訊影象裝置--像可以輸出電視訊號格式的裝置.
3. 直接傳輸視訊介面(video overlay interface):它的主要工作是把從視訊採集裝置採集過來的訊號直接輸出到輸出裝置之上,而不用經過系統的CPU.
4. 視訊間隔消隱訊號介面(VBI interface):它可以使應用可以訪問傳輸消隱期的視訊訊號.
5. 收音機介面(radio interface):可用來處理從AM或FM高頻頭裝置接收來的音訊流.
V4L2 驅動核心
V4L2 的驅動原始碼在 drivers/media/video目錄下,主要核心程式碼有:
v4l2-dev.c //linux版本2視訊捕捉介面,主要結構體 video_device 的註冊
v4l2-common.c //在Linux作業系統體系採用低級別的操作一套裝置structures/vectors的通用視訊裝置介面。
//此檔案將替換videodev.c的檔案配備常規的核心分配。
v4l2-device.c //V4L2的裝置支援。註冊v4l2_device
v4l22-ioctl.c //處理V4L2的ioctl命令的一個通用的框架。
v4l2-subdev.c //v4l2子裝置
v4l2-mem2mem.c //記憶體到記憶體為Linux和videobuf視訊裝置的框架。裝置的輔助函式,使用其源和目的地videobuf緩衝區。
標頭檔案linux/videodev2.h、media/v4l2-common.h、media/v4l2-device.h、media/v4l2-ioctl.h、media/v4l2-dev.h、media/v4l2-ioctl.h等。
V4l2相關結構體
1.V4l2_device
struct V4l2_device{
/* DEV-> driver_data指向這個結構。 注:DEV可能是空的,如果沒有父裝置是如同ISA裝置。 */
struct device *dev;
/* 用於跟蹤註冊的subdevs */
struct list_head subdevs;
/*鎖定此結構體;可以使用的驅動程式以及如果這個結構嵌入到一個更大的結構。 */
spinlock_t lock;
/* 獨特的裝置名稱,預設情況下,驅動程式姓名+匯流排ID */
char name[V4L2_DEVICE_NAME_SIZE];
/*報告由一些子裝置呼叫的回撥函式。 */
void (*notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
};
v4l2_device註冊和登出
v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
第一個引數‘dev’通常是一個pci_dev的struct device的指標,但它是ISA裝置或一個裝置建立多個PCI裝置時這是罕見的DEV為NULL,因此makingit不可能聯想到一個特定的父母v4l2_dev。 您也可以提供一個notify()回撥子裝置,可以通過呼叫通知你的事件。取決於你是否需要設定子裝置。一個子裝置支援的任何通知必須在標頭檔案中定義 .
註冊時將初始化 v4l2_device 結構體. 如果 dev->driver_data欄位是空, 它將連線到 v4l2_dev.
v4l2_device_unregister(struct v4l2_device *v4l2_dev);
登出也將自動登出裝置所有子裝置。
2.video_device
在/dev目錄下的裝置節點使用的 struct video_device(v4l2_dev.h)建立。
struct video_device
{
/*裝置操作函式 */
const struct v4l2_file_operations *fops;
/* 虛擬檔案系統 */
struct device dev; /* v4l 裝置 */
struct cdev *cdev; /* 字元裝置 */
struct device *parent; /*父裝置 */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */
/* 裝置資訊 */
char name[32];
int vfl_type;
/* 'minor' is set to -1 if the registration failed */
int minor;
u16 num;
/* use bitops to set/clear/test flags */
unsigned long flags;
/*屬性來區分一個物理裝置上的多個索引 */
int index;
/* V4L2 檔案控制代碼 */
spinlock_t fh_lock; /*鎖定所有的 v4l2_fhs */
struct list_head fh_list; /* List of struct v4l2_fh */
int debug; /* Activates debug level*/
/* Video standard vars */
v4l2_std_id tvnorms; /* Supported tv norms */
v4l2_std_id current_norm; /* Current tvnorm */
/* 釋放的回撥函式 */
void (*release)(struct video_device *vdev);
/* 控制的回撥函式 */
const struct v4l2_ioctl_ops *ioctl_ops;
}
動態分配:
struct video_device *vdev = video_device_alloc();
結構體配置:
fops:設定這個v4l2_file_operations結構,file_operations的一個子集。v4l2_dev: 設定這個v4l2_device父裝置
name:
ioctl_ops:使用v4l2_ioctl_ops簡化的IOCTL,然後設定v4l2_ioctl_ops結構。
lock:如果你想要做的全部驅動程式鎖定就保留為NULL。否則你給它一個指標指向一個mutex_lock結構體和任何v4l2_file_operations被呼叫之前核心應該釋放釋放鎖。
parent:一個硬體裝置有多個PCI裝置,都共享相同v4l2_device核心時,設定註冊使用NULL v4l2_device作為父裝置結構。
flags:可選的。設定到V4L2_FL_USE_FH_PRIO如你想讓框架處理VIDIOC_G/ S_PRIORITY的ioctl。這就需要您使用結構v4l2_fh。這個標誌最終會消失,一旦所有的驅動程式使用的核心優先處理。但現在它必須明確設定。
如果使用v4l2_ioctl_ops,那麼你應該設定。unlocked_ioctlvideo_ioctl2在v4l2_file_operations結構。
註冊/登出 video_device:
video_register_device(struct video_device *vdev, int type, int nr);
__video_register_device(struct video_device *vdev, int type, int nr,int warn_if_nr_in_use)
引數:
vdev:我們要註冊的視訊裝置結構。
type:裝置型別註冊
nr:裝置號(0==/dev/video0,1== /dev/video1,...-1==釋放第一個)
warn_if_nr_in_use:如果所需的裝置節點號碼已經在使用另一個號碼代替選擇。
註冊程式分配次裝置號和裝置節點的數字根據請求的型別和註冊到核心新裝置節點。如果無法找到空閒次裝置號或裝置節點編號,或者如果裝置節點註冊失敗,就返回一個錯誤。
video_unregister_device(struct video_device *vdev);
3.v4l2_subdev
每個子裝置驅動程式必須有一個v4l2_subdev結構。這個結構可以獨立簡單的裝置或者如果需要儲存更多的狀態資訊它可能被嵌入在一個更大的結構。由於子裝置可以做很多不同的東西,你不想結束一個巨大的OPS結構其中只有少數的OPS通常執行,函式指標進行排序按類別,每個類別都有其自己的OPS結構。頂層OPS結構包含的類別OPS結構,這可能是NULL如果在subdev驅動程式不支援任何從該類別指標。