1

Добрый день!
Возникла такая задача, вывода нескольких изображений с одной видеокамеры на устройстве.
Т.е. один монитор одна камера и с нее валится два одинаковых изображения.
Использую arm устройство, с установленным Linux.
Вывести изображение с камеры могу при помощи V4l2 используя технологи mmap, но вот как вывести изображение два раза не понимаю. Подскажите пожалуйста может кто-то сталкивался с такой задачей?

2

mibin пишет:

Вывести изображение с камеры могу при помощи V4l2 используя технологи mmap

код в студию...

95% процентов проблем находятся между клавиатурой и стулом.

3

Ну код собственно вот он.
Вся фигня в том, что данная реализация поддерживает открытие устройства /dev/video16 (видеовыход) несколько раз (соответственно я завожу вторую переменную под устройство /dev/video16), НО при этом нельзя запустить поток (VIDIOC_STREAMON) на это устройство второй раз.

Это полностью рабочий код без каких либо изменений в сторону вывода второго изображения.
Данный код считывает данные с камеры и выводит их на дисплей.

#ifdef __cplusplus
extern "C"{
#endif

/*=======================================================================
                                        INCLUDE FILES
=======================================================================*/
/* Standard Include Files */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

/* Verification Test Environment Include Files */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <asm/types.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <math.h>
#include <string.h>
#include <malloc.h>

#include <linux/mxcfb.h>

#define TFAIL -1
#define TPASS 0

char v4l_capture_dev[100] = "/dev/video0";
char v4l_output_dev[100] = "/dev/video16";
int fd_capture_v4l = 0;
int fd_output_v4l = 0;
int g_cap_mode = 0;
int g_input = 1;
int g_fmt = V4L2_PIX_FMT_UYVY;
int g_rotate = 0;
int g_motion = 0;
int g_tb = 0;
int g_output = 3;
int g_output_num_buffers = 4;
int g_capture_num_buffers = 3;
int g_in_width = 0;
int g_in_height = 0;
int g_display_width = 0;
int g_display_height = 0;
int g_display_top = 0;
int g_display_left = 0;
int g_frame_size;
int g_frame_period = 33333;
v4l2_std_id g_current_std = V4L2_STD_PAL;

struct testbuffer
{
        unsigned char *start;
        size_t offset;
        unsigned int length;
};

struct testbuffer output_buffers[4];
struct testbuffer capture_buffers[3];

int start_capturing(void)
{
        unsigned int i;
        struct v4l2_buffer buf;
        enum v4l2_buf_type type;

        for (i = 0; i < g_capture_num_buffers; i++)
        {
                memset(&buf, 0, sizeof (buf));
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.index = i;
                if (ioctl(fd_capture_v4l, VIDIOC_QUERYBUF, &buf) < 0)
                {
                        printf("VIDIOC_QUERYBUF error\n");
                        return TFAIL;
                }

                capture_buffers[i].length = buf.length;
                capture_buffers[i].offset = (size_t) buf.m.offset;
                capture_buffers[i].start = mmap (NULL, capture_buffers[i].length,
                    PROT_READ | PROT_WRITE, MAP_SHARED,
                    fd_capture_v4l, capture_buffers[i].offset);
        memset(capture_buffers[i].start, 0xFF, capture_buffers[i].length);
        }

        for (i = 0; i < g_capture_num_buffers; i++)
        {
                memset(&buf, 0, sizeof (buf));
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;
                buf.index = i;
        buf.m.offset = capture_buffers[i].offset;
                if (ioctl (fd_capture_v4l, VIDIOC_QBUF, &buf) < 0) {
                        printf("VIDIOC_QBUF error\n");
                        return TFAIL;
                }
        }

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if (ioctl (fd_capture_v4l, VIDIOC_STREAMON, &type) < 0) {
                printf("VIDIOC_STREAMON error\n");
                return TFAIL;
        }
        return 0;
}

int prepare_output(void)
{
    int i;
    struct v4l2_buffer output_buf;

    for (i = 0; i < g_output_num_buffers; i++)
    {
            memset(&output_buf, 0, sizeof(output_buf));
            output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
            output_buf.memory = V4L2_MEMORY_MMAP;
            output_buf.index = i;
            if (ioctl(fd_output_v4l, VIDIOC_QUERYBUF, &output_buf) < 0)
            {
                    printf("VIDIOC_QUERYBUF error\n");
        return TFAIL;
            }

            output_buffers[i].length = output_buf.length;
            output_buffers[i].offset = (size_t) output_buf.m.offset;
            output_buffers[i].start = mmap (NULL, output_buffers[i].length,
                                     PROT_READ | PROT_WRITE, MAP_SHARED,
                                     fd_output_v4l, output_buffers[i].offset);
            if (output_buffers[i].start == NULL) {
                    printf("v4l2 tvin test: output mmap failed\n");
        return TFAIL;
            }
    }
    return 0;
}

int v4l_capture_setup(void)
{
    struct v4l2_dbg_chip_ident chip;
    struct v4l2_format fmt;
    struct v4l2_streamparm parm;
        struct v4l2_requestbuffers req;
    v4l2_std_id id;

    if (ioctl(fd_capture_v4l, VIDIOC_DBG_G_CHIP_IDENT, &chip))
    {
        printf("VIDIOC_DBG_G_CHIP_IDENT failed.\n");
        close(fd_capture_v4l);
        return TFAIL;
    }
    printf("TV decoder chip is %s\n", chip.match.name);

    if (ioctl(fd_capture_v4l, VIDIOC_S_INPUT, &g_input) < 0)
    {
        printf("VIDIOC_S_INPUT failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id) < 0)
    {
        printf("VIDIOC_G_STD failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }
    g_current_std = id;

    if (ioctl(fd_capture_v4l, VIDIOC_S_STD, &id) < 0)
    {
        printf("VIDIOC_S_STD failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    parm.parm.capture.timeperframe.numerator = 1;
    parm.parm.capture.timeperframe.denominator = 0;
    parm.parm.capture.capturemode = 0;
    if (ioctl(fd_capture_v4l, VIDIOC_S_PARM, &parm) < 0)
    {
        printf("VIDIOC_S_PARM failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.pixelformat = g_fmt;
    fmt.fmt.pix.width = 0;
    fmt.fmt.pix.height = 0;
    if (ioctl(fd_capture_v4l, VIDIOC_S_FMT, &fmt) < 0)
    {
        printf("VIDIOC_S_FMT failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    if (ioctl(fd_capture_v4l, VIDIOC_G_FMT, &fmt) < 0)
    {
        printf("VIDIOC_G_FMT failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    g_in_width = fmt.fmt.pix.width;
    g_in_height = fmt.fmt.pix.height;

    memset(&req, 0, sizeof (req));
    req.count = g_capture_num_buffers;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if (ioctl(fd_capture_v4l, VIDIOC_REQBUFS, &req) < 0)
    {
            printf("VIDIOC_REQBUFS failed\n");
    close(fd_capture_v4l);
            return TFAIL;
    }

    return 0;
}

int v4l_output_setup(void)
{
    struct v4l2_control ctrl;
    struct v4l2_format fmt;
    struct v4l2_framebuffer fb;
    struct v4l2_cropcap cropcap;
    struct v4l2_crop crop;
    struct v4l2_requestbuffers buf_req;

    if (ioctl(fd_output_v4l, VIDIOC_S_OUTPUT, &g_output) < 0)
    {
            printf("set output failed\n");
            return TFAIL;
    }

    memset(&cropcap, 0, sizeof(cropcap));
    cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    if (ioctl(fd_output_v4l, VIDIOC_CROPCAP, &cropcap) < 0)
    {
            printf("get crop capability failed\n");
            return TFAIL;
    }

    crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    crop.c.top = g_display_top;
    crop.c.left = g_display_left;
    crop.c.width = g_display_width;
    crop.c.height = g_display_height;
    if (ioctl(fd_output_v4l, VIDIOC_S_CROP, &crop) < 0)
    {
            printf("set crop failed\n");
            return TFAIL;
    }

    ctrl.id = V4L2_CID_PRIVATE_BASE;
    ctrl.value = g_rotate;
    if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
    {
            printf("set ctrl failed\n");
    return TFAIL;
    }

    ctrl.id = V4L2_CID_PRIVATE_BASE + 3;
    ctrl.value = g_motion;
    if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
    {
            printf("set ctrl failed\n");
    return TFAIL;
    }

    fb.flags = V4L2_FBUF_FLAG_OVERLAY;
    ioctl(fd_output_v4l, VIDIOC_S_FBUF, &fb);

    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    fmt.fmt.pix.width= g_in_width;
    fmt.fmt.pix.height= g_in_height;
    fmt.fmt.pix.pixelformat = g_fmt;
    fmt.fmt.pix.bytesperline = g_in_width;
    fmt.fmt.pix.priv = 0;
    fmt.fmt.pix.sizeimage = 0;
    if (g_tb)
        fmt.fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
    else
        fmt.fmt.pix.field = V4L2_FIELD_INTERLACED_BT;
        if (ioctl(fd_output_v4l, VIDIOC_S_FMT, &fmt) < 0)
        {
                printf("set format failed\n");
                return TFAIL;
        }

        if (ioctl(fd_output_v4l, VIDIOC_G_FMT, &fmt) < 0)
        {
                printf("get format failed\n");
                return TFAIL;
        }
        g_frame_size = fmt.fmt.pix.sizeimage;

        memset(&buf_req, 0, sizeof(buf_req));
        buf_req.count = g_output_num_buffers;
        buf_req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        buf_req.memory = V4L2_MEMORY_MMAP;
        if (ioctl(fd_output_v4l, VIDIOC_REQBUFS, &buf_req) < 0)
        {
                printf("request buffers failed\n");
                return TFAIL;
        }

    return 0;
}

int
mxc_v4l_tvin_test(void)
{
    struct v4l2_buffer capture_buf, output_buf;
    v4l2_std_id id;
    int i, j;
    enum v4l2_buf_type type;
    int total_time;
    struct timeval tv_start, tv_current;

    if (prepare_output() < 0)
    {
        printf("prepare_output failed\n");
        return TFAIL;
    }

    if (start_capturing() < 0)
    {
        printf("start_capturing failed\n");
        return TFAIL;
    }

    gettimeofday(&tv_start, 0);
    printf("start time = %d s, %d us\n", tv_start.tv_sec, tv_start.tv_usec);

    for (i = 0; ; i++) {
begin:
        if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id)) {
                        printf("VIDIOC_G_STD failed.\n");
            return TFAIL;
        }

        if (id == g_current_std)
            goto next;
        else if (id == V4L2_STD_PAL || id == V4L2_STD_NTSC) {
            type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
            ioctl(fd_output_v4l, VIDIOC_STREAMOFF, &type);

            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            ioctl(fd_capture_v4l, VIDIOC_STREAMOFF, &type);

            for (j = 0; j < g_output_num_buffers; j++)
            {
                munmap(output_buffers[j].start, output_buffers[j].length);
            }
            for (j = 0; j < g_capture_num_buffers; j++)
            {
                munmap(capture_buffers[j].start, capture_buffers[j].length);
            }

            if (v4l_capture_setup() < 0) {
                printf("Setup v4l capture failed.\n");
                return TFAIL;
            }

            if (v4l_output_setup() < 0) {
                printf("Setup v4l output failed.\n");
                return TFAIL;
            }

            if (prepare_output() < 0)
            {
                printf("prepare_output failed\n");
                return TFAIL;
            }

            if (start_capturing() < 0)
            {
                printf("start_capturing failed\n");
                return TFAIL;
            }
            i = 0;
            printf("TV standard changed\n");
        } else {
            sleep(1);
            /* Try again */
            if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id)) {
                printf("VIDIOC_G_STD failed.\n");
                return TFAIL;
            }

            if (id != V4L2_STD_ALL)
                goto begin;

            printf("Cannot detect TV standard\n");
            return 0;
        }
next:
    memset(&capture_buf, 0, sizeof(capture_buf));
    capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    capture_buf.memory = V4L2_MEMORY_MMAP;
    if (ioctl(fd_capture_v4l, VIDIOC_DQBUF, &capture_buf) < 0)    {
        printf("VIDIOC_DQBUF failed.\n");
        return TFAIL;
    }

    memset(&output_buf, 0, sizeof(output_buf));
    output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    output_buf.memory = V4L2_MEMORY_MMAP;
    if (i < g_output_num_buffers) {
        output_buf.index = i;
        if (ioctl(fd_output_v4l, VIDIOC_QUERYBUF, &output_buf) < 0)
        {
            printf("VIDIOC_QUERYBUF failed\n");
            return TFAIL;
        }
    } else {
            output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
            output_buf.memory = V4L2_MEMORY_MMAP;
            if (ioctl(fd_output_v4l, VIDIOC_DQBUF, &output_buf) < 0)
            {
                printf("VIDIOC_DQBUF failed\n");
                return TFAIL;
            }
    }

        memcpy(output_buffers[output_buf.index].start, capture_buffers[capture_buf.index].start, g_frame_size);

        if (ioctl(fd_capture_v4l, VIDIOC_QBUF, &capture_buf) < 0) {
            printf("VIDIOC_QBUF failed\n");
            return TFAIL;
        }

        output_buf.timestamp.tv_sec = tv_start.tv_sec;
        output_buf.timestamp.tv_usec = tv_start.tv_usec + (g_frame_period * i);
                if (ioctl(fd_output_v4l, VIDIOC_QBUF, &output_buf) < 0)
                {
                        printf("VIDIOC_QBUF failed\n");
            return TFAIL;
                }

                if (i == 1) {
                        type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
                        if (ioctl(fd_output_v4l, VIDIOC_STREAMON, &type) < 0) {
                                printf("Could not start stream\n");
                return TFAIL;
                        }
                }
    }

        gettimeofday(&tv_current, 0);
        total_time = (tv_current.tv_sec - tv_start.tv_sec) * 1000000L;
        total_time += tv_current.tv_usec - tv_start.tv_usec;
        printf("total time for %u frames = %u us =  %lld fps\n", i, total_time, (i * 1000000ULL) / total_time);

    return 0;
}

int process_cmdline(int argc, char **argv)
{
        int i;

        for (i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-ow") == 0) {
            g_display_width = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "-oh") == 0) {
            g_display_height = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "-ot") == 0) {
            g_display_top = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "-ol") == 0) {
            g_display_left = atoi(argv[++i]);
        }
                else if (strcmp(argv[i], "-r") == 0) {
                        g_rotate = atoi(argv[++i]);
                }
                else if (strcmp(argv[i], "-f") == 0) {
                        i++;
                        g_fmt = v4l2_fourcc(argv[i][0], argv[i][1],argv[i][2],argv[i][3]);

            if ((g_fmt != V4L2_PIX_FMT_NV12) &&
                (g_fmt != V4L2_PIX_FMT_UYVY) &&
                (g_fmt != V4L2_PIX_FMT_YUYV) &&
                            (g_fmt != V4L2_PIX_FMT_YUV420))
                        {
                printf("Default format is used: UYVY\n");
                        }
                }
                else if (strcmp(argv[i], "-m") == 0) {
                        g_motion = atoi(argv[++i]);
                }
                else if (strcmp(argv[i], "-tb") == 0) {
                        g_tb = 1;
                }
                else if (strcmp(argv[i], "-help") == 0) {
                        printf("MXC Video4Linux TVin Test\n\n" \
                   "Syntax: mxc_v4l2_tvin.out\n" \
                   " -ow <capture display width>\n" \
                   " -oh <capture display height>\n" \
                   " -ot <display top>\n" \
                   " -ol <display left>\n" \
                               " -r <rotation> -c <capture counter> \n"
                   " -m <motion> 0:medium 1:low 2:high, 0-default\n"
                   " -tb top field first, bottom field first-default\n"
                   " -f <format, only YU12, YUYV, UYVY and NV12 are supported> \n");
                        return TFAIL;
               }
        }

        if ((g_display_width == 0) || (g_display_height == 0)) {
        printf("Zero display width or height\n");
                return TFAIL;
    }

        return 0;
}

int
main(int argc, char **argv)
{
        char fb_device[100] = "/dev/fb0";
        int fd_fb = 0, i;
        struct mxcfb_gbl_alpha alpha;
    enum v4l2_buf_type type;

        if (process_cmdline(argc, argv) < 0) {
                return TFAIL;
        }

        if ((fd_capture_v4l = open(v4l_capture_dev, O_RDWR, 0)) < 0)
        {
                printf("Unable to open %s\n", v4l_capture_dev);
                return TFAIL;
        }

    if ((fd_output_v4l = open(v4l_output_dev, O_RDWR, 0)) < 0)
    {
        printf("Unable to open %s\n", v4l_output_dev);
        return TFAIL;
    }

        if (v4l_capture_setup() < 0) {
                printf("Setup v4l capture failed.\n");
                return TFAIL;
    }

        if (v4l_output_setup() < 0) {
                printf("Setup v4l output failed.\n");
        close(fd_capture_v4l);
                return TFAIL;
    }

        if ((fd_fb = open(fb_device, O_RDWR )) < 0)    {
        printf("Unable to open frame buffer\n");
        close(fd_capture_v4l);
        close(fd_output_v4l);
                return TFAIL;
        }

        /* Overlay setting */
        alpha.alpha = 0;
    alpha.enable = 1;
    if (ioctl(fd_fb, MXCFB_SET_GBL_ALPHA, &alpha) < 0) {
        printf("Set global alpha failed\n");
        close(fd_fb);
        close(fd_capture_v4l);
        close(fd_output_v4l);
        return TFAIL;
    }

    mxc_v4l_tvin_test();

        type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        ioctl(fd_output_v4l, VIDIOC_STREAMOFF, &type);

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ioctl(fd_capture_v4l, VIDIOC_STREAMOFF, &type);

        for (i = 0; i < g_output_num_buffers; i++)
        {
                munmap(output_buffers[i].start, output_buffers[i].length);
        }
        for (i = 0; i < g_capture_num_buffers; i++)
        {
                munmap(capture_buffers[i].start, capture_buffers[i].length);
        }

    close(fd_capture_v4l);
    close(fd_output_v4l);
    close(fd_fb);
    return 0;
}

4

Вчера нарвался на понятие sub-device может кто-нибудь с ним встречался?

5

Когда-то немного поразвлекался с opencv и Python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cv

def main():
    capture = cv.CaptureFromCAM(-1)
    cv.NamedWindow("capture", cv.CV_WINDOW_AUTOSIZE)
    cv.NamedWindow("capture2", cv.CV_WINDOW_AUTOSIZE)

    while True:
        frame = cv.QueryFrame(capture)
        cv.ShowImage("capture", frame)
        cv.ShowImage("capture2", frame)
        cv.WaitKey(10)

    cv.DestroyWindow("capture")
    cv.DestroyWindow("capture2")
if __name__ == '__main__':
    main()

ЗЫ. Создаст два окошка с выводом с первой попавшейся камеры (одно окно над другим)
ЗЗЫ. Для работы необходим python-opencv

Да, у меня Ubuntu.
Нет, не глючит.

6

я вот не очень понимаю, на что ты выводишь изображение... что есть /dev/video16 физически? ТВ-тюльпан какой-нить? я как-то не думал, что на v4l-устройства вообще выводить видео можно...

в теории всё просто: чтобы вывести два одинаковых изображения надо в mxc_v4l_tvin_test() сделать memcpy() два раза друг за другом (второй со смещением)... соответственно надо где-то настроить размеры буферов (если они слишком маленькие)... вот только где и как именно я не скажу...

mibin пишет:

Вся фигня в том, что данная реализация поддерживает открытие устройства /dev/video16 (видеовыход) несколько раз (соответственно я завожу вторую переменную под устройство /dev/video16), НО при этом нельзя запустить поток (VIDIOC_STREAMON) на это устройство второй раз.

само собой... устройства открываются только один раз... драйвер может разрешить больше открытий, но для особых целей...

95% процентов проблем находятся между клавиатурой и стулом.

7 (03.02.2013 18:17:05 отредактировано mibin)

/dev/video16 - это LVDS монитор мой на который валится изображение.
v4l2 поддерживает как захват так и выбор и обработку изображения.

в теории всё просто: чтобы вывести два одинаковых изображения надо в mxc_v4l_tvin_test() сделать memcpy() два раза друг за другом (второй со смещением)... соответственно надо где-то настроить размеры буферов (если они слишком маленькие)... вот только где и как именно я не скажу...

ВООООТ и я до этого дошел!
Но вот вопрос как сделать memcpy со смещением? он разве не перезаписывает? приведите примерчик по гроб жизни буду вам благодарен, я прекрасно понимаю что нужно сделать именно так...но вот вопрос как...когда я делал буфер видеовыхода большим в два раза че буфер видеозахвата и пытался съэмулировать работу memcpy циклами for получал множественное наложение картинок...ну бред короче...возможно я не правильно описал работу memcpy а возможно еще в чем-то проблема...


по поводу значит opencv вся петрушка происходит на плате где нет x11 он по-моему без него не работает или я плохо его знаю.

8

Тут бы хотелось еще кое что понять...v4l2 выдает изображение в нашем случае обработанное им или нет.

mibin пишет:

   memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.pixelformat = g_fmt;
    fmt.fmt.pix.width = 0;
    fmt.fmt.pix.height = 0;
    if (ioctl(fd_capture_v4l, VIDIOC_S_FMT, &fmt) < 0)
    {
        printf("VIDIOC_S_FMT failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

Вот этот кусок когда в районе g_fmt указывает на определенный формат изображение (V4L2_PIX_FMT_YUYV, V4L2_PI_FMT_YU420 и т.д.)

9

Изменил код с memcpy вот на этот...нифига не полегчало...получилось именно то о чем я говорил...множественные наложения, фотку выложу после.

Тут возникает вопрос как именно идет отрисовка...

        memcpy(output_buffers[output_buf.index].start, capture_buffers[capture_buf.index].start, capture_buffers[capture_buf.index].length);
        memcpy(output_buffers[output_buf.index].start + capture_buffers[capture_buf.index].length, capture_buffers[capture_buf.index].start, capture_buffers[capture_buf.index].length);

10

Сделал две копии буфера с камеры, получил два неких файла...теперь бы понять по ним что это за формат...возможно копировать нужно не полностью...

11

mibin пишет:

/dev/video16 - это LVDS монитор мой на который валится изображение.
v4l2 поддерживает как захват так и выбор и обработку изображения.

странно, что он определяется не как обычное fb-устройство....

mibin пишет:

Но вот вопрос как сделать memcpy со смещением? он разве не перезаписывает? приведите примерчик по гроб жизни буду вам благодарен, я прекрасно понимаю что нужно сделать именно так...но вот вопрос как...когда я делал буфер видеовыхода большим в два раза че буфер видеозахвата и пытался съэмулировать работу memcpy циклами for получал множественное наложение картинок...ну бред короче...возможно я не правильно описал работу memcpy а возможно еще в чем-то проблема...

тут хорошо бы знать все размеры, чтобы не гадать...
распечатай вывод VIDIOC_G_FMT для обоих устройств после установки всех параметров, особенно интересуют размеры... а заодно и length для всех используемых буферов....

mibin пишет:

Тут возникает вопрос как именно идет отрисовка...

только g_frame_size, а не capture_buffers[capture_buf.index].length

memcpy(output_buffers[output_buf.index].start, capture_buffers[capture_buf.index].start, g_frame_size);
memcpy(output_buffers[output_buf.index].start + g_frame_size, capture_buffers[capture_buf.index].start, g_frame_size);
mibin пишет:

Сделал две копии буфера с камеры, получил два неких файла...теперь бы понять по ним что это за формат...возможно копировать нужно не полностью...

скорей всего там простой плоский файл т.е. RGB(A) [или какой там формат] последовательность байт...

ЗЫ: а библиотеки с обёртками для всех этих вызовов разве нет? а то ioctl'ы плохо читаются...

95% процентов проблем находятся между клавиатурой и стулом.

12

только g_frame_size, а не capture_buffers[capture_buf.index].length

Вот кстати фигня в том что если я выствляю g_frame_size то я славливаю segmentation failed.

Завтра после работы приложу все необходимые данные,
g_frame_size и размеры всех буферов, а заодно и файлики приложу.

а библиотеки с обёртками для всех этих вызовов разве нет? а то ioctl'ы плохо читаются...

Все что есть документация и более ничего...
Вот ссылка на нее http://linuxtv.org/downloads/v4l-dvb-apis/ если интересно, но в принципе готов пояснить любую часть кода.

13 (04.02.2013 11:35:55 отредактировано mibin)

Да, кстати, для простоты понимания ioctl:
VIDIOC_S_FMT -  это установить формат (об этом нам говорит буква S - SET в середине слова)
VIDIOC_G_FMT -  это получить формат (об этом нам говорит буква G - GET в середине слова)

Данный принцип действует по всей программе.

14 (04.02.2013 11:16:52 отредактировано mibin)

Путем расспросов смог выяснить что в буфере храниться информация только об изображении и никаких других данных там нет.
То в каком формате храниться изображение определяется методом которым мы указали открывать
Вот это будет наш тестовый случай (именно в таком формате возвращает данные ADV7180):
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY.

Слудующие действия будут такие...кодировка формата в RGB и вывод его через буфер /dev/fb0.
Частично готовый вариант выложу вечером.

15

mibin пишет:

Слудующие действия будут такие...кодировка формата в RGB

просто используй V4L2_PIX_FMT_RGB24 или 32.
если драйвер девайса будет кочебенится, то для этого вроде и есть libv4l из v4l-utils... документации у неё почти нет, но большая часть функций понятна по названиям...

95% процентов проблем находятся между клавиатурой и стулом.

16

Да вот поддерживаемый форматы только четыре и все они YUV ab так что кочебениться будет 100%
А по этому поводу сейчас почитаю посмотрю что такое libv4l

17 (04.02.2013 21:25:21 отредактировано mibin)

При переезде забыл кабеля...блин все тесты смогу выложить не раньше чем завтра.
НО я не могу откладывать разработку проекта поэтому дабы поддержать историзм выкладываю часть кода которой я собираюсь преобразовывать набор данных в картинку.
Вот этот код я буду использовать для преобразования массива данных в структуру YUV
Смысл данного кода прост, я беру сплошной набор данных и структурирую его согласно форма YUV на соответствующие составляющие, это нам понадобиться для дальнейшего преобразования картинки в RGB формат.
Ссыка на спецификацию данного формата: http://linuxtv.org/downloads/v4l-dvb-ap … -UYVY.html

// Format UYVY
struct tyuv { 
    char y,
    char u,
    char v
};
struct trgb { 
    char r,
    char g,
    char b
}
int p;
tyuv yuv[capture_buffers[0].length];
trgb rgb[capture_buffers[0].length];

// ************************************************
for (p = 1; p < capture_buffers[capture_buf.index].length; p += 2) {
    yuv[p].y = yuv((char *)capture_buffers[capture_buf.index].start)[p];
}
for (p = 0; p < capture_buffers[capture_buf.index].length-2; p+=4) {
  yuv[p].u = yuv((char *)capture_buffers[capture_buf.index].start)[p];
  yuv[p].v = yuv((char *)capture_buffers[capture_buf.index].start)[p+2];
}
// *************************************************

// ******* YUV to RGB ******************************
for (p = 1; p < capture_buffers[capture_buf.index].length; p += 2) {
    rgb[p].r = yuv[p].y + 1.140*yuv[p].v
    rgb[p].g = yuv[p].y - 0.395*yuv[p].u - 0.581*yuv[p].v
    rgb[p].b = yuv[p].y + 2.032*yuv[p].u
}
// *************************************************

Наверное некоторые меня спросят почему я не использовал функцию кодирования из библиотеки v4l2lib, ведь скорее всего там все функции перекодировки оптимизированы и будут работать полюбому быстрее.
Дело в том, что с данной функциональностью я не знаком и хочу реализовать ХОТЬ КАК-НИБУДЬ, для начала создадим проект функционирующий, а дальше имея что-то за душой сможем развивать его, оптимизировать дополнять и т.д.

18

mibin пишет:

for (p = 1; p < capture_buffers[capture_buf.index].length; p += 2) {
    yuv[p].y = yuv((char *)capture_buffers[capture_buf.index].start)[p];
}
for (p = 0; p < capture_buffers[capture_buf.index].length-2; p+=4) {
  yuv[p].u = yuv((char *)capture_buffers[capture_buf.index].start)[p];
  yuv[p].v = yuv((char *)capture_buffers[capture_buf.index].start)[p+2];
}

околесица какая-то... тем более, если формат именно V4L2_PIX_FMT_UYVY... даже если libv4l не хочешь использовать, то код конвертации уместно из него взять...

95% процентов проблем находятся между клавиатурой и стулом.

19 (04.02.2013 22:04:08 отредактировано mibin)

Cb00    Y'00        Cr00     Y'01       Cb01    Y'02       Cr01    Y'03
Cb10    Y'10        Cr10     Y'11       Cb11    Y'12     Cr11    Y'13
Cb20    Y'20        Cr20    Y'21     Cb21    Y'22       Cr21    Y'23
Cb30    Y'30        Cr30    Y'31     Cb31    Y'32       Cr31    Y'33

Почему околесица...вроде бы биты все подряд посчитал...
Блин хреново без платки-то...так бы сразу проверял бы че написал...

20

Я вот могу согласиться,что вот тут нужно использовать не capture_buffers[0].length в качестве размера

tyuv yuv[capture_buffers[0].length];
trgb rgb[capture_buffers[0].length];

а ширину * высоту

tyuv yuv[width*height];
trgb rgb[width*height];

21

БЛИН...ВО ТУПАНУЛ!!! ГОЛОВА БОЛИТ ПРОШУ ПРОЩЕНИЯ!! СЕЙЧАС ИСПРАВЛЮ ab

22

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <linux/videodev2.h>
#include <linux/fb.h>
#include <libv4l2.h>

void fprint_fb_screeninfo(FILE* fs, struct fb_fix_screeninfo *si) {
    fprintf(fs, "id:            %s  \n", si->id);
    fprintf(fs, "smem_start:    %p  \n", (void*)si->smem_start);
    fprintf(fs, "smem_len:      %u  \n", si->smem_len);
    fprintf(fs, "type:          %#0x\n", si->type);
    fprintf(fs, "type_aux:      %#0x\n", si->type_aux);
    fprintf(fs, "visual:        %#0x\n", si->visual);
    fprintf(fs, "xpanstep:      %u  \n", si->xpanstep);
    fprintf(fs, "ypanstep:      %u  \n", si->ypanstep);
    fprintf(fs, "ywrapstep:     %u  \n", si->ywrapstep);
    fprintf(fs, "line_length:   %u  \n", si->line_length);
    fprintf(fs, "mmio_start:    %p  \n", (void*)si->mmio_start);
    fprintf(fs, "mmio_len:      %u  \n", si->mmio_len);
    fprintf(fs, "accel:         %u  \n", si->accel);
    fprintf(fs, "capabilities:  %#0x\n", si->capabilities);
}

#define CASE_V4L2_FORMAT_TYPE_STR(type_str,type) case type: (type_str)=#type
#define UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, type) case type: \
    fprintf(fs, "type: %s \nUNSUPPORTED\n", #type); \
    break;

void fprint_v4l2_format(FILE* fs, struct v4l2_format *fmt) {
    const char* type_str="";

    switch(fmt->type) {
    CASE_V4L2_FORMAT_TYPE_STR(type_str, V4L2_BUF_TYPE_VIDEO_CAPTURE      );
        fprintf(fs, "type:          %s\n", type_str);
        fprintf(fs, "width:         %u\n", fmt->fmt.pix.width);
        fprintf(fs, "height:        %u\n", fmt->fmt.pix.height);
        fprintf(fs, "pixelformat:   %#0x(%c%c%c%c)\n", fmt->fmt.pix.pixelformat, 
                (fmt->fmt.pix.pixelformat >>  0) & 0xFF,
                (fmt->fmt.pix.pixelformat >>  8) & 0xFF,
                (fmt->fmt.pix.pixelformat >> 16) & 0xFF,
                (fmt->fmt.pix.pixelformat >> 24) & 0xFF);
        fprintf(fs, "field:         %u\n", fmt->fmt.pix.field);
        fprintf(fs, "bytesperline:  %u\n", fmt->fmt.pix.bytesperline);
        fprintf(fs, "sizeimage:     %u\n", fmt->fmt.pix.sizeimage);
        fprintf(fs, "colorspace:    %u\n", fmt->fmt.pix.colorspace);
        break;
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_VIDEO_OUTPUT       );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_VIDEO_OVERLAY      );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_VBI_CAPTURE        );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_VBI_OUTPUT         );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT  );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  );
    UNSUPPORTED_CASE_V4L2_FORMAT_TYPE_STR(fs, V4L2_BUF_TYPE_PRIVATE              );    
    }
}

int main(int argc, char** argv) {
    int rc;
    int i,j;

    char *dev_name;
    int dev_fd;
    uint8_t* dev_buf;
    struct v4l2_format fmt;

    const char *fb_name="/dev/fb0";
    int fb_fd;
    struct fb_fix_screeninfo fb_si;
    uint8_t* fb_buf;


    if(argc != 2) {
        fprintf(stderr, "Usage: %s /dev/videoX\n", argv[0]);
        return EXIT_FAILURE;
    }
    
    dev_name = argv[1];

    dev_fd = v4l2_open(dev_name, O_RDWR);
    if( dev_fd == -1 ) {
        fprintf(stderr, "open %s failed: %s\n", dev_name, strerror(errno));
        return EXIT_FAILURE;
    }

    fb_fd = open(fb_name, O_RDWR);
    if( fb_fd == -1 ) {
        fprintf(stderr, "open %s failed: %s\n", fb_name, strerror(errno));
        return EXIT_FAILURE;
    }

    memset( &fb_si, 0, sizeof(fb_si));
    rc = ioctl( fb_fd, FBIOGET_FSCREENINFO, &fb_si);
    if(rc < 0) {
        fprintf(stderr, "FBIOGET_FSCREENINFO failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

#if 0 // print framebuffer info
    printf("===== %s ======\n", fb_name);
    fprint_fb_screeninfo(stdout, &fb_si);
#endif // 0 

    fb_buf=mmap(0, fb_si.smem_len, PROT_WRITE|PROT_READ,
                       MAP_SHARED, fb_fd, 0);
    if(fb_buf == (void*) -1) {
        fprintf(stderr, "mmap %d(%s) failed: %s\n", fb_fd, fb_name, strerror(errno));
        return EXIT_FAILURE;
    }

#if 0 // try to draw garbage on framebuffer
    int i=0,j=0;
    for(i=0; i<100*4;i++) {
        for(j=0; j<100;j++) {
            fb_buf[i+j*fb_si.line_length]=rand() % 256;
        }
    }
    
    sleep(10);
#endif

#if 0 // print current v4l2 format
    memset(&fmt, 0, sizeof(struct v4l2_format));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    rc = v4l2_ioctl(dev_fd, VIDIOC_G_FMT, &fmt);
    if(rc < 0) {
        fprintf(stderr, "ioctl VIDIOC_G_FMT on %s failed: %s\n", dev_name, strerror(errno));
        return EXIT_FAILURE;
    }

    printf("===== %s: format =====\n", dev_name);
    fprint_v4l2_format(stdout, &fmt);
#endif // 0 

#if 1 // enumerate all supported image formats by the !device! not v4l
    struct v4l2_fmtdesc fmtdsc;
    for(i=0; ;i++) {
        fmtdsc.index = i;
        fmtdsc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        rc = ioctl(dev_fd, VIDIOC_ENUM_FMT, &fmtdsc);
        // NOTE: you can compare this to the output of v4l2_ioctl
        if( rc<0 ) {
            if(errno==EINVAL) {
                errno=0;
                break;
            } else {
                fprintf(stderr, "ioctl VIDIOC_ENUM_FMT on %s failed: %s\n", dev_name, strerror(errno));
                return EXIT_FAILURE;
            }
        }

        printf("%3d| %c%c%c%c| %32s| %s%s\n", 
                fmtdsc.index, 
                (fmtdsc.pixelformat >>  0) & 0xFF,
                (fmtdsc.pixelformat >>  8) & 0xFF,
                (fmtdsc.pixelformat >> 16) & 0xFF,
                (fmtdsc.pixelformat >> 24) & 0xFF,
                fmtdsc.description,
                fmtdsc.flags & V4L2_FMT_FLAG_COMPRESSED ? " Comressed" : "",
                fmtdsc.flags & V4L2_FMT_FLAG_EMULATED   ? " Emulated" : "");
    }
#endif
    
    memset(&fmt, 0, sizeof(struct v4l2_format));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width  = 400;
    fmt.fmt.pix.height = 300;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;

    rc = v4l2_ioctl(dev_fd, VIDIOC_S_FMT, &fmt);
    if(rc < 0) {
        fprintf(stderr, "ioctl VIDIOC_S_FMT on %s failed: %s\n", dev_name, strerror(errno));
        return EXIT_FAILURE;
    }
    printf("===== %s: format =====\n", dev_name);
    fprint_v4l2_format(stdout, &fmt);
    
    for(i=0; i<9000; i++) {
        size_t sz, buf_sz = fmt.fmt.pix.width * fmt.fmt.pix.height * 3;
        dev_buf = malloc(buf_sz);
        sz = v4l2_read(dev_fd, dev_buf, buf_sz);
        if(sz != buf_sz) {
            fprintf(stderr, "%s: readed %lu instead of %lu bytes. error %d: %s\n", 
                        dev_name, sz, buf_sz, errno, strerror(errno));
            return EXIT_FAILURE;
        }
        for(i=0; i<fmt.fmt.pix.height; i++) {
            for(j=0; j<fmt.fmt.pix.width; j++) {
                fb_buf[i*fb_si.line_length + j * 4    ] = dev_buf[(i*fmt.fmt.pix.width + j)*3    ];
                fb_buf[i*fb_si.line_length + j * 4 + 1] = dev_buf[(i*fmt.fmt.pix.width + j)*3 + 1];
                fb_buf[i*fb_si.line_length + j * 4 + 2] = dev_buf[(i*fmt.fmt.pix.width + j)*3 + 2];
                
#if 0 // print the second frame right under the first one
    // NOTE: if image is larger than the framebuffer, this can cause SIGFAULT
                fb_buf[i*fb_si.line_length + j * 4     + fb_si.line_length * fmt.fmt.pix.height] = 
                        dev_buf[(i*fmt.fmt.pix.width + j)*3    ];
                fb_buf[i*fb_si.line_length + j * 4 + 1 + fb_si.line_length * fmt.fmt.pix.height] = 
                        dev_buf[(i*fmt.fmt.pix.width + j)*3 + 1];
                fb_buf[i*fb_si.line_length + j * 4 + 2 + fb_si.line_length * fmt.fmt.pix.height] = 
                        dev_buf[(i*fmt.fmt.pix.width + j)*3 + 2];
#endif
            }
        }
        usleep(1000/30);
    }
    
    free(dev_buf);
    munmap(fb_buf, fb_si.smem_len);
    v4l2_close(dev_fd);
    close(fb_fd);
    return EXIT_SUCCESS;
}

накидал тут небольшой пример, выводящий с помощью libv4l2 в фреймбуфер...
в ifdef'ах парочка дополнительных возможностей, которые можно включить или выключить...
прелесть в том, что от обычного v4l2-Фзш почти не отличается, зато есть несколько форматов, в которые всё конвертируется налету...

95% процентов проблем находятся между клавиатурой и стулом.

23 (06.02.2013 09:34:30 отредактировано mibin)

Достаточно интересный пример.
Попробую разобраться в нем. С ничем похожим я пока в инете не встречался, когда искал доку и примеры по v4l2. Хотя может у меня интернет особенный ab

Однако одна бессонная ночь дала результаты. Есть две новости:
1 - Драйвер етить его поддерживает формат RGB32, RGB24 (а так же их синонимы BGR)и еще какой-то RGB из всего перечисленного списка в документации к v4l2. Более того он не просто поддерживает ОН! картинку выводит ровно прям именно так как надо (правда только с форматом RGB32), одна засада - стоит какая-то голубая дымка, ничего похоже не наблюдается при использовании форматов YUV.
2 - Мой мозг и я решительно задолбались кодить формат UYVY, поэтому я стал использовать для захвата изображения форма YUV420 и конвертил его в RGB следующим кодом:

char clamp (int x) {
    if (x>255) return 255;
    if (x<0) return 0;
    return x;
}

void showFrame(const void *p, size_t length)
{
    printf ("show frame called\n");
       
        // -------- working with display --------------------

    printf ("image received, length=%d\n", length);
    char s[4096];  
    sprintf (s,"");

    printf ("now displaying...\n");
       
   
    int width=g_in_width;
    int height=g_in_heigth;
    
    long size = width*height;
 
// pixel format = 24bit
    char i420[length];
 
    typedef struct {
            char y, u, v;
            } Tyuv ;
            
    typedef struct  {
            char r;
            char g;
            char b;
            }  Trgb;
            
    Tyuv yuv[size];
    Trgb rgb[size];  
    printf ("copying buffer to i420 array\n");
   int i;
 
    for(i = 0; i < length; i++ ) {
        i420[i] = *(char *)p++;
    }
    printf ("copying Y\n");
 
    for(i = 0; i < width*height; i++ ) {
        yuv[i].y = i420[i];
    }
    
    int Counter = 0;
 
    printf ("copying U and V\n");
    for(i = 0; i < width*height/4; i++ )
    {
       yuv[Counter].u                  =
       yuv[Counter + 1].u              =
       yuv[Counter + width].u     =
       yuv[Counter + width + 1].u = i420[width*height + i];
 
       yuv[Counter].v                  =
       yuv[Counter + 1].v              =
       yuv[Counter + width].v     =
       yuv[Counter + width + 1].v = i420[width*height + i + width*height/4];
 
       Counter += 2;
       if( Counter%width == 0 )
           if( (Counter/width)%2 != 0 )
                Counter += width;
  }
 

    printf ("converting yuv to rgb\n");
 
    for( i = 0; i < size; i++ ) {
        int C,D,E;
        int Y= yuv[i].y;
        int U= yuv[i].u;  
        int V= yuv[i].v;  
        C = Y - 16;
        D = U - 128;
        E = V - 128;
   
 
       char R = clamp((int) ( 298 * C + 409 * E + 128) >> 8);
       char G = clamp((int) ( 298 * C - 100 * D - 208 * E + 128) >> 8);
       char B = clamp((int) ( 298 * C + 516 * D + 128) >> 8);        
       rgb[i].r = R;
       rgb[i].g = G;
       rgb[i].b = B;
    }
    int c=0;
    int x,y;
    printf ("displaying rgb to screen\n");
         
    int screenwidth=800;
    int screenheight = 480;
 
    for( y = 0; y < screenheight; y++ )
    {      
        for(x = 0; x < screenwidth; x++)
        {
            if ( (x<width) && (y<height) ) {
                    ((__u8*)fb)[c++] = rgb[y*width + x].b;       // Blue
                    ((__u8*)fb)[c++] = rgb[y*width + x].g;       // Green
                    ((__u8*)fb)[c++] = rgb[y*width + x].r;       // Red
            }
            else c+=3;
        }
    }  
    return ;
}

код этот принадлежит не мне и его еще стоит оптимизировать, но как видно формат YUV420 гораздо проще поддается обработке.

Вроде бы получил даже картинку...что в итоге получилось выложу вечером, следующий этап это вывод двух картинок, что на самом деле с таким кодом не должно представлять большого труда, ну а потом попробую освоить функцию конвертации форматов от v4l2.

24

mibin пишет:

1 - Драйвер етить его поддерживает формат RGB32, RGB24 (а так же их синонимы BGR)и еще какой-то RGB из всего перечисленного списка в документации к v4l2. Более того он не просто поддерживает ОН! картинку выводит ровно прям именно так как надо (правда только с форматом RGB32), одна засада - стоит какая-то голубая дымка, ничего похоже не наблюдается при использовании форматов YUV.

если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)

mibin пишет:

2 - Мой мозг и я решительно задолбались кодить формат UYVY, поэтому я стал использовать для захвата изображения форма YUV420

вот зачем изобретать велосипед... есть же готовый код в исходниках libv4l...

95% процентов проблем находятся между клавиатурой и стулом.

25 (11.02.2013 21:47:10 отредактировано mibin)

Наконец-то я смог завершить свою эпопею, прошу прощения, что так долго не отвечал.
В общем, данный код выводит 4 изображения  на экран, в общем имея 4 разных буфера можно выкидывать изображение 4 различных изображения.

Запускать надо следующим образом на платах с ARM (ну это в моем случае, в Вашем может потребоваться небольшая доработка, какая зависит от конкретного случая):

./memcpy -ow 640 -oh 480 -ol 0 -ot 0 -f YUV12 

Вот сам код:

/*
 * Copyright 2007-2011 Freescale Semiconductor, Inc. All rights reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

/*
 * @file mxc_v4l2_tvin.c
 *
 * @brief Mxc TVIN For Linux 2 driver test application
 *
 */

#ifdef __cplusplus
extern "C"{
#endif

/*=======================================================================
                                        INCLUDE FILES
=======================================================================*/
/* Standard Include Files */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

/* Verification Test Environment Include Files */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <asm/types.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <math.h>
#include <string.h>
#include <malloc.h>

#include <linux/mxcfb.h>

#define TFAIL -1
#define TPASS 0

char v4l_capture_dev[100] = "/dev/video0";
char v4l_output_dev[100] = "/dev/video16";
int fd_capture_v4l = 0;
int fd_output_v4l = 0;
int g_cap_mode = 0;
int g_input = 1;
int g_fmt = V4L2_PIX_FMT_UYVY;
int g_fmt2 = V4L2_PIX_FMT_YUV420;
int g_rotate = 0;
int g_motion = 0;
int g_tb = 0;
int g_output = 3;
int g_output_num_buffers = 4;
int g_capture_num_buffers = 3;
int g_in_width = 0;
int g_in_height = 0;
int g_display_width = 0;
int g_display_height = 0;
int g_display_top = 0;
int g_display_left = 0;
int g_frame_size;
int g_frame_period = 33333;
v4l2_std_id g_current_std = V4L2_STD_PAL;

struct testbuffer
{
        unsigned char *start;
        size_t offset;
        unsigned int length;
};

struct testbuffer output_buffers[4];
struct testbuffer capture_buffers[3];

int start_capturing(void)
{
        unsigned int i;
        struct v4l2_buffer buf;
        enum v4l2_buf_type type;

        for (i = 0; i < g_capture_num_buffers; i++)
        {
                memset(&buf, 0, sizeof (buf));
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.index = i;
                if (ioctl(fd_capture_v4l, VIDIOC_QUERYBUF, &buf) < 0)
                {
                        printf("VIDIOC_QUERYBUF error\n");
                        return TFAIL;
                }

                capture_buffers[i].length = buf.length;
                capture_buffers[i].offset = (size_t) buf.m.offset;
                capture_buffers[i].start = mmap (NULL, capture_buffers[i].length,
                    PROT_READ | PROT_WRITE, MAP_SHARED,
                    fd_capture_v4l, capture_buffers[i].offset);
        memset(capture_buffers[i].start, 0xFF, capture_buffers[i].length);
        }

        for (i = 0; i < g_capture_num_buffers; i++)
        {
                memset(&buf, 0, sizeof (buf));
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;
                buf.index = i;
        buf.m.offset = capture_buffers[i].offset;
                if (ioctl (fd_capture_v4l, VIDIOC_QBUF, &buf) < 0) {
                        printf("VIDIOC_QBUF error\n");
                        return TFAIL;
                }
        }

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if (ioctl (fd_capture_v4l, VIDIOC_STREAMON, &type) < 0) {
                printf("VIDIOC_STREAMON error\n");
                return TFAIL;
        }
        return 0;
}

int prepare_output(void)
{
    int i;
        struct v4l2_buffer output_buf;

        for (i = 0; i < g_output_num_buffers; i++)
        {
                memset(&output_buf, 0, sizeof(output_buf));
                output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
                output_buf.memory = V4L2_MEMORY_MMAP;
                output_buf.index = i;
                if (ioctl(fd_output_v4l, VIDIOC_QUERYBUF, &output_buf) < 0)
                {
                        printf("VIDIOC_QUERYBUF error\n");
            return TFAIL;
                }

                output_buffers[i].length = output_buf.length;
                output_buffers[i].offset = (size_t) output_buf.m.offset;
                output_buffers[i].start = mmap (NULL, output_buffers[i].length,
                                         PROT_READ | PROT_WRITE, MAP_SHARED,
                                         fd_output_v4l, output_buffers[i].offset);
                if (output_buffers[i].start == NULL) {
                        printf("v4l2 tvin test: output mmap failed\n");
            return TFAIL;
                }
        }
    return 0;
}

int v4l_capture_setup(void)
{
    struct v4l2_dbg_chip_ident chip;
    struct v4l2_format fmt;
    struct v4l2_streamparm parm;
        struct v4l2_requestbuffers req;
    v4l2_std_id id;

    if (ioctl(fd_capture_v4l, VIDIOC_DBG_G_CHIP_IDENT, &chip))
    {
                printf("VIDIOC_DBG_G_CHIP_IDENT failed.\n");
        close(fd_capture_v4l);
                return TFAIL;
    }
    printf("TV decoder chip is %s\n", chip.match.name);

    if (ioctl(fd_capture_v4l, VIDIOC_S_INPUT, &g_input) < 0)
    {
        printf("VIDIOC_S_INPUT failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id) < 0)
    {
        printf("VIDIOC_G_STD failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }
    g_current_std = id;

    if (ioctl(fd_capture_v4l, VIDIOC_S_STD, &id) < 0)
    {
        printf("VIDIOC_S_STD failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    parm.parm.capture.timeperframe.numerator = 1;
    parm.parm.capture.timeperframe.denominator = 0;
    parm.parm.capture.capturemode = 0;
    if (ioctl(fd_capture_v4l, VIDIOC_S_PARM, &parm) < 0)
    {
        printf("VIDIOC_S_PARM failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.pixelformat = g_fmt2;
    fmt.fmt.pix.width = 0;
    fmt.fmt.pix.height = 0;
    if (ioctl(fd_capture_v4l, VIDIOC_S_FMT, &fmt) < 0)
    {
        printf("VIDIOC_S_FMT failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    if (ioctl(fd_capture_v4l, VIDIOC_G_FMT, &fmt) < 0)
    {
        printf("VIDIOC_G_FMT failed\n");
        close(fd_capture_v4l);
        return TFAIL;
    }

    g_in_width = fmt.fmt.pix.width;
    g_in_height = fmt.fmt.pix.height;

        memset(&req, 0, sizeof (req));
        req.count = g_capture_num_buffers;
        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_MMAP;
        if (ioctl(fd_capture_v4l, VIDIOC_REQBUFS, &req) < 0)
        {
                printf("VIDIOC_REQBUFS failed\n");
        close(fd_capture_v4l);
                return TFAIL;
        }

        return 0;
}

int v4l_output_setup(void)
{
    struct v4l2_control ctrl;
    struct v4l2_format fmt;
    struct v4l2_framebuffer fb;
    struct v4l2_cropcap cropcap;
    struct v4l2_crop crop;
    struct v4l2_requestbuffers buf_req;

        if (ioctl(fd_output_v4l, VIDIOC_S_OUTPUT, &g_output) < 0)
        {
                printf("set output failed\n");
                return TFAIL;
        }

        memset(&cropcap, 0, sizeof(cropcap));
        cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        if (ioctl(fd_output_v4l, VIDIOC_CROPCAP, &cropcap) < 0)
        {
                printf("get crop capability failed\n");
                return TFAIL;
        }

        crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        crop.c.top = g_display_top;
        crop.c.left = g_display_left;
        crop.c.width = g_display_width;
        crop.c.height = g_display_height;
        if (ioctl(fd_output_v4l, VIDIOC_S_CROP, &crop) < 0)
        {
                printf("set crop failed\n");
                return TFAIL;
        }

        ctrl.id = V4L2_CID_PRIVATE_BASE;
        ctrl.value = g_rotate;
        if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
        {
                printf("set ctrl failed\n");
        return TFAIL;
        }

    ctrl.id = V4L2_CID_PRIVATE_BASE + 3;
        ctrl.value = g_motion;
        if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
        {
                printf("set ctrl failed\n");
        return TFAIL;
        }

    fb.flags = V4L2_FBUF_FLAG_OVERLAY;
    ioctl(fd_output_v4l, VIDIOC_S_FBUF, &fb);

    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    fmt.fmt.pix.width= g_in_width*2;
    fmt.fmt.pix.height= g_in_height*2;
    fmt.fmt.pix.pixelformat = g_fmt2;
    fmt.fmt.pix.bytesperline = g_in_width*2;
    fmt.fmt.pix.priv = 0;
    fmt.fmt.pix.sizeimage = 0;
    if (g_tb)
        fmt.fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
    else
        fmt.fmt.pix.field = V4L2_FIELD_INTERLACED_BT;
        if (ioctl(fd_output_v4l, VIDIOC_S_FMT, &fmt) < 0)
        {
                printf("set format failed\n");
                return TFAIL;
        }

        if (ioctl(fd_output_v4l, VIDIOC_G_FMT, &fmt) < 0)
        {
                printf("get format failed\n");
                return TFAIL;
        }
        g_frame_size = fmt.fmt.pix.sizeimage;

        memset(&buf_req, 0, sizeof(buf_req));
        buf_req.count = g_output_num_buffers;
        buf_req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        buf_req.memory = V4L2_MEMORY_MMAP;
        if (ioctl(fd_output_v4l, VIDIOC_REQBUFS, &buf_req) < 0)
        {
                printf("request buffers failed\n");
                return TFAIL;
        }

    return 0;
}

int
mxc_v4l_tvin_test(void)
{
        struct v4l2_buffer capture_buf, output_buf;
    v4l2_std_id id;
        int i, j;
    enum v4l2_buf_type type;
        int total_time;
        struct timeval tv_start, tv_current;

    if (prepare_output() < 0)
    {
        printf("prepare_output failed\n");
        return TFAIL;
    }

    if (start_capturing() < 0)
    {
        printf("start_capturing failed\n");
        return TFAIL;
    }

    gettimeofday(&tv_start, 0);
    printf("start time = %d s, %d us\n", tv_start.tv_sec, tv_start.tv_usec);

    for (i = 0; ; i++) {
begin:
        if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id)) {
                        printf("VIDIOC_G_STD failed.\n");
            return TFAIL;
        }

        if (id == g_current_std)
            goto next;
        else if (id == V4L2_STD_PAL || id == V4L2_STD_NTSC) {
            type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
            ioctl(fd_output_v4l, VIDIOC_STREAMOFF, &type);

            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            ioctl(fd_capture_v4l, VIDIOC_STREAMOFF, &type);

            for (j = 0; j < g_output_num_buffers; j++)
            {
                munmap(output_buffers[j].start, output_buffers[j].length);
            }
            for (j = 0; j < g_capture_num_buffers; j++)
            {
                munmap(capture_buffers[j].start, capture_buffers[j].length);
            }

            if (v4l_capture_setup() < 0) {
                printf("Setup v4l capture failed.\n");
                return TFAIL;
            }

            if (v4l_output_setup() < 0) {
                printf("Setup v4l output failed.\n");
                return TFAIL;
            }

            if (prepare_output() < 0)
            {
                printf("prepare_output failed\n");
                return TFAIL;
            }

            if (start_capturing() < 0)
            {
                printf("start_capturing failed\n");
                return TFAIL;
            }
            i = 0;
            printf("TV standard changed\n");
        } else {
            sleep(1);
            /* Try again */
            if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id)) {
                printf("VIDIOC_G_STD failed.\n");
                return TFAIL;
            }

            if (id != V4L2_STD_ALL)
                goto begin;

            printf("Cannot detect TV standard\n");
            return 0;
        }
next:
                memset(&capture_buf, 0, sizeof(capture_buf));
                capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                capture_buf.memory = V4L2_MEMORY_MMAP;
                if (ioctl(fd_capture_v4l, VIDIOC_DQBUF, &capture_buf) < 0)    {
                        printf("VIDIOC_DQBUF failed.\n");
            return TFAIL;
                }

                memset(&output_buf, 0, sizeof(output_buf));
                output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
                output_buf.memory = V4L2_MEMORY_MMAP;
                if (i < g_output_num_buffers) {
                        output_buf.index = i;
                        if (ioctl(fd_output_v4l, VIDIOC_QUERYBUF, &output_buf) < 0)
                        {
                                printf("VIDIOC_QUERYBUF failed\n");
                return TFAIL;
                        }
                } else {
                        output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
                        output_buf.memory = V4L2_MEMORY_MMAP;
                        if (ioctl(fd_output_v4l, VIDIOC_DQBUF, &output_buf) < 0)
                        {
                                printf("VIDIOC_DQBUF failed\n");
                return TFAIL;
                        }
                }
        printf("Prepare copy buf.\n");

        memset(output_buffers[output_buf.index].start, 0, sizeof(output_buffers[output_buf.index].length));
        int p;
        int k = 0;

        for (p=0; p<g_in_height; p++) {
            memcpy(output_buffers[output_buf.index].start + k*g_in_width,              capture_buffers[capture_buf.index].start + p*g_in_width, g_in_width);
            memcpy(output_buffers[output_buf.index].start + k*g_in_width + g_in_width, capture_buffers[capture_buf.index].start + p*g_in_width, g_in_width);

            memcpy(output_buffers[output_buf.index].start + k*g_in_width              + 2*g_in_width*g_in_height,  capture_buffers[capture_buf.index].start + p*g_in_width, g_in_width);
            memcpy(output_buffers[output_buf.index].start + k*g_in_width + g_in_width + 2*g_in_width*g_in_height,  capture_buffers[capture_buf.index].start + p*g_in_width, g_in_width);
            k+=2;
        }

        for (p=0; p<g_in_height/2; p++) {
            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2),                capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);
            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2) + g_in_width/2, capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);

            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2) + (g_in_width*g_in_height)/2,                capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);
            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2) + g_in_width/2 + (g_in_width*g_in_height)/2, capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);

            k+=2;
        }
        k = 0;
        for (p=g_in_height/2; p<g_in_height; p++) {
            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2),                capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);
            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2) + g_in_width/2, capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);

            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2) + (g_in_width*g_in_height)/2,                capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);
            memcpy(output_buffers[output_buf.index].start + 4*g_in_width*g_in_height + k*(g_in_width/2) + g_in_width/2 + (g_in_width*g_in_height)/2, capture_buffers[capture_buf.index].start + (g_in_width*g_in_height + p*(g_in_width/2)), g_in_width/2);

            k+=2;
        }

        if (ioctl(fd_capture_v4l, VIDIOC_QBUF, &capture_buf) < 0) {
            printf("VIDIOC_QBUF failed\n");
            return TFAIL;
        }

        output_buf.timestamp.tv_sec = tv_start.tv_sec;
        output_buf.timestamp.tv_usec = tv_start.tv_usec + (g_frame_period * i);
                if (ioctl(fd_output_v4l, VIDIOC_QBUF, &output_buf) < 0)
                {
                        printf("VIDIOC_QBUF failed\n");
            return TFAIL;
                }

                if (i == 1) {
                    type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
                    if (ioctl(fd_output_v4l, VIDIOC_STREAMON, &type) < 0) {
                        printf("Could not start stream\n");
                        return TFAIL;
                    }
                }
    }

        gettimeofday(&tv_current, 0);
        total_time = (tv_current.tv_sec - tv_start.tv_sec) * 1000000L;
        total_time += tv_current.tv_usec - tv_start.tv_usec;
        printf("total time for %u frames = %u us =  %lld fps\n", i, total_time, (i * 1000000ULL) / total_time);

    return 0;
}

