因为我的STVxxx USB camera输出格式是bayer格式,手头上只有YUVTOOLS这个查看工具,没法验证STVxxx在开发板上是否正常工作。
网上找了很久也没找到格式转换工具,最后放弃了,觉得还是写个转换工具比较快。抄写了部分libv4lconvert的代码, 我只验证了
V4L2_PIX_FMT_SGBRG8到V4L2_PIX_FMT_YUV420的转换。
bayer.c
##################################################################################
/* * lib4lconvert, video4linux2 format conversion lib * (C) 2008 Hans de Goede <[email protected]> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA * * Note: original bayer_to_bgr24 code from : * 1394-Based Digital Camera Control Library * * Bayer pattern decoding functions * * Written by Damien Douxchamps and Frederic Devernay * * Note that the original bayer.c in libdc1394 supports many different * bayer decode algorithms, for lib4lconvert the one in this file has been * chosen (and optimized a bit) and the other algorithm's have been removed, * see bayer.c from libdc1394 for all supported algorithms */ #include <string.h> #include <linux/videodev2.h> #include <stdio.h> #include "convert.h" /************************************************************** * Color conversion functions for cameras that can * * output raw-Bayer pattern images, such as some Basler and * * Point Grey camera. Most of the algos presented here come * * from http://www-ise.stanford.edu/~tingchen/ and have been * * converted from Matlab to C and extended to all elementary * * patterns. * **************************************************************/ /* inspired by OpenCV's Bayer decoding */ static void v4lconvert_border_bayer_line_to_bgr24( const unsigned char *bayer, const unsigned char *adjacent_bayer, unsigned char *bgr, int width, int start_with_green, int blue_line) { int t0, t1; if (start_with_green) { /* First pixel */ if (blue_line) { *bgr++ = bayer[1]; *bgr++ = bayer[0]; *bgr++ = adjacent_bayer[0]; } else { *bgr++ = adjacent_bayer[0]; *bgr++ = bayer[0]; *bgr++ = bayer[1]; } /* Second pixel */ t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3; t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1; if (blue_line) { *bgr++ = bayer[1]; *bgr++ = t0; *bgr++ = t1; } else { *bgr++ = t1; *bgr++ = t0; *bgr++ = bayer[1]; } bayer++; adjacent_bayer++; width -= 2; } else { /* First pixel */ t0 = (bayer[1] + adjacent_bayer[0] + 1) >> 1; if (blue_line) { *bgr++ = bayer[0]; *bgr++ = t0; *bgr++ = adjacent_bayer[1]; } else { *bgr++ = adjacent_bayer[1]; *bgr++ = t0; *bgr++ = bayer[0]; } width--; } if (blue_line) { for ( ; width > 2; width -= 2) { t0 = (bayer[0] + bayer[2] + 1) >> 1; *bgr++ = t0; *bgr++ = bayer[1]; *bgr++ = adjacent_bayer[1]; bayer++; adjacent_bayer++; t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3; t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1; *bgr++ = bayer[1]; *bgr++ = t0; *bgr++ = t1; bayer++; adjacent_bayer++; } } else { for ( ; width > 2; width -= 2) { t0 = (bayer[0] + bayer[2] + 1) >> 1; *bgr++ = adjacent_bayer[1]; *bgr++ = bayer[1]; *bgr++ = t0; bayer++; adjacent_bayer++; t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3; t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1; *bgr++ = t1; *bgr++ = t0; *bgr++ = bayer[1]; bayer++; adjacent_bayer++; } } if (width == 2) { /* Second to last pixel */ t0 = (bayer[0] + bayer[2] + 1) >> 1; if (blue_line) { *bgr++ = t0; *bgr++ = bayer[1]; *bgr++ = adjacent_bayer[1]; } else { *bgr++ = adjacent_bayer[1]; *bgr++ = bayer[1]; *bgr++ = t0; } /* Last pixel */ t0 = (bayer[1] + adjacent_bayer[2] + 1) >> 1; if (blue_line) { *bgr++ = bayer[2]; *bgr++ = t0; *bgr++ = adjacent_bayer[1]; } else { *bgr++ = adjacent_bayer[1]; *bgr++ = t0; *bgr++ = bayer[2]; } } else { /* Last pixel */ if (blue_line) { *bgr++ = bayer[0]; *bgr++ = bayer[1]; *bgr++ = adjacent_bayer[1]; } else { *bgr++ = adjacent_bayer[1]; *bgr++ = bayer[1]; *bgr++ = bayer[0]; } } } /* From libdc1394, which on turn was based on OpenCV's Bayer decoding */ static void bayer_to_rgbbgr24(const unsigned char *bayer, unsigned char *bgr, int width, int height, unsigned int pixfmt, int start_with_green, int blue_line) { /* render the first line */ v4lconvert_border_bayer_line_to_bgr24(bayer, bayer + width, bgr, width, start_with_green, blue_line); bgr += width * 3; return; /* reduce height by 2 because of the special case top/bottom line */ for (height -= 2; height; height--) { int t0, t1; /* (width - 2) because of the border */ const unsigned char *bayer_end = bayer + (width - 2); if (start_with_green) { /* OpenCV has a bug in the next line, which was t0 = (bayer[0] + bayer[width * 2] + 1) >> 1; */ t0 = (bayer[1] + bayer[width * 2 + 1] + 1) >> 1; /* Write first pixel */ t1 = (bayer[0] + bayer[width * 2] + bayer[width + 1] + 1) / 3; if (blue_line) { *bgr++ = t0; *bgr++ = t1; *bgr++ = bayer[width]; } else { *bgr++ = bayer[width]; *bgr++ = t1; *bgr++ = t0; } /* Write second pixel */ t1 = (bayer[width] + bayer[width + 2] + 1) >> 1; if (blue_line) { *bgr++ = t0; *bgr++ = bayer[width + 1]; *bgr++ = t1; } else { *bgr++ = t1; *bgr++ = bayer[width + 1]; *bgr++ = t0; } bayer++; } else { /* Write first pixel */ t0 = (bayer[0] + bayer[width * 2] + 1) >> 1; if (blue_line) { *bgr++ = t0; *bgr++ = bayer[width]; *bgr++ = bayer[width + 1]; } else { *bgr++ = bayer[width + 1]; *bgr++ = bayer[width]; *bgr++ = t0; } } if (blue_line) { for (; bayer <= bayer_end - 2; bayer += 2) { t0 = (bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2] + 2) >> 2; t1 = (bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1] + 2) >> 2; *bgr++ = t0; *bgr++ = t1; *bgr++ = bayer[width + 1]; t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1; t1 = (bayer[width + 1] + bayer[width + 3] + 1) >> 1; *bgr++ = t0; *bgr++ = bayer[width + 2]; *bgr++ = t1; } } else { for (; bayer <= bayer_end - 2; bayer += 2) { t0 = (bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2] + 2) >> 2; t1 = (bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1] + 2) >> 2; *bgr++ = bayer[width + 1]; *bgr++ = t1; *bgr++ = t0; t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1; t1 = (bayer[width + 1] + bayer[width + 3] + 1) >> 1; *bgr++ = t1; *bgr++ = bayer[width + 2]; *bgr++ = t0; } } if (bayer < bayer_end) { /* write second to last pixel */ t0 = (bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2] + 2) >> 2; t1 = (bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1] + 2) >> 2; if (blue_line) { *bgr++ = t0; *bgr++ = t1; *bgr++ = bayer[width + 1]; } else { *bgr++ = bayer[width + 1]; *bgr++ = t1; *bgr++ = t0; } /* write last pixel */ t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1; if (blue_line) { *bgr++ = t0; *bgr++ = bayer[width + 2]; *bgr++ = bayer[width + 1]; } else { *bgr++ = bayer[width + 1]; *bgr++ = bayer[width + 2]; *bgr++ = t0; } bayer++; } else { /* write last pixel */ t0 = (bayer[0] + bayer[width * 2] + 1) >> 1; t1 = (bayer[1] + bayer[width * 2 + 1] + bayer[width] + 1) / 3; if (blue_line) { *bgr++ = t0; *bgr++ = t1; *bgr++ = bayer[width + 1]; } else { *bgr++ = bayer[width + 1]; *bgr++ = t1; *bgr++ = t0; } } /* skip 2 border pixels */ bayer += 2; blue_line = !blue_line; start_with_green = !start_with_green; } /* render the last line */ v4lconvert_border_bayer_line_to_bgr24(bayer + width, bayer, bgr, width, !start_with_green, !blue_line); } void v4lconvert_bayer_to_rgb24(const unsigned char *bayer, unsigned char *bgr, int width, int height, unsigned int pixfmt) { bayer_to_rgbbgr24(bayer, bgr, width, height, pixfmt, pixfmt == V4L2_PIX_FMT_SGBRG8 /* start with green */ || pixfmt == V4L2_PIX_FMT_SGRBG8, pixfmt != V4L2_PIX_FMT_SBGGR8 /* blue line */ && pixfmt != V4L2_PIX_FMT_SGBRG8); } void v4lconvert_bayer_to_bgr24(const unsigned char *bayer, unsigned char *bgr, int width, int height, unsigned int pixfmt) { bayer_to_rgbbgr24(bayer, bgr, width, height, pixfmt, pixfmt == V4L2_PIX_FMT_SGBRG8 /* start with green */ || pixfmt == V4L2_PIX_FMT_SGRBG8, pixfmt == V4L2_PIX_FMT_SBGGR8 /* blue line */ || pixfmt == V4L2_PIX_FMT_SGBRG8); } static void v4lconvert_border_bayer_line_to_y( const unsigned char *bayer, const unsigned char *adjacent_bayer, unsigned char *y, int width, int start_with_green, int blue_line) { int t0, t1; if (start_with_green) { /* First pixel */ if (blue_line) { *y++ = (8453 * adjacent_bayer[0] + 16594 * bayer[0] + 3223 * bayer[1] + 524288) >> 15; } else { *y++ = (8453 * bayer[1] + 16594 * bayer[0] + 3223 * adjacent_bayer[0] + 524288) >> 15; } /* Second pixel */ t0 = bayer[0] + bayer[2] + adjacent_bayer[1]; t1 = adjacent_bayer[0] + adjacent_bayer[2]; if (blue_line) *y++ = (4226 * t1 + 5531 * t0 + 3223 * bayer[1] + 524288) >> 15; else *y++ = (8453 * bayer[1] + 5531 * t0 + 1611 * t1 + 524288) >> 15; bayer++; adjacent_bayer++; width -= 2; } else { /* First pixel */ t0 = bayer[1] + adjacent_bayer[0]; if (blue_line) { *y++ = (8453 * adjacent_bayer[1] + 8297 * t0 + 3223 * bayer[0] + 524288) >> 15; } else { *y++ = (8453 * bayer[0] + 8297 * t0 + 3223 * adjacent_bayer[1] + 524288) >> 15; } width--; } if (blue_line) { for ( ; width > 2; width -= 2) { t0 = bayer[0] + bayer[2]; *y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] + 1611 * t0 + 524288) >> 15; bayer++; adjacent_bayer++; t0 = bayer[0] + bayer[2] + adjacent_bayer[1]; t1 = adjacent_bayer[0] + adjacent_bayer[2]; *y++ = (4226 * t1 + 5531 * t0 + 3223 * bayer[1] + 524288) >> 15; bayer++; adjacent_bayer++; } } else { for ( ; width > 2; width -= 2) { t0 = bayer[0] + bayer[2]; *y++ = (4226 * t0 + 16594 * bayer[1] + 3223 * adjacent_bayer[1] + 524288) >> 15; bayer++; adjacent_bayer++; t0 = bayer[0] + bayer[2] + adjacent_bayer[1]; t1 = adjacent_bayer[0] + adjacent_bayer[2]; *y++ = (8453 * bayer[1] + 5531 * t0 + 1611 * t1 + 524288) >> 15; bayer++; adjacent_bayer++; } } if (width == 2) { /* Second to last pixel */ t0 = bayer[0] + bayer[2]; if (blue_line) { *y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] + 1611 * t0 + 524288) >> 15; } else { *y++ = (4226 * t0 + 16594 * bayer[1] + 3223 * adjacent_bayer[1] + 524288) >> 15; } /* Last pixel */ t0 = bayer[1] + adjacent_bayer[2]; if (blue_line) { *y++ = (8453 * adjacent_bayer[1] + 8297 * t0 + 3223 * bayer[2] + 524288) >> 15; } else { *y++ = (8453 * bayer[2] + 8297 * t0 + 3223 * adjacent_bayer[1] + 524288) >> 15; } } else { /* Last pixel */ if (blue_line) { *y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] + 3223 * bayer[0] + 524288) >> 15; } else { *y++ = (8453 * bayer[0] + 16594 * bayer[1] + 3223 * adjacent_bayer[1] + 524288) >> 15; } } } void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv, int width, int height, unsigned int src_pixfmt, int yvu) { int blue_line = 0, start_with_green = 0, x, y; unsigned char *ydst = yuv; unsigned char *udst, *vdst; if (yvu) { vdst = yuv + width * height; udst = vdst + width * height / 4; } else { udst = yuv + width * height; vdst = udst + width * height / 4; } printf("bayer address(0x%p)", bayer); /* First calculate the u and v planes 2x2 pixels at a time */ switch (src_pixfmt) { case V4L2_PIX_FMT_SBGGR8: for (y = 0; y < height; y += 2) { for (x = 0; x < width; x += 2) { int b, g, r; b = bayer[x]; g = bayer[x + 1]; g += bayer[x + width]; r = bayer[x + width + 1]; *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15; *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15; } bayer += 2 * width; } blue_line = 1; break; case V4L2_PIX_FMT_SRGGB8: for (y = 0; y < height; y += 2) { for (x = 0; x < width; x += 2) { int b, g, r; r = bayer[x]; g = bayer[x + 1]; g += bayer[x + width]; b = bayer[x + width + 1]; *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15; *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15; } bayer += 2 * width; } break; case V4L2_PIX_FMT_SGBRG8: for (y = 0; y < height; y += 2) { for (x = 0; x < width; x += 2) { int b, g, r; g = bayer[x]; b = bayer[x + 1]; r = bayer[x + width]; g += bayer[x + width + 1]; *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15; *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15; } bayer += 2 * width; } blue_line = 1; start_with_green = 1; break; case V4L2_PIX_FMT_SGRBG8: for (y = 0; y < height; y += 2) { for (x = 0; x < width; x += 2) { int b, g, r; g = bayer[x]; r = bayer[x + 1]; b = bayer[x + width]; g += bayer[x + width + 1]; *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15; *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15; } bayer += 2 * width; } start_with_green = 1; break; } bayer -= width * height; printf("bayer address(0x%p)", bayer); /* render the first line */ v4lconvert_border_bayer_line_to_y(bayer, bayer + width, ydst, width, start_with_green, blue_line); ydst += width; printf("bayer address(0x%p), height(%d)", bayer, height); /* reduce height by 2 because of the border */ for (height -= 2; height; height--) { int t0, t1; /* (width - 2) because of the border */ const unsigned char *bayer_end = bayer + (width - 2); if (start_with_green) { t0 = bayer[1] + bayer[width * 2 + 1]; /* Write first pixel */ t1 = bayer[0] + bayer[width * 2] + bayer[width + 1]; if (blue_line) *ydst++ = (8453 * bayer[width] + 5516 * t1 + 1661 * t0 + 524288) >> 15; else *ydst++ = (4226 * t0 + 5516 * t1 + 3223 * bayer[width] + 524288) >> 15; /* Write second pixel */ t1 = bayer[width] + bayer[width + 2]; if (blue_line) *ydst++ = (4226 * t1 + 16594 * bayer[width + 1] + 1611 * t0 + 524288) >> 15; else *ydst++ = (4226 * t0 + 16594 * bayer[width + 1] + 1611 * t1 + 524288) >> 15; bayer++; } else { /* Write first pixel */ t0 = bayer[0] + bayer[width * 2]; if (blue_line) { *ydst++ = (8453 * bayer[width + 1] + 16594 * bayer[width] + 1661 * t0 + 524288) >> 15; } else { *ydst++ = (4226 * t0 + 16594 * bayer[width] + 3223 * bayer[width + 1] + 524288) >> 15; } } if (blue_line) { for (; bayer <= bayer_end - 2; bayer += 2) { t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2]; t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1]; *ydst++ = (8453 * bayer[width + 1] + 4148 * t1 + 806 * t0 + 524288) >> 15; t0 = bayer[2] + bayer[width * 2 + 2]; t1 = bayer[width + 1] + bayer[width + 3]; *ydst++ = (4226 * t1 + 16594 * bayer[width + 2] + 1611 * t0 + 524288) >> 15; } } else { for (; bayer <= bayer_end - 2; bayer += 2) { t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2]; t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1]; *ydst++ = (2113 * t0 + 4148 * t1 + 3223 * bayer[width + 1] + 524288) >> 15; t0 = bayer[2] + bayer[width * 2 + 2]; t1 = bayer[width + 1] + bayer[width + 3]; *ydst++ = (4226 * t0 + 16594 * bayer[width + 2] + 1611 * t1 + 524288) >> 15; } } if (bayer < bayer_end) { /* Write second to last pixel */ t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2]; t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1]; if (blue_line) *ydst++ = (8453 * bayer[width + 1] + 4148 * t1 + 806 * t0 + 524288) >> 15; else *ydst++ = (2113 * t0 + 4148 * t1 + 3223 * bayer[width + 1] + 524288) >> 15; /* write last pixel */ t0 = bayer[2] + bayer[width * 2 + 2]; if (blue_line) { *ydst++ = (8453 * bayer[width + 1] + 16594 * bayer[width + 2] + 1661 * t0 + 524288) >> 15; } else { *ydst++ = (4226 * t0 + 16594 * bayer[width + 2] + 3223 * bayer[width + 1] + 524288) >> 15; } bayer++; } else { /* write last pixel */ t0 = bayer[0] + bayer[width * 2]; t1 = bayer[1] + bayer[width * 2 + 1] + bayer[width]; if (blue_line) *ydst++ = (8453 * bayer[width + 1] + 5516 * t1 + 1661 * t0 + 524288) >> 15; else *ydst++ = (4226 * t0 + 5516 * t1 + 3223 * bayer[width + 1] + 524288) >> 15; } /* skip 2 border pixels */ bayer += 2; blue_line = !blue_line; start_with_green = !start_with_green; } /* render the last line */ v4lconvert_border_bayer_line_to_y(bayer + width, bayer, ydst, width, !start_with_green, !blue_line); }
##################################################################################
convert.c
##################################################################################
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/stat.h> #include <linux/videodev2.h> #include "convert.h" char *g_src_file = NULL; char *g_dest_file = NULL; int g_in_width = 352; int g_in_height = 292; unsigned int g_src_fmt = V4L2_PIX_FMT_SGBRG8; //unsigned int g_dest_fmt = V4L2_PIX_FMT_RGB24; unsigned int g_dest_fmt = V4L2_PIX_FMT_YUV420; int process_cmdline(int argc, char **argv) { int i; char *tmp; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-s") == 0) { g_src_file = argv[++i]; } else if (strcmp(argv[i], "d") == 0) { g_dest_file = strdup(argv[++i]); } else if (strcmp(argv[i], "-sf") == 0) { tmp = argv[++i]; if (strlen(tmp) == 4) { g_src_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]); } } else if (strcmp(argv[i], "-df") == 0) { tmp = argv[++i]; if (strlen(tmp) == 4) { g_dest_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]); } } else if (strcmp(argv[i], "iw") == 0) { g_in_width = atoi(argv[++i]); } else if (strcmp(argv[i], "ih") == 0) { g_in_height = atoi(argv[++i]); } } if (g_src_file && g_dest_file == NULL) { g_dest_file = malloc(256); sprintf(g_dest_file, "%s.out", g_src_file); } if (g_in_width == 0 || g_in_height == 0) { } } int get_file_size(int fd) { int ret; struct stat sb; ret = fstat(fd, &sb); if (ret == -1) { return ret; } return sb.st_size; } int get_bits_per_pixel(unsigned int fmt) { int ret; switch (fmt) { case V4L2_PIX_FMT_RGB24: ret = 24; break; case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: ret = 8; break; case V4L2_PIX_FMT_YUV420: ret = 12; break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: ret = 16; break; default: ret = -1; break; } return ret; } void convert(void *src, void *dest, int width, int height, unsigned int src_fmt, unsigned int dest_fmt) { switch (src_fmt) { case V4L2_PIX_FMT_SGBRG8: if (dest_fmt == V4L2_PIX_FMT_RGB24) { v4lconvert_bayer_to_rgb24(src, dest, width, height, src_fmt); } else if (dest_fmt == V4L2_PIX_FMT_YUV420) { v4lconvert_bayer_to_yuv420(src, dest, width, height, src_fmt, 0); } break; default: break; } } int main(int argc, char *argv[]) { int ret = 0; int fd_src = 0; int fd_dest = 0; int src_size = 0; int dest_size = 0; int pix_num; void *src = NULL; void *dest = NULL; process_cmdline(argc, argv); if (g_src_file == NULL || g_dest_file == NULL) { ret = -1; goto bailout; } printf("input file(%s), output file(%s)\n", g_src_file, g_dest_file); fd_src = open(g_src_file, O_RDONLY); if (fd_src == -1) { ret = -2; goto bailout; } fd_dest = open(g_dest_file, O_RDWR | O_CREAT, 0666); if (fd_dest == -1) { ret = -3; goto bailout; } src_size = get_file_size(fd_src); if (src_size == -1) { ret = -4; goto bailout; } pix_num = src_size / (get_bits_per_pixel(g_src_fmt)/8) ; //dest_size = pix_num * get_bytes_per_pixel(g_dest_fmt); ret = get_bits_per_pixel(g_dest_fmt); dest_size = pix_num * ret / 8; printf("src_size(%d), dest_size(%d)\n", src_size, dest_size); src = malloc(src_size); dest = malloc(dest_size); if (src == NULL || dest == NULL) { ret = -5; goto bailout; } ret = read(fd_src, src, src_size); if (ret != src_size) { ret = -6; goto bailout; } convert(src, dest, g_in_width, g_in_height, g_src_fmt, g_dest_fmt); printf("write out file, size=%d\n", dest_size); ret = write(fd_dest, dest, dest_size); if (ret != dest_size) { ret = -1; goto bailout; } bailout: if (src) free(src); if (dest) free(dest); if (fd_src) close(fd_src); if (fd_dest) close(fd_dest); if (g_dest_file) free(g_dest_file); printf("ret(%d)\n", ret); return ret; }
##################################################################################
covert.h
##################################################################################
#ifndef __LIBV4LCONVERT_PRIV_H #define __LIBV4LCONVERT_PRIV_H #define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') void v4lconvert_bayer_to_rgb24(const unsigned char *bayer, unsigned char *bgr, int width, int height, unsigned int pixfmt); void v4lconvert_bayer_to_bgr24(const unsigned char *bayer, unsigned char *bgr, int width, int height, unsigned int pixfmt); void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv, int width, int height, unsigned int src_pixfmt, int yvu); #endif /* __LIBV4LCONVERT_PRIV_H */
##################################################################################
Makefile
##################################################################################
CONVERT := convert CFLAGS := -static CC = gcc $(CONVERT): convert.c bayer.c $(CC) -o $@ $^ $(CFLAGS) clean: rm -f *.o $(CONVERT)
RGB32 RGB565转换为YUV444
另外为了在PC显示framebuffer中的数据,写了一个ARGB32或者RGB565到YUV444的转换工具。利用YUVtools显示YUV444图像。
其实可以不用这么麻烦,使用ddms截屏也行。
YUV444是 Y U V分量比为4:4:4,每个像素用24bits表示。
##################################################################################
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/stat.h> #include <linux/videodev2.h> char *g_src_file = NULL; char *g_dest_file = NULL; int g_in_width = 720; int g_in_height = 480; /* V4L2_PIX_FMT_BGR32 */ //unsigned int g_src_fmt = V4L2_PIX_FMT_RGB32; unsigned int g_src_fmt = V4L2_PIX_FMT_RGB565; /* V4L2_PIX_FMT_YUYV V4L2_PIX_FMT_YVYU V4L2_PIX_FMT_UYVY V4L2_PIX_FMT_VYUY */ unsigned int g_dest_fmt = V4L2_PIX_FMT_YUV444; static unsigned char get_R(unsigned char *src, unsigned int fmt) { unsigned char R; switch (fmt) { case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_RGB24: R = *(src); break; case V4L2_PIX_FMT_RGB565: R = (*(src) & 0x1F) << 3; break; case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV444: default: R = 0; break; } return R; } static unsigned char get_G(unsigned char *src, unsigned int fmt) { unsigned char G; switch (fmt) { case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_RGB24: G = *(src + 1); break; case V4L2_PIX_FMT_RGB565: G = ((*(src) & 0xE0) >> 3) | ((*(src + 1) & 0x07) << 5); break; case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV444: default: G = 0; break; } return G; } static unsigned char get_B(unsigned char *src, unsigned int fmt) { unsigned char B; switch (fmt) { case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_RGB24: B = *(src + 2); break; case V4L2_PIX_FMT_RGB565: B = (*(src + 1) & 0xF8); break; case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV444: default: B = 0; break; } return B; } rgb2yuv(char *rgb, char *yuv) { int i, j; unsigned char R, G, B, *y, *u, *v, *alpha; double RR, GG, BB; unsigned char *src, *dest; for (i = 0; i < g_in_height; i++) { for (j = 0; j < g_in_width; j++) { src = rgb + (i * g_in_width + j) * get_bpp(g_src_fmt) / 8; dest = yuv + (i * g_in_width + j) * get_bpp(g_dest_fmt) / 8; R = get_R(src, g_src_fmt); G = get_G(src, g_src_fmt); B = get_B(src, g_src_fmt); /* normalize to 16 ..235 */ RR = 219 * R / 255 + 16; GG = 219 * G / 255 + 16; BB = 219 * B / 255 + 16; y = dest; u = dest + 1; v = dest + 2; //alpha = dest + 3; *y = (unsigned char)(0.2991*RR + 0.5849*GG + 0.1159*BB + 0.5); *u = (unsigned char)(-0.1725*RR - 0.3372*GG + 0.5097*BB + 128.5); *v = (unsigned char)(0.5097*RR - 0.4254*GG - 0.0843*BB + 128.5); //*alpha = 255; } } } int process_cmdline(int argc, char **argv) { int i; char *tmp; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-s") == 0) { g_src_file = argv[++i]; } else if (strcmp(argv[i], "-d") == 0) { g_dest_file = strdup(argv[++i]); } else if (strcmp(argv[i], "-sf") == 0) { tmp = argv[++i]; if (strlen(tmp) == 4) { g_src_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]); } } else if (strcmp(argv[i], "-df") == 0) { tmp = argv[++i]; if (strlen(tmp) == 4) { g_dest_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]); } } else if (strcmp(argv[i], "iw") == 0) { g_in_width = atoi(argv[++i]); } else if (strcmp(argv[i], "ih") == 0) { g_in_height = atoi(argv[++i]); } } if (g_src_file && g_dest_file == NULL) { g_dest_file = malloc(256); sprintf(g_dest_file, "%s.out", g_src_file); } if (g_in_width == 0 || g_in_height == 0) { } } int get_bpp(unsigned int fmt) { int ret; switch (fmt) { case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: ret = 32; break; case V4L2_PIX_FMT_RGB24: ret = 24; break; case V4L2_PIX_FMT_RGB565: ret = 16; break; case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: ret = 8; break; case V4L2_PIX_FMT_YUV420: ret = 12; break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: ret = 16; break; case V4L2_PIX_FMT_YUV444: ret = 24; break; default: ret = -1; break; } return ret; } main(int argc, char *argv[]) { int ret; int src_fd, dest_fd; int src_size, dest_size; char *src_buf; char *dest_buf; process_cmdline(argc, argv); if (g_src_file == NULL || g_dest_file == NULL) { ret = -1; goto bailout; } src_fd = open(g_src_file, O_RDONLY); if (src_fd == -1) { ret = -2; goto bailout; } dest_fd = open(g_dest_file, O_RDWR | O_CREAT, 0666); if (dest_fd == -1) { ret = -3; goto bailout; } src_size = g_in_width * g_in_height * get_bpp(g_src_fmt) / 8; dest_size = g_in_width * g_in_height * get_bpp(g_dest_fmt) / 8; src_buf = malloc(src_size); dest_buf = malloc(dest_size); ret = read(src_fd, src_buf, src_size); if (ret != src_size) { printf("src_size=%d, ret=%d\n", src_size, ret); ret = -4; goto bailout; } rgb2yuv(src_buf, dest_buf); printf("write out file, size=%d\n", dest_size); ret = write(dest_fd, dest_buf, dest_size); if (ret != dest_size) { ret = -5; goto bailout; } bailout: printf("ret(%d)\n", ret); return ret; }