V4L2フレームワーク分析

       V4L2はVideo for linux2の略で、Linuxのビデオ機器のカーネルドライバーです。v4L2は、uvc(USBビデオクラス)ドライブフリーUSBデバイス用のプログラミングフレームワークで、主にUSBカメラなどの収集に使用されます。

      次の図はV4L2のフレームワークです。最初に、システムコアレイヤーの割り当て設定は、cdev構造(cdev構造はvideo_device構造の一部です)という名前の変数を登録し、cdev-> ops = v4l2_fopsを設定しますハードウェアレイヤーで、設定登録を割り当てますvfd構造(video_device構造)という名前の変数、およびset vfd-> fops =&vivi_fops、vfd-> ioctl_ops =&vivi_ioctl_ops;アプリケーション(APP)が読み取りやオープンなどの関数を呼び出すと、v4l2_fopsで呼び出されます読み取り関数とオープン関数、およびv4l2_fopsの読み取り関数とオープン関数は、ハードウェアレイヤーに関連するvfd-> fopsの読み取り関数とオープン関数を呼び出します。ioctl関数も同様です。

        V4L2フレームワークを分析するプログラムから始めましょう。この記事ではLinuxカーネルディレクトリのdrivers \ medio \ videoにある仮想ビデオドライバーvivi.c使用して(このコードは、v4l2 apiを使用して実際のビデオデバイスをシミュレートします)、V4L2フレームワークを分析します。 。その全体的なフレームワークは次のとおりです。

vivi_init
    vivi_create_instance
        v4l2_device_register   // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数
        video_device_alloc
        // 设置
          1. vfd:
            .fops           = &vivi_fops,
            .ioctl_ops 	= &vivi_ioctl_ops,
            .release	= video_device_release,
          2.
            vfd->v4l2_dev = &dev->v4l2_dev;
          3. 设置"ctrl属性"(用于APP的ioctl):
            	v4l2_ctrl_handler_init(hdl, 11);
            	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
            			V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
            	dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
            			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
            	dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
            			V4L2_CID_CONTRAST, 0, 255, 1, 16);                        
        video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)
            __video_register_device
                vdev->cdev = cdev_alloc();
                vdev->cdev->ops = &v4l2_fops;
                cdev_add
                
                video_device[vdev->minor] = vdev;

        		if (vdev->ctrl_handler == NULL)
        			vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;

①vivi.cのvivi_init関数から開始したところ、v4l2_device_registerが呼び出され、スピンロックや参照カウントなど、初期化に必要ないものを使用していることがわかりました。②video_device_allocを呼び出して、video_device構造体を割り当て、たとえば、適切な設定を行います

.fops =&vivi_fops、
.ioctl_ops =&vivi_ioctl_ops、
.release = video_device_release、

設定を待ってから、構造体をvideo_register_deviceに登録します。

③video_register_device関数は__video_register_deviceを呼び出して次の操作を実行します。

vdev-> cdev = cdev_alloc();
vdev-> cdev-> ops =&v4l2_fops;
cdev_add
                
video_device [vdev-> minor] = vdev;

if(vdev-> ctrl_handler == NULL)
    vdev-> ctrl_handler = vdev-> v4l2_dev-> ctrl_handler;

 

 

上の画像はvivi_create_instance関数の一部です。最初にvideo_device構造の変数vfdを割り当て、次に* vfd = vivi_templateを設定します。ここで、vivi_templateはvideo_deviceの構造変数であり、それ自体が.fopsなどの情報を設定します(以下を参照) )、この操作は設定と同等です

 1. vfd:

.fops =&vivi_fops、
.ioctl_ops =&vivi_ioctl_ops、
.release = video_device_release、

static struct video_device vivi_template = {
	.name		= "vivi",
	.fops           = &vivi_fops,
	.ioctl_ops 	= &vivi_ioctl_ops,
	.release	= video_device_release,

	.tvnorms              = V4L2_STD_525_60,
	.current_norm         = V4L2_STD_NTSC_M,
};

次に、video_register_device関数を入力します。以下は、video_register_deviceのソースコードの一部です。最初にcdev構造体を割り当てます

次に、cdev-> ops =&v4l2_fops;を設定します。v4l2_fops自体がいくつかの関数を指します(下図を参照)。cdevもこれらの関数を指します。APPが読み取り関数を呼び出すと、cdevの読み取り関数が呼び出されます。

static const struct file_operations v4l2_fops = {
	.owner = THIS_MODULE,
	.read = v4l2_read,
	.write = v4l2_write,
	.open = v4l2_open,
	.get_unmapped_area = v4l2_get_unmapped_area,
	.mmap = v4l2_mmap,
	.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = v4l2_compat_ioctl32,
#endif
	.release = v4l2_release,
	.poll = v4l2_poll,
	.llseek = no_llseek,
};

cdevのread関数を下図に示しますが、まずfilpに従ってvideo_device構造体を取得し、次にvideo_device構造体のread関数を判定し、存在する場合はそれを呼び出します。関数を読み取ります。

 

 

 

 

open関数やread関数と比較して、ioctlの呼び出しプロセスはより複雑なので、以下を見てみましょう(例としてVIDIOC_QUERYCAPを取り上げます)。次の図は、v4l2_fopsの.unlocked_ioctlが指すv4l2_ioctl関数です。

以前のvivi_templateのfopでioctlを呼び出します。

次の図では、vivi_templateのfopsのioctlが__video_do_ioctl関数に呼び出され、最終的にvfdのioctl_opsメンバーの関数、つまりvivi_ioctl_opsの関数を呼び出します

たとえば、VIDIOC_QUERYCAPが呼び出されると、最終的に次の関数が呼び出されます。

/* ------------------------------------------------------------------
	IOCTL vidioc handling
   ------------------------------------------------------------------*/
static int vidioc_querycap(struct file *file, void  *priv,
					struct v4l2_capability *cap)
{
	struct vivi_dev *dev = video_drvdata(file);

	strcpy(cap->driver, "vivi");
	strcpy(cap->card, "vivi");
	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
	cap->version = VIVI_VERSION;
	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
			    V4L2_CAP_READWRITE;
	return 0;
}

 

 

概要:ioctlの呼び出しはopenおよびreadよりも1層多くなります。APPがioctl関数を呼び出すと、cdevでioctl関数が呼び出され、先ほど設定したvfd.fopsでioctl関数が呼び出されます(つまり、読み取り、開く)。 V4l2_ioctlを関数の同じ構造にして、最後にとを呼び出します  

.fops =&vivi_fops、同じ構造の.ioctl_ops =&vivi_ioctl_opsの
対応する関数。

 

 

関連記事:

https://blog.csdn.net/qingkongyeyue/article/details/53447331

https://blog.csdn.net/qingkongyeyue/article/details/52372960

42件のオリジナル記事を公開 いいね10 10,000人以上の訪問者

おすすめ

転載: blog.csdn.net/qq_37659294/article/details/104139839