int process_cmdline(int argc, char **argv)
{
        int i;

        for (i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-ow") == 0) {
            g_display_width = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "-oh") == 0) {
            g_display_height = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "-ot") == 0) {
            g_display_top = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "-ol") == 0) {
            g_display_left = atoi(argv[++i]);
        }
                else if (strcmp(argv[i], "-r") == 0) {
                        g_rotate = atoi(argv[++i]);
                }
                else if (strcmp(argv[i], "-f") == 0) {
                        i++;
                        g_fmt = v4l2_fourcc(argv[i][0], argv[i][1],argv[i][2],argv[i][3]);

            if ((g_fmt != V4L2_PIX_FMT_NV12) &&
                (g_fmt != V4L2_PIX_FMT_UYVY) &&
                (g_fmt != V4L2_PIX_FMT_YUYV) &&
                            (g_fmt != V4L2_PIX_FMT_YUV420))
                        {
                printf("Default format is used: UYVY\n");
                        }
                }
                else if (strcmp(argv[i], "-m") == 0) {
                        g_motion = atoi(argv[++i]);
                }
                else if (strcmp(argv[i], "-tb") == 0) {
                        g_tb = 1;
                }
                else if (strcmp(argv[i], "-help") == 0) {
                        printf("MXC Video4Linux TVin Test\n\n" \
                   "Syntax: mxc_v4l2_tvin.out\n" \
                   " -ow <capture display width>\n" \
                   " -oh <capture display height>\n" \
                   " -ot <display top>\n" \
                   " -ol <display left>\n" \
                               " -r <rotation> -c <capture counter> \n"
                   " -m <motion> 0:medium 1:low 2:high, 0-default\n"
                   " -tb top field first, bottom field first-default\n"
                   " -f <format, only YU12, YUYV, UYVY and NV12 are supported> \n");
                        return TFAIL;
               }
        }

        if ((g_display_width == 0) || (g_display_height == 0)) {
        printf("Zero display width or height\n");
                return TFAIL;
    }

        return 0;
}

