하드웨어
저번글에 이어서
드라이버를 연 이후에는 다음과 같은 과정을 거친다.
- 드라이버가 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 의 카메라에 대한 글" 을 맞칩니다.