回覆列表
  • 1 # 奈何黑夜

    在linux下所有裝置都是檔案。所以對攝像頭的操作其實就是對檔案的操作。USB攝像頭的裝置檔案就是在/dev目錄下的video0(假如只有一個攝像頭)。在linux下操作攝像頭就是使用v4l2對攝像頭進行的操作,操作步驟如下

    開啟裝置檔案。

    int fd=open(”/dev/video0″,O_RDWR);

    2. 取得裝置的capability,看看裝置具有什麼功能,比如是否具有輸入,或者音訊輸入輸出等。VIDIOC_QUERYCAP,struct v4l2_capability

    v4l2_std_id std;

    do {

    ret= ioctl(fd, VIDIOC_QUERYSTD, std);

    } while (ret == -1 errno == EAGAIN);

    switch (std) {

    case V4L2_STD_NTSC:

    //……

    case V4L2_STD_PAL:

    //……

    }

    3. 選擇輸入,一個裝置可以有多個輸入。VIDIOC_S_INPUT,struct v4l2_input(可不要)

    4. 設定的制式和幀格式,制式包括PAL,NTSC,幀的格式個包括寬度和高度等。

    VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format

    struct v4l2_format fmt;

    memset ( fmt, 0, sizeof(fmt) );

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    fmt.fmt.pix.width = 320;

    fmt.fmt.pix.height = 240;

    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;

    if (ioctl(fd, VIDIOC_S_FMT, fmt) < 0)

    {

    printf("set format failed\n");

    //return 0;

    }

    5. 向驅動申請幀緩衝,一般不超過5個。struct v4l2_requestbuffers

    struct v4l2_requestbuffers req;

    memset(req, 0, sizeof (req));

    req.count = 4;

    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    req.memory = V4L2_MEMORY_MMAP;

    if (ioctl(fd,VIDIOC_REQBUFS,req) == -1)

    {

    perror("VIDIOC_REQBUFS error \n");

    //return -1;

    }

    6.申請物理記憶體

    將申請到的幀緩衝對映到使用者空間,這樣就可以直接操作採集到的幀了,而不必去複製。將申請到的幀緩衝全部入佇列,以便存放採集到的資料.VIDIOC_QBUF,struct v4l2_buffer

    VideoBuffer* buffers = calloc( req.count, sizeof(VideoBuffer) );

    printf("sizeof(VideoBuffer) is %d\n",sizeof(VideoBuffer));

    struct v4l2_buffer buf;

    for (numBufs = 0; numBufs < req.count; numBufs++)

    {

    memset( buf, 0, sizeof(buf) );

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory = V4L2_MEMORY_MMAP;

    buf.index = numBufs;

    if (ioctl(fd, VIDIOC_QUERYBUF, buf) < 0)

    {

    printf("VIDIOC_QUERYBUF error\n");

    //return -1;

    }

    printf("buf len is %d\n",sizeof(buf));

    //記憶體對映

    buffers[numBufs].length = buf.length;

    buffers[numBufs].offset = (size_t) buf.m.offset;

    buffers[numBufs].start = mmap (NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);

    printf("buffers.length = %d,buffers.offset = %d ,buffers.start[0] = %d\n",buffers[numBufs].length,buffers[numBufs].offset,buffers[numBufs].start[0]);

    printf("buf2 len is %d\n",sizeof(buffers[numBufs].start));

    if (buffers[numBufs].start == MAP_FAILED)

    {

    perror("buffers error\n");

    //return -1;

    }

    if (ioctl (fd, VIDIOC_QBUF, buf) < 0)

    {

    printf("VIDIOC_QBUF error\n");

    //return -1;

    }

    }

    7. 開始的採集。

    enum v4l2_buf_type type;

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if (ioctl (fd, VIDIOC_STREAMON, type) < 0)

    {

    printf("VIDIOC_STREAMON error\n");

    // return -1;

    }

    8. 出佇列以取得已採集資料的幀緩衝,取得原始採集資料。VIDIOC_DQBUF, 將緩衝重新入佇列尾,這樣可以迴圈採集。VIDIOC_QBUF

    if (ioctl(fd, VIDIOC_DQBUF, buf) < 0)

    {

    perror("VIDIOC_DQBUF failed.\n");

    //return -1;

    }

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory = V4L2_MEMORY_MMAP;

    unsigned char *ptcur = buffers[numBufs].start;

    DEBUG("buf.bytesused = %d \n",buf.bytesused);

    int i1;

    for(i1=0; i1<buf.bytesused; i1++)

    {

    if((buffers[numBufs].start[i1] == 0xFF) (buffers[numBufs].start[i1+1] == 0xC4))

    {

    DEBUG("huffman table finded! \nbuf.bytesused = %d\nFFC4 = %d \n",buf.bytesused,i1);

    break;

    }

    }

    if(i1 == buf.bytesused)printf("huffman table don"t exist! \n");

    int i;

    for(i=0; i<buf.bytesused; i++)

    {

    if((buffers[numBufs].start[i] == 0xFF) (buffers[numBufs].start[i+1] == 0xD8)) break;

    ptcur++;

    }

    DEBUG("i=%d,FF=%02x,D8=%02x\n",i,buffers[numBufs].start[i],buffers[numBufs].start[i+1]);

    int imagesize =buf.bytesused - i;

    DEBUG("buf.bytesused = %d \n",buf.bytesused);

    DEBUG ("imagesize = %d \n",imagesize);

    9. 停止的採集。VIDIOC_STREAMOFF

    10. 關閉裝置。close(fd);

  • 中秋節和大豐收的關聯?
  • 工程質量檢驗評定標準是如何規定的?