int
main(int argc, char **argv)
{
        char fb_device[100] = "/dev/fb0";
        int fd_fb = 0, i;
        struct mxcfb_gbl_alpha alpha;
    enum v4l2_buf_type type;

        if (process_cmdline(argc, argv) < 0) {
                return TFAIL;
        }

        if ((fd_capture_v4l = open(v4l_capture_dev, O_RDWR, 0)) < 0)
        {
                printf("Unable to open %s\n", v4l_capture_dev);
                return TFAIL;
        }

    if ((fd_output_v4l = open(v4l_output_dev, O_RDWR, 0)) < 0)
    {
        printf("Unable to open %s\n", v4l_output_dev);
        return TFAIL;
    }

        if (v4l_capture_setup() < 0) {
                printf("Setup v4l capture failed.\n");
                return TFAIL;
    }

        if (v4l_output_setup() < 0) {
                printf("Setup v4l output failed.\n");
        close(fd_capture_v4l);
                return TFAIL;
    }

        if ((fd_fb = open(fb_device, O_RDWR )) < 0)    {
        printf("Unable to open frame buffer\n");
        close(fd_capture_v4l);
        close(fd_output_v4l);
                return TFAIL;
        }

        /* Overlay setting */
        alpha.alpha = 0;
    alpha.enable = 1;
    if (ioctl(fd_fb, MXCFB_SET_GBL_ALPHA, &alpha) < 0) {
        printf("Set global alpha failed\n");
        close(fd_fb);
        close(fd_capture_v4l);
        close(fd_output_v4l);
        return TFAIL;
    }

    mxc_v4l_tvin_test();

        type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        ioctl(fd_output_v4l, VIDIOC_STREAMOFF, &type);

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ioctl(fd_capture_v4l, VIDIOC_STREAMOFF, &type);

        for (i = 0; i < g_output_num_buffers; i++)
        {
                munmap(output_buffers[i].start, output_buffers[i].length);
        }
        for (i = 0; i < g_capture_num_buffers; i++)
        {
                munmap(capture_buffers[i].start, capture_buffers[i].length);
        }

    close(fd_capture_v4l);
    close(fd_output_v4l);
    close(fd_fb);
    return 0;
}

