視頻傳輸

視頻傳輸方式一:以IIC協議,經過IO口傳輸視頻流:框架

視頻傳輸方式二:以usb接口傳輸視頻流:ide

驅動:字符設備驅動函數

怎麼寫驅動程序:構造file_operationsspa

                             告訴內核code

                             入口函數orm

                             出口函數視頻

v4l2驅動框架:核心層 -- > file_operationsblog

                         硬件相關層:接口

一、將usb攝像頭設備插到裝有虛擬機的pc上,dmesg會打印出一些發現usb攝像頭設備的信息,在內核中grep找到打印信息的具體位置;文檔

二、查找打印信息

三、用source insight或其餘閱讀軟件打開uvc_driver.c文件

      3.1 -->struct uvc_driver

                 --> uvc_probe:

                       v4l2_device_register     // 只是作一些初始化工做,初始化鏈表、自旋鎖、互斥鎖等

                       uvc_register_chains ---uvc_register_video--video_device  video_register_device

                                                          ---struct video_device *vdev;    // 分配video_device結構體,設置並經過video_register_device註冊  video_device結構體有兩個重要的成員 ->fops和->ioctl_ops

                                                                       struct uvc_device *dev,

                                                                 vdev->v4l2_dev = &dev->vdev;
                                                                 vdev->fops = &uvc_fops;

                       media_device_register

四、在內核中有v4l2-framework.txt文檔能夠參考

五、能夠分析虛擬攝像頭驅動:vivi.c

vivi_init-->vivi_create_instance-->video_device_alloc-->video_register_device-->__video_register_device-->vdev->cdev = cdev_alloc();--> cdev_add()

六、在內核中已經提供了file_operations  v4l2_fops  的一些基本函數,因此咱們不須要寫字符設備函數。當應用層調用ioctl函數時,調用file_operations中的ioctl---.unlocked_ioctl = v4l2_ioctl,  -->video_usercopy(file, cmd, arg, __video_do_ioctl) -->__video_do_ioctl --> 根據應用層ioctl傳入的參數調用video_device->ioctl_ops中對應的函數

v4l2_ioctl------

             if (video_is_registered(vdev))
                      ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);

若是video_device已經被註冊了,就調用video_device裏面的fops函數裏面的unlocked_ioctl函數。

而unlocked_ioctl函數內核中已經寫好了,咱們不須要再寫---video_usercopy

----cmd_input_size(cmd);

----check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);

----獲得咱們想要的

static unsigned long cmd_input_size(unsigned int cmd)
{
    /* Size of structure up to and including 'field' */
#define CMDINSIZE(cmd, type, field)                 \
    case VIDIOC_##cmd:                     \
        return offsetof(struct v4l2_##type, field) +     \
            sizeof(((struct v4l2_##type *)0)->field);

    switch (cmd) {
        CMDINSIZE(ENUM_FMT,        fmtdesc,    type);
        CMDINSIZE(G_FMT,        format,        type);
        CMDINSIZE(QUERYBUF,        buffer,        length);
        CMDINSIZE(G_PARM,        streamparm,    type);
        CMDINSIZE(ENUMSTD,        standard,    index);
        CMDINSIZE(ENUMINPUT,        input,        index);
        CMDINSIZE(G_CTRL,        control,    id);
        CMDINSIZE(G_TUNER,        tuner,        index);
        CMDINSIZE(QUERYCTRL,        queryctrl,    id);
        CMDINSIZE(QUERYMENU,        querymenu,    index);
        CMDINSIZE(ENUMOUTPUT,        output,        index);
        CMDINSIZE(G_MODULATOR,        modulator,    index);
        CMDINSIZE(G_FREQUENCY,        frequency,    tuner);
        CMDINSIZE(CROPCAP,        cropcap,    type);
        CMDINSIZE(G_CROP,        crop,        type);
        CMDINSIZE(ENUMAUDIO,        audio,         index);
        CMDINSIZE(ENUMAUDOUT,        audioout,     index);
        CMDINSIZE(ENCODER_CMD,        encoder_cmd,    flags);
        CMDINSIZE(TRY_ENCODER_CMD,    encoder_cmd,    flags);
        CMDINSIZE(G_SLICED_VBI_CAP,    sliced_vbi_cap,    type);
        CMDINSIZE(ENUM_FRAMESIZES,    frmsizeenum,    pixel_format);
        CMDINSIZE(ENUM_FRAMEINTERVALS,    frmivalenum,    height);
    default:
        return _IOC_SIZE(cmd);
    }
}

static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
                void * __user *user_ptr, void ***kernel_ptr)
{
    int ret = 0;

    switch (cmd) {
    case VIDIOC_QUERYBUF:
    case VIDIOC_QBUF:
    case VIDIOC_DQBUF: {
        struct v4l2_buffer *buf = parg;

        if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) {
            if (buf->length > VIDEO_MAX_PLANES) {
                ret = -EINVAL;
                break;
            }
            *user_ptr = (void __user *)buf->m.planes;
            *kernel_ptr = (void *)&buf->m.planes;
            *array_size = sizeof(struct v4l2_plane) * buf->length;
            ret = 1;
        }
        break;
    }

    case VIDIOC_S_EXT_CTRLS:
    case VIDIOC_G_EXT_CTRLS:
    case VIDIOC_TRY_EXT_CTRLS: {
        struct v4l2_ext_controls *ctrls = parg;

        if (ctrls->count != 0) {
            if (ctrls->count > V4L2_CID_MAX_CTRLS) {
                ret = -EINVAL;
                break;
            }
            *user_ptr = (void __user *)ctrls->controls;
            *kernel_ptr = (void *)&ctrls->controls;
            *array_size = sizeof(struct v4l2_ext_control)
                    * ctrls->count;
            ret = 1;
        }
        break;
    }
    }

    return ret;
}

七、用strace 能夠得到程序執行過程當中的系統調用

strace -o xawtv.log xawtv

xawtv所涉及的系統調用就會記錄在xawtv.log中

相關文章
相關標籤/搜索