저번글에 이어서

 

드라이버를 연 이후에는 다음과 같은 과정을 거친다.

  • 드라이버가 overay 를 지원하는가?   >> 지원하지 않으면 에러이다.
  • 드라이버가 read(), mmap()  함수를 지원하는가?   >> 둘중 하나만 지원하면 된다. (정확히는 user-io 란 것도 있다.)
  • 카메라 입력 형태를 설정한다.  >> YCbCr, RGB 이런 형태와 해상도를 설정한다.
  • 카메라 출력 형태를 설정한다.   >> 출력형태를 지원하지 않아도 된다. (UVC 는 이런것이 대부분 없다)
  • mmap 를 사용하여 메모리를 할당받는다.  >> read() 함수를 사용한다면 안해도 된다.
  • 카메라 캡쳐를 시작한다.
  • 프레임이 만들어 졌는지 감시한다.
  • 만들어진 프레임을 화면에 뿌리거나 파일에 저장하거나 압축하거나..
  • 다음 프레임 캡쳐를 기다리거나 종료한다.

 

이제 카메라 입력과 출력에 대한것을 설정하였으니 이제 메모리 할당을 해야한다.

 

mmap 를 사용하여 메모리를 할당받는다

 

 /*
  typedef struct {
      unsigned int  len;
      void *start;
  } qbuf_t;
*/
  
    struct v4l2_requestbuffers req;
    unsigned int loop;
    int  rtn, qcnt;
   
    qcnt = 4;
   
    CLEAR_STRUCT(req);
    req.count  = qcnt;
    req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
   
    rtn = ioctl( cam_fd, VIDIOC_REQBUFS, &req );
    if ( 0 > rtn )
    {
        perror("VIDIOC_REQBUFS" );
        return -1;
    }
   
    printf( " qcount=%d(app) req.count=%d(dev)\n", qcnt, req.count );  
 
    for(loop=0; loop<req.count; loop++)
    {
        struct v4l2_buffer buf;
       
        CLEAR_STRUCT(buf);
        buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index  = loop;
 
        rtn = ioctl( cam_fd, VIDIOC_QUERYBUF, &buf );
        if ( 0 > rtn )
        {
            perror("VIDIOC_QUERYBUF" );
            return -1;
        }
       
        qbuf->len   = buf.length;
        qbuf->start = mmap (NULL,
                            buf.length,
                            PROT_READ | PROT_WRITE, /* required */
                            MAP_SHARED,             /* recommended */
                            cam_fd, buf.m.offset ); 
                          
        if ( MAP_FAILED == qbuf->start )
        {
            perror("mmap failed" );
            return -1;
        }
 
        printf(" %d) start =0x%p\n", loop, qbuf->start );
        printf("    length=0x%05x (%d)\n", buf.length, buf.length   );
       
        qbuf++;
    }


    mmap 를 사용한다면 카메라드라이버로 부터 선두주소를 얻어야 한다. 대게의 경우 4개의 버퍼를 지원한다.

    mmap 를 지원하지 않는다면 read() 함수를 사용하여 읽어내면 된다.

 

 

카메라 캡쳐를 시작한다

 

  enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
 ioctl(cam_fd, VIDIOC_STREAMON, &type);

 

    캡쳐를 중지하려면 VIDIOC_STREAMOFF 를 사용한다.

 

 

프레임이 만들어 졌는지 감시한다
 

    rtn = poll( (struct pollfd *)&poll_fds, 1, tmout );
    if ( rtn < 0 ) return -1;
 
    CLEAR_STRUCT(buf);
    buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
 
    rtn = ioctl( cam_fd, VIDIOC_DQBUF, &buf ); 
    if ( rtn == -1 ) rtn = ioctl( cam_fd, VIDIOC_QBUF, &buf );

 

    poll() 함수를 통해 캡쳐가 되었는지 이벤트로 확인한다.
    VIDIOC_DQBUF  를 지원하지 않는다면  VIDIOC_QBUF 를 사용한다.

    삼성 MCU 의 cam 드라이버는 VIDIOC_DQBUF 를 지원하지만  UVC 는 지원하지 않는다.

 

이제 프레임이 만들어 졌으니 이것을 가지고 화면에 뿌리거나 아니면 파일에 저장하면 된다.

메모리 선두 주소는  buf.index  값을 확인한 후 mmap 를 얻은 버퍼의 인덱스 번호에 해당하는 메모리 주소를

크기 만큼 저장하면 된다.

 

UVC 카메라를 사용할때 USB 2.0 이 아니면 카메라 해상도와 프레임수가 심하게 제한을 받는다.

UVC 카메라를 사용할려면 USB 2.0 이 필수이다. ㅠ,ㅠ

 

이상  "삼성ARM MCU 의 카메라에 대한 글" 을 맞칩니다.

 

cam2.PNG