В общем-то все просто, буфер видевыхода больше в 4 раза буфера видеовхода что и позволило запихнуть картинку 4 раза в него.

Вот ссылка на формат, там его описание и как именно хранятся данные в нем:
http://linuxtv.org/downloads/v4l-dvb-apis/re23.html

Вот конечный результат, который я получил на своем агрегате:
http://s019.radikal.ru/i633/1302/43/9699fa476c94.jpg

К сожаления, на этом приключения не заканчиваются, я чуток позже я создам новый топик по доработке драйвера устройства, надеюсь на такую же активную поддержку, отныне постараюсь и сам внести свой вклад в развитие нации на форуме... ВСЕМ ОГРОМНОЕ СПАСИБО!!!

26

mibin пишет:

Вот конечный результат, который я получил на своем агрегате:

а то что всё синее тебя не смущает?

Fat-Zer пишет:

если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)

95% процентов проблем находятся между клавиатурой и стулом.

27

а то что всё синее тебя не смущает?

Нет, цвет вполне реалистичный, это просто цветопередача на камере мобилки так сработала.

28

Fat-Zer пишет:

если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)

Тут все просто, конвертит все внутри себя v4l2 я ему сказал что формат изображение YUV420 на входе и на выходе, а далее он сам разбирается как это ему выводить, все что я сделал это собрал картинку в нужном порядке в буфере выдеовыхода (output_buffers).