/* # RGB and YUV crop routines # (C) 2008 Hans de Goede # This program 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 program 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 program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #include #include "libv4lconvert-priv.h" static void v4lconvert_reduceandcrop_rgbbgr24( unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int x, y; int startx = src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width; int starty = src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height; src += starty * src_fmt->fmt.pix.bytesperline + 3 * startx; for (y = 0; y < dest_fmt->fmt.pix.height; y++) { unsigned char *mysrc = src; for (x = 0; x < dest_fmt->fmt.pix.width; x++) { *(dest++) = *(mysrc++); *(dest++) = *(mysrc++); *(dest++) = *(mysrc++); mysrc += 3; /* skip one pixel */ } src += 2 * src_fmt->fmt.pix.bytesperline; /* skip one line */ } } static void v4lconvert_crop_rgbbgr24(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int x; int startx = (src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2; int starty = (src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2; src += starty * src_fmt->fmt.pix.bytesperline + 3 * startx; for (x = 0; x < dest_fmt->fmt.pix.height; x++) { memcpy(dest, src, dest_fmt->fmt.pix.width * 3); src += src_fmt->fmt.pix.bytesperline; dest += dest_fmt->fmt.pix.bytesperline; } } static void v4lconvert_reduceandcrop_yuv420( unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int x, y; int dest_height_half = dest_fmt->fmt.pix.height / 2; int dest_width_half = dest_fmt->fmt.pix.width / 2; int startx = (src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width) & ~1; int starty = (src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height) & ~1; unsigned char *mysrc, *mysrc2; /* Y */ mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx; for (y = 0; y < dest_fmt->fmt.pix.height; y++) { mysrc2 = mysrc; for (x = 0; x < dest_fmt->fmt.pix.width; x++) { *(dest++) = *mysrc2; mysrc2 += 2; /* skip one pixel */ } mysrc += 2 * src_fmt->fmt.pix.bytesperline; /* skip one line */ } /* U */ mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; for (y = 0; y < dest_height_half; y++) { mysrc2 = mysrc; for (x = 0; x < dest_width_half; x++) { *(dest++) = *mysrc2; mysrc2 += 2; /* skip one pixel */ } mysrc += src_fmt->fmt.pix.bytesperline ; /* skip one line */ } /* V */ mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline * 5 / 4 + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; for (y = 0; y < dest_height_half; y++) { mysrc2 = mysrc; for (x = 0; x < dest_width_half; x++) { *(dest++) = *mysrc2; mysrc2 += 2; /* skip one pixel */ } mysrc += src_fmt->fmt.pix.bytesperline ; /* skip one line */ } } static void v4lconvert_crop_yuv420(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int x; int startx = ((src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2) & ~1; int starty = ((src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2) & ~1; unsigned char *mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx; /* Y */ for (x = 0; x < dest_fmt->fmt.pix.height; x++) { memcpy(dest, mysrc, dest_fmt->fmt.pix.width); mysrc += src_fmt->fmt.pix.bytesperline; dest += dest_fmt->fmt.pix.bytesperline; } /* U */ mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; for (x = 0; x < dest_fmt->fmt.pix.height / 2; x++) { memcpy(dest, mysrc, dest_fmt->fmt.pix.width / 2); mysrc += src_fmt->fmt.pix.bytesperline / 2; dest += dest_fmt->fmt.pix.bytesperline / 2; } /* V */ mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline * 5 / 4 + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; for (x = 0; x < dest_fmt->fmt.pix.height / 2; x++) { memcpy(dest, mysrc, dest_fmt->fmt.pix.width / 2); mysrc += src_fmt->fmt.pix.bytesperline / 2; dest += dest_fmt->fmt.pix.bytesperline / 2; } } /* Ok, so this is not really cropping, but more the reverse, whatever */ static void v4lconvert_add_border_rgbbgr24( unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int y; int borderx = (dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2; int bordery = (dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2; for (y = 0; y < bordery; y++) { memset(dest, 0, dest_fmt->fmt.pix.width * 3); dest += dest_fmt->fmt.pix.bytesperline; } for (y = 0; y < src_fmt->fmt.pix.height; y++) { memset(dest, 0, borderx * 3); dest += borderx * 3; memcpy(dest, src, src_fmt->fmt.pix.width * 3); src += src_fmt->fmt.pix.bytesperline; dest += src_fmt->fmt.pix.width * 3; memset(dest, 0, borderx * 3); dest += dest_fmt->fmt.pix.bytesperline - (borderx + src_fmt->fmt.pix.width) * 3; } for (y = 0; y < bordery; y++) { memset(dest, 0, dest_fmt->fmt.pix.width * 3); dest += dest_fmt->fmt.pix.bytesperline; } } static void v4lconvert_add_border_yuv420( unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int y; int borderx = ((dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2) & ~1; int bordery = ((dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2) & ~1; /* Y */ for (y = 0; y < bordery; y++) { memset(dest, 16, dest_fmt->fmt.pix.width); dest += dest_fmt->fmt.pix.bytesperline; } for (y = 0; y < src_fmt->fmt.pix.height; y++) { memset(dest, 16, borderx); dest += borderx; memcpy(dest, src, src_fmt->fmt.pix.width); src += src_fmt->fmt.pix.bytesperline; dest += src_fmt->fmt.pix.width; memset(dest, 16, borderx); dest += dest_fmt->fmt.pix.bytesperline - (borderx + src_fmt->fmt.pix.width); } for (y = 0; y < bordery; y++) { memset(dest, 16, dest_fmt->fmt.pix.width); dest += dest_fmt->fmt.pix.bytesperline; } /* U */ for (y = 0; y < bordery / 2; y++) { memset(dest, 128, dest_fmt->fmt.pix.width / 2); dest += dest_fmt->fmt.pix.bytesperline / 2; } for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { memset(dest, 128, borderx / 2); dest += borderx / 2; memcpy(dest, src, src_fmt->fmt.pix.width / 2); src += src_fmt->fmt.pix.bytesperline / 2; dest += src_fmt->fmt.pix.width / 2; memset(dest, 128, borderx / 2); dest += (dest_fmt->fmt.pix.bytesperline - (borderx + src_fmt->fmt.pix.width)) / 2; } for (y = 0; y < bordery / 2; y++) { memset(dest, 128, dest_fmt->fmt.pix.width / 2); dest += dest_fmt->fmt.pix.bytesperline / 2; } /* V */ for (y = 0; y < bordery / 2; y++) { memset(dest, 128, dest_fmt->fmt.pix.width / 2); dest += dest_fmt->fmt.pix.bytesperline / 2; } for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { memset(dest, 128, borderx / 2); dest += borderx / 2; memcpy(dest, src, src_fmt->fmt.pix.width / 2); src += src_fmt->fmt.pix.bytesperline / 2; dest += src_fmt->fmt.pix.width / 2; memset(dest, 128, borderx / 2); dest += (dest_fmt->fmt.pix.bytesperline - (borderx + src_fmt->fmt.pix.width)) / 2; } for (y = 0; y < bordery / 2; y++) { memset(dest, 128, dest_fmt->fmt.pix.width / 2); dest += dest_fmt->fmt.pix.bytesperline / 2; } } void v4lconvert_crop(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { switch (dest_fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width && src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height) v4lconvert_add_border_rgbbgr24(src, dest, src_fmt, dest_fmt); else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width && src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height) v4lconvert_reduceandcrop_rgbbgr24(src, dest, src_fmt, dest_fmt); else v4lconvert_crop_rgbbgr24(src, dest, src_fmt, dest_fmt); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width && src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height) v4lconvert_add_border_yuv420(src, dest, src_fmt, dest_fmt); else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width && src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height) v4lconvert_reduceandcrop_yuv420(src, dest, src_fmt, dest_fmt); else v4lconvert_crop_yuv420(src, dest, src_fmt, dest_fmt); break; } }