Hatena::Grouptechmemo

USBカメラを使って色々遊ぶ日記(仮)

2008-04-13

サンプルを読み解く(4)

| 14:26 | サンプルを読み解く(4) - USBカメラを使って色々遊ぶ日記(仮) を含むブックマーク はてなブックマーク - サンプルを読み解く(4) - USBカメラを使って色々遊ぶ日記(仮)

次は、init_device()を見ていきます。

ちょっと長めなので、ちょっとずつ分割して確認。

まずは、変数の宣言部。 コメントはわたし自身によるものです。

static void
init_device                     (void)
{
    /* デバイスの能力を問い合わせるときに結果を格納する構造体 */
    struct v4l2_capability cap;
    /* キャプチャ5のクロッピング能力問合せ時に結果を格納する構造体 */
    struct v4l2_cropcap cropcap;
    /* クロッピングされた画像を格納する構造体 */
    struct v4l2_crop crop;
    /* フォーマットに関する情報を格納する構造体 */
    struct v4l2_format fmt;
    unsigned int min;

下3つの構造体が何のためのものか読んでたら時間がかかってしまった。

次は、VIDIOC_QUERYCAPを使ってデバイスの能力を問い合わせてチェックするところ。

    /* xioctlは、このサンプルで定義されている関数で、
     * 中でioctlを実行している。*/
    if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
        if (EINVAL == errno) {
            /* 引数に誤りがあった場合 */
            fprintf (stderr, "%s is no V4L2 device\n",
                     dev_name);
            exit (EXIT_FAILURE);
        } else {
            errno_exit ("VIDIOC_QUERYCAP");
        }
    }

    /* デバイスがキャプチャ能力を備えているかチェック */ 
    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
        fprintf (stderr, "%s is no video capture device\n",
                 dev_name);
        exit (EXIT_FAILURE);
    }

    /* 入出力の種類を判別?変数ioはサンプル内定義のstatic変数(enum)
     * デフォルトはIO_METHOD_MMAP */
    switch (io) {
    case IO_METHOD_READ:
        /* とりあえずこちらは使わないので無視 */
        if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
            fprintf (stderr, "%s does not support read i/o\n",
                     dev_name);
            exit (EXIT_FAILURE);
        }

        break;

    case IO_METHOD_MMAP:
    case IO_METHOD_USERPTR:
        /* デバイスがストリーミングIOをサポートしているかチェック */
        if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
            fprintf (stderr, "%s does not support streaming i/o\n",
                     dev_name);
            exit (EXIT_FAILURE);
        }

        break;
    }

次は、クロッピング領域の設定。

    /* Select video input, video standard and tune here. */

    CLEAR (cropcap);

    /* ここはアプリケーション側でセットしなくてはいけないらしい */
    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    /* その後、ioctlでv4l2_cropcap構造体の残り部分を埋めてくれる */
    if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        crop.c = cropcap.defrect; /* reset to default */

        /* クロッピングする領域をcrop構造体の中身に従ってセット */
        if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
            switch (errno) {
            case EINVAL:
                /* Cropping not supported. */
                break;
            default:
                /* Errors ignored. */
                break;
            }
        }
    } else {        
        /* Errors ignored. */
    }

次は、映像フォーマットの設定。

    CLEAR (fmt); /* 初期化して */

    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width       = 640; 
    fmt.fmt.pix.height      = 480;
    /* ピクセルフォーマットの設定 YUYVに */
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    /* 受信する映像のフィールド */
    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

    if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
        errno_exit ("VIDIOC_S_FMT");

    /* Note VIDIOC_S_FMT may change width and height. */

    /* Buggy driver paranoia. */ /* これは何だろう? */
    min = fmt.fmt.pix.width * 2;
    if (fmt.fmt.pix.bytesperline < min)
        fmt.fmt.pix.bytesperline = min;
    min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
    if (fmt.fmt.pix.sizeimage < min)
        fmt.fmt.pix.sizeimage = min;

最後に、バッファとするメモリ領域の初期化を行っている。

    switch (io) {
    case IO_METHOD_READ:
        init_read (fmt.fmt.pix.sizeimage);
        break;

    /* デフォルトはmmap */
    case IO_METHOD_MMAP:
        init_mmap ();
        break;

    case IO_METHOD_USERPTR:
        init_userp (fmt.fmt.pix.sizeimage);
        break;
    }
}

こちらの中身はとりあえず置いておく。