Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #95, НОЯБРЬ 2006 г.

Eye of the xakep

Fagot (salieff@mail.ru)

Хакер, номер #095, стр. 095-124-3


Начинаем с того, что открываем файл камеры и получаем ее свойства:

КОД

int vdev_fd;

struct video_capability videocap;

if ((vdev_fd=open("/dev/video0", O_RDWR))<0) return false;

if (ioctl(vdev_fd, VIDIOCGCAP, &videocap)!=0) return false;

if (!(videocap.type&VID_TYPE_CAPTURE)) return false;

Так как у меня веб-камера, а не тюнер с кучей каналов (не эфирных, а аппаратных - аудио, видео, телетекста и прочих), то я не буду заморачиваться с выбором нужного канала посредством VIDIOCGCHAN/VIDIOCSCHAN, а сразу перейду к настройке параметров картинки, запрошу текущие параметры, поправлю необходимые мне и установлю обратно:

КОД

struct video_picture videopict;

if (ioctl(vdev_fd, VIDIOCGPICT, &videopict)!=0) return false;

videopict.depth=24;

videopict.palette=VIDEO_PALETTE_RGB24;

if (ioctl(vdev_fd, VIDIOCSPICT, &videopict)!=0) return false;

Затем установим разрешение видеозахвата. Я ставлю максимальное из ранее полученных от камеры свойств:

КОД

struct video_window videowin;

if (ioctl(vdev_fd, VIDIOCGWIN, &videowin)!=0) return false;

videowin.width=videocap.maxwidth;

videowin.height=videocap.maxheight;

if (ioctl(vdev_fd, VIDIOCSWIN, &videowin)!=0) return false;

Теперь все готово к тому, чтобы читать кадры из дескриптора vdev_fd, например вот так:

КОД

char frame_buf[videowin.width*videowin.height*videopict.depth/8]={0};

if (read(vdev_fd, frame_buf, sizeof(frame_buf))!=sizeof(frame_buf)) return false;

Но... это неспортивно ;). Сейчас объясню почему. Каждый вызов read блокируется на время формирования кадра, а между вызовами камера простаивает. Учитывая невысокий FPS дешевых веб-камер, это недопустимо. Нужно сделать так, чтобы во время обработки текущего кадра камера уже формировала следующий, то есть организовать doublebuffering. Делается это с помощью mmap. Суть такова – можно сказать камере, чтобы она начала формирование кадра, а самому не блокироваться, а заниматься своими делами. Для использования mmap нужно получить параметры мэпинга и заmmap'ить сам файл камеры:

КОД

struct video_mbuf videobuf;

unsigned char * vbuf_ptr;

if (ioctl(vdev_fd, VIDIOCGMBUF, &videobuf)!=0) return false;

if ((vbuf_ptr=(unsigned char *)mmap(0, videobuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, vdev_fd, 0))==MAP_FAILED) return false;

Теперь можно приступить к захвату в режиме doublebufering. Синхронизируемся с формированием кадра, копируем кадр из mmap-указателя в рабочий буфер, запускаем на формирование следующий кадр, отправляем рабочий буфер на обработку. Таким образом, пока идет обработка, камера не теряет времени даром, формируя нам следующий кадр:

КОД

struct video_mmap vmmap;

vmmap.height = videowin.height;

vmmap.width = videowin.width;

vmmap.format = videopict.palette;

vmmap.frame = 0;

if (ioctl(vdev_fd, VIDIOCMCAPTURE, &vmmap)!=0) return false;

Назад на стр. 095-124-2  Содержание  Вперед на стр. 095-124-4