VideoForLinux2 & HOLA-VCEB
muaddib
Пункты: 1232
Регистрация: 20.11.2014
Программировал ли кто-нибудь захват изображения с HOLA-VCEB на С++ используя VideoForLinux2?
Выполняю команду modprobe mxc_v4l2_capture, для того чтобы /dev/video0 появился.
Использую стандартный код.
Привожу пример сокращенного кода:
//Открываю устройство
int vdev_fd = ::open(/dev/video0, O_RDWR);
//Задаю формат и разрешение
v4l2_format videopict;
videopict.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
videopict.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;
videopict.fmt.pix.width = 720;
videopict.fmt.pix.height = 576;
//Выделяю память
unsigned char *buf = new unsigned char[720 * 576 * 2];
//Читаю в цикле
read(vdev_fd, buf, 720 * 576 * 2);
В результате получаю 3 кадра/сек и вот такое изображение
http://savepic.su/4475971.jpg
Тот же самый код проверял для архитектуры x86 для платы Avermedia, все корректно работает и кадров/сек: 25.
sasamy
Пункты: 83556
Регистрация: 14.08.2009
Если собираете в buildroot - включите в сборку
-> Target packages
-> Hardware handling
-> Freescale i.MX libraries
[*] imx-test
там есть примеры для захвата кадров с tv in, исходники после сборки можно найти в output/build/imx-test-xxx
Цитата
//Читаю в цикле
read(vdev_fd, buf, 720 * 576 * 2);
...
Тот же самый код проверял для архитектуры x86 для платы Avermedia, все корректно работает и кадров/сек: 25.
если надо отдельные кадры брать (1-2 в сек) можно и read использовать, а вообще о нем лучше забыть на arm-ах, используйте mmap или user-ptr
muaddib
Пункты: 1232
Регистрация: 20.11.2014
muaddib
Пункты: 1232
Регистрация: 20.11.2014
muaddib
Пункты: 1232
Регистрация: 20.11.2014
muaddib
Пункты: 1232
Регистрация: 20.11.2014
Непонятно, также как менять номер видеовхода платы.
VIDIOC_S_INPUT выдает ошибку если задаешь номер больше 1.
На 0 и 1 визуально ничего не меняется.
muaddib
Пункты: 1232
Регистрация: 20.11.2014
sasamy
Пункты: 83556
Регистрация: 14.08.2009
danilsl
Пункты: 4201
Регистрация: 08.12.2010
Пол: Мужчина
Код int cx25858_camera::camsrc_open_device(char * camdev, int w, int h) {
int index;
struct v4l2_input input;
v4l2_std_id std_id;
struct v4l2_standard standard;
struct v4l2_capability capability;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_frequency freq;
unsigned int i;
if (capture_fd != 0)
return -1;
capture_fd = open(camdev, O_RDWR);
if (capture_fd <= 0) {
printf("Cannot open = %s device\n", camdev);
return -1;
}
printf("Opened device %s\n", camdev);
if (ioctl(capture_fd, VIDIOC_G_INPUT, &index) < 0) {
printf("Error VIDIOC_G_INPUT\n");
camsrc_close_device();
return -1;
}
printf("Active input is %d\n", index);
memset(&input, 0, sizeof (input));
input.index = index;
if (ioctl(capture_fd, VIDIOC_ENUMINPUT, &input) < 0) {
printf("Error VIDIOC_ENUMINPUT\n");
}
printf("%s: Current Input: %s\n", camdev, input.name);
if (ioctl(capture_fd, VIDIOC_QUERYSTD, &std_id) < 0) {
printf("Error VIDIOC_QUERYSTD\n");
}
std_id = V4L2_STD_PAL_BG;
if (ioctl(capture_fd, VIDIOC_S_STD, &std_id) < 0) {
printf("Error VIDIOC_G_STD\n");
} else
printf("std_id = %d\n", (int) std_id);
memset(&standard, 0, sizeof (standard));
standard.index = 0;
while (1) {
if (ioctl(capture_fd, VIDIOC_ENUMSTD, &standard) < 0) {
printf("Error VIDIOC_ENUMSTD\n");
break;
}
/* Store the name of the standard */
printf("std.id=%d std.name=%s\n", (int) standard.id, standard.name);
if (standard.id & std_id) {
printf("%s: Current standard: %s\n", camdev, standard.name);
//break;
}
standard.index++;
}
memset(&capability, 0, sizeof (capability));
if (ioctl(capture_fd, VIDIOC_QUERYCAP, &capability) < 0) {
printf("Error VIDIOC_QUERYCAP\n");
camsrc_close_device();
return -1;
}
if (capability.capabilities & V4L2_CAP_STREAMING)
printf("%s: Capable of streaming\n", camdev);
else {
printf("%s: Not capable of streaming\n", camdev);
camsrc_close_device();
return -1;
}
memset(&fmt, 0, sizeof (fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(capture_fd, VIDIOC_G_FMT, &fmt) < 0) {
printf("Error VIDIOC_G_FMT\n");
camsrc_close_device();
return -1;
}
printf("Video size is %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
fmt.fmt.pix.width = w;
fmt.fmt.pix.height = h;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
//fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (ioctl(capture_fd, VIDIOC_S_FMT, &fmt) < 0) {
printf("Error VIDIOC_S_FMT\n");
camsrc_close_device();
return -1;
}
if (ioctl(capture_fd, VIDIOC_G_FMT, &fmt) < 0) {
printf("Error VIDIOC_G_FMT\n");
camsrc_close_device();
return -1;
}
printf("Capture size is %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
width = fmt.fmt.pix.width;
height = fmt.fmt.pix.height;
// if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
// printf("Pixel format is V4L2_PIX_FMT_YUYV\n");
memset(&req, 0, sizeof (req));
req.count = NUM_BUFFERS;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(capture_fd, VIDIOC_REQBUFS, &req) < 0) {
printf("Cannot allocate memory. Error VIDIOC_REQBUFS\n");
camsrc_close_device();
return -1;
}
printf("%s: Number of requested buffers = %d\n", camdev, req.count);
buffers = (buffer*) calloc(req.count, sizeof (*buffers));
for (i = 0; i < req.count; i++) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof (buf));
buf.type = req.type;
buf.memory = req.memory;
buf.index = i;
if (ioctl(capture_fd, VIDIOC_QUERYBUF, &buf) < 0) {
printf("Error VIDIOC_QUERYCAP\n");
allocbufs = i;
camsrc_close_device();
return -1;
}
buffers[i].length = buf.length;
buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, capture_fd, buf.m.offset);
if (buffers[i].start == MAP_FAILED) {
printf("Cannot mmap = %d buffer\n", i);
allocbufs = i;
camsrc_close_device();
return -1;
}
memset((void *) buffers[i].start, 0x80, buffers[i].length);
if (ioctl(capture_fd, VIDIOC_QBUF, &buf)) {
printf("Error VIDIOC_QBUF\n");
allocbufs = i;
camsrc_close_device();
return -1;
}
printf("Allocated buffer %d with length %d\n", i, buffers[i].length);
bufLenght = buffers[i].length;
}
allocbufs = NUM_BUFFERS;
return 0;
}
Код int cx25858_camera::startCapturing() {
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(capture_fd, VIDIOC_STREAMON, &type)) {
printf("Error VIDIOC_STREAMON\n");
return -1;
}
return 0;
}
Код int cx25858_camera::getFrame() {
struct v4l2_buffer capture_buf;
memset(&capture_buf, 0, sizeof (capture_buf));
capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
capture_buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(capture_fd, VIDIOC_DQBUF, &capture_buf)) {
printf("Error VIDIOC_DQBUF\n");
return -1;
}
if (capture_buf.index >= NUM_BUFFERS) {
printf("Invalid buffer\n");
return -1;
}
memcpy(rawBuffer, buffers[capture_buf.index].start,
buffers[capture_buf.index].length);
if (ioctl(capture_fd, VIDIOC_QBUF, &capture_buf)) {
printf("Error VIDIOC_QBUF\n");
return -1;
}
return 0;
}
Это кусок класса, но основное здесь есть. Код писался для коннексантовского захвата с кривым драйвером, с которым не захотели работать ни gstreamer, ни opencv. Но с тех пор этот код работал на любых аналоговых захватах, что мне попадали.
А read() использует слишком много ресурсов камня. А в камне не всё гладко с прямым чтением из CSI.