LinuxForum.Fans
Тема

Video4Linux2. Вывод нескольких буферов.

Автор: mibin 28 сообщений 6513 просмотров
#300707

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

#300966
text
#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-Фзш почти не отличается, зато есть несколько форматов, в которые всё конвертируется налету...

#300977

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

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

text
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.

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

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

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

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

#302081

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

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

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

Вот сам код:

text
/*
 * 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

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


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

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

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

"Fat-Zer" написал:
если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)
#302145

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

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

#302146
"Fat-Zer" написал:
если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)

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

Войдите или зарегистрируйтесь, чтобы ответить.