БЛИН...ВО ТУПАНУЛ!!! ГОЛОВА БОЛИТ ПРОШУ ПРОЩЕНИЯ!! СЕЙЧАС ИСПРАВЛЮ :)
Video4Linux2. Вывод нескольких буферов.
#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-Фзш почти не отличается, зато есть несколько форматов, в которые всё конвертируется налету...
Достаточно интересный пример.
Попробую разобраться в нем. С ничем похожим я пока в инете не встречался, когда искал доку и примеры по v4l2. Хотя может у меня интернет особенный :)
Однако одна бессонная ночь дала результаты. Есть две новости:
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.
1 - Драйвер етить его поддерживает формат RGB32, RGB24 (а так же их синонимы BGR)и еще какой-то RGB из всего перечисленного списка в документации к v4l2. Более того он не просто поддерживает ОН! картинку выводит ровно прям именно так как надо (правда только с форматом RGB32), одна засада - стоит какая-то голубая дымка, ничего похоже не наблюдается при использовании форматов YUV.
если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)
2 - Мой мозг и я решительно задолбались кодить формат UYVY, поэтому я стал использовать для захвата изображения форма YUV420
вот зачем изобретать велосипед... есть же готовый код в исходниках libv4l...
Наконец-то я смог завершить свою эпопею, прошу прощения, что так долго не отвечал.
В общем, данный код выводит 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
Вот конечный результат, который я получил на своем агрегате:

К сожаления, на этом приключения не заканчиваются, я чуток позже я создам новый топик по доработке драйвера устройства, надеюсь на такую же активную поддержку, отныне постараюсь и сам внести свой вклад в развитие нации на форуме... ВСЕМ ОГРОМНОЕ СПАСИБО!!!
Вот конечный результат, который я получил на своем агрегате:
а то что всё синее тебя не смущает?
если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)
а то что всё синее тебя не смущает?
Нет, цвет вполне реалистичный, это просто цветопередача на камере мобилки так сработала.
если выводишь во фреймбуфер, то там порядок байт BGRA (то же, что и BGR32)
Тут все просто, конвертит все внутри себя v4l2 я ему сказал что формат изображение YUV420 на входе и на выходе, а далее он сам разбирается как это ему выводить, все что я сделал это собрал картинку в нужном порядке в буфере выдеовыхода (output_buffers).