리눅스에서는 카메라 입력을 받기 위한 표준의 인터페이스로 V4L2 가 존재한다.

카메라 역시 디바이스 드라이버이기 때문에 file-operation  을 이용한다.

디바이스 드라이버라면 역시 노드파일(node) 이 있어야 한다.

 

char-device  major=81  minor=0 부터 계속

 

삼성 S3C6410 보드라면  /dev/cam_codec  81,0 번이며  /dev/cam_preview 는  81,1   번이다.

혹시 보드에  UVC (Usb Video Camera) 를 지원하는 WebCam 을 여기에 연결하면  81,2  번으로 등록된다.

 

코드에서 알아보자

 

드라이버를 연다.

     cam_fd = open( "/dev/cam_codec", O_RDWR );
    if ( 0 > cam_fd )
    {
        printf( " open fail %s\n", dev_name );
        return -1;
    }
 

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

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

드라이버가 overay 를 지원하는가? 

드라이버가 read(), mmap()  함수를 지원하는가?

     {
        struct v4l2_capability cap;
        
        ret = ioctl( cam_fd, VIDIOC_QUERYCAP, &cap );
        if (ret < 0) 
        {
            perror( "VIDIOC_QUERYCAP\n");
            goto err_out;
        }
        /* Check the type - OVERLAY */
        if (!(cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)) 
        {
            printf("Can not capture(V4L2_CAP_VIDEO_OVERLAY is false)\n");
            goto err_out;
        }
        
        if ( cap.capabilities & V4L2_CAP_READWRITE ) 
            printf( " preview surport read io\n" );
        if ( cap.capabilities & V4L2_CAP_STREAMING ) 
            printf( " preview surport mmap\n" );
    }

대부분의 경우 V4L2_CAP_STREAMING  즉 mmap() 함수를 지원한다.

read() 함수를 사용하면 메모리 복사가 한번 더 있어 그 만큼 속도가 떨어진다.


 

카메라 입력 형태를 설정한다

    {
        struct v4l2_format vfmt;
        
        CLEAR_STRUCT(vfmt);
        vfmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;  // V4L2_CAP_VIDEO_OVERLAY
        vfmt.fmt.pix.width       = 640;     
        vfmt.fmt.pix.height      = 480;     
        vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;   
        vfmt.fmt.pix.priv        = V4L2_FMT_IN;
        
        ret = ioctl(cam_fd, VIDIOC_S_FMT, &vfmt);
        if (ret < 0) 
        {
            perror("VIDIOC_S_FMT failled");
            goto err_out;
        }
    }

일반적인  CMOS 카메라라면 YCbCr 형태를 지원할 것이다. 이것을 V4L2_PIX_FMT_YUYV 로 표현한다.

 

카메라 출력 형태를 설정한다

    {
        struct v4l2_framebuffer  vfb;
        struct v4l2_pix_format   vfb_fmt;
        CLEAR_STRUCT(vfb_fmt);
        vfb_fmt.width        = 640;    
        vfb_fmt.height       = 480;    
        vfb_fmt.pixelformat  = V4L2_PIX_FMT_YUV422P; 
         /*  ref. include/linux/videodev2.h
                  pixel(interleave)  : V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_YYUV
                  planar             : V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV411P
        */        
        vfb.base       = 0;
        vfb.flags      = 0;
        vfb.capability = 0;
        vfb.fmt        = vfb_fmt;
        ret = ioctl( cam_fd, VIDIOC_S_FBUF, &vfb);
        if (ret< 0) 
        {
            perror("VIDIOC_S_BUF\n");
        }
    }

 앞에서 언급했듯이 UVC 는 지원하지 않는다.

삼성칩들의 경우 내장 하드웨어를 사용하여  입력의 크기에 관계없이 스케일링하거나 

픽셀단위의 YCrCb 형태가 입력되어도 플랜형태의 버퍼에 담아 준다.

만일 우리가 codec 이 아닌 preview 드라이버를 열었다면 출력형태는 반드시 V4L2_PIX_FMT_RGB565 이어야 한다.

LCD 에 뿌릴 목적이라면 preview 드라이버를 여는것이 합리적이다.

 

continue .........

쓰다보니 시간의 압박이,,, 다음강좌로

근래 들어 카메라 관련 프로젝트가 3건이나 물려있다. 별것 아닌듯 한데 안될땐 증말  실타 emoticon

 

cam2.PNG