From a64c10fd1712c6df8bc3dd33b6bdf91b3c9cc8b2 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 24 May 2005 12:51:01 +0000 Subject: [PATCH] Added YUV routines needed for v4l driver, and in the future possibly other capture drivers too. --- dlls/qcap/Makefile.in | 3 +- dlls/qcap/qcap_main.h | 19 +++++ dlls/qcap/yuv.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 dlls/qcap/yuv.c diff --git a/dlls/qcap/Makefile.in b/dlls/qcap/Makefile.in index be9e0571d2d..a225edc5bad 100644 --- a/dlls/qcap/Makefile.in +++ b/dlls/qcap/Makefile.in @@ -13,7 +13,8 @@ C_SRCS = \ enummedia.c \ enumpins.c \ pin.c \ - qcap_main.c + qcap_main.c \ + yuv.c RC_SRCS = version.rc diff --git a/dlls/qcap/qcap_main.h b/dlls/qcap/qcap_main.h index 230745978f5..023af47d65b 100644 --- a/dlls/qcap/qcap_main.h +++ b/dlls/qcap/qcap_main.h @@ -56,4 +56,23 @@ void DeleteMediaType(AM_MEDIA_TYPE * pmt); BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards); void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt); +enum YUV_Format { + /* Last 2 numbers give the skip info, the smaller they are the better + * Planar: + * HSKIP : VSKIP */ + YUVP_421, /* 2 : 1 */ + YUVP_422, /* 2 : 2 */ + YUVP_441, /* 4 : 1 */ + YUVP_444, /* 4 : 4 */ + ENDPLANAR, /* No format, just last planar item so we can check on it */ + + /* Non-planar */ + YUYV, /* Order: YUYV (Guess why it's named like that) */ + UYVY, /* Order: UYVY (Looks like someone got bored and swapped the Y's) */ + UYYVYY, /* YUV411 linux style, perhaps YUV420 is YYUYYV? */ +}; + +void YUV_Init(void); +void YUV_To_RGB24(enum YUV_Format format, unsigned char *target, const unsigned char *source, int width, int height); + #endif /* _QCAP_MAIN_H_DEFINED */ diff --git a/dlls/qcap/yuv.c b/dlls/qcap/yuv.c new file mode 100644 index 00000000000..c1cee2cd11b --- /dev/null +++ b/dlls/qcap/yuv.c @@ -0,0 +1,195 @@ +/* DirectShow capture services (QCAP.DLL) + * + * Copyright 2005 Maarten Lankhorst + * + * This file contains the part of the vfw capture interface that + * does the actual Video4Linux(1/2) stuff required for capturing + * and setting/getting media format.. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "strmif.h" +#include "qcap_main.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(qcap); + +static int yuv_xy[256]; /* Gray value */ +static int yuv_gu[256]; /* Green U */ +static int yuv_bu[256]; /* Blue U */ +static int yuv_rv[256]; /* Red V */ +static int yuv_gv[256]; /* Green V */ +static int initialised = 0; + +static inline int ValidRange(int in) { + if (in > 255) in = 255; + if (in < 0) in = 0; + return in; +} + +typedef struct RGB { +#if 0 /* For some reason I have to revert R and B, not sure why */ + unsigned char r, g, b; +#else + unsigned char b, g, r; +#endif +} RGB; + +static inline void YUV2RGB(const unsigned char y_, const unsigned char cb, const unsigned char cr, RGB* retval) { + retval->r = ValidRange(yuv_xy[y_] + yuv_rv[cr]); + retval->g = ValidRange(yuv_xy[y_] + yuv_gu[cb] + yuv_gv[cr]); + retval->b = ValidRange(yuv_xy[y_] + yuv_bu[cb]); +} + +void YUV_Init(void) { + float y, u, v; + int y_, cb, cr; + + if (initialised++) return; + + for (y_ = 0; y_ <= 255; y_++) + { + y = ((float) 255 / 219) * (y_ - 16); + yuv_xy[y_] = ValidRange((int) (y)); + } + + for (cb = 0; cb <= 255; cb++) + { + u = ((float) 255 / 224) * (cb - 128); + yuv_gu[cb] = - ValidRange((int) (0.344 * u)); + yuv_bu[cb] = ValidRange((int) (1.772 * u)); + } + + for (cr = 0; cr <= 255; cr++) + { + v = ((float) 255 / 224) * (cr - 128); + yuv_rv[cr] = ValidRange((int) (1.402 * v)); + yuv_gv[cr] = - ValidRange((int) (0.714 * v)); + } + TRACE("Filled hash table\n"); +} + +static void Parse_YUYV(unsigned char *destbuffer, const unsigned char *input, int width, int height) +{ + const unsigned char *pY, *pCb, *pCr; + int togo = width * height / 2; + pY = input; + pCb = input+1; + pCr = input+3; + while (--togo) { + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + pY += 2; destbuffer += 3; + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + pY += 2; pCb += 4; pCr += 4; destbuffer += 3; + } +} + +static void Parse_UYVY(unsigned char *destbuffer, const unsigned char *input, int width, int height) +{ + const unsigned char *pY, *pCb, *pCr; + int togo = width * height / 2; + pY = input+1; + pCb = input; + pCr = input+2; + while (--togo) { + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + pY += 2; destbuffer += 3; + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + pY += 2; pCb += 4; pCr += 4; destbuffer += 3; + } +} + +static void Parse_UYYVYY(unsigned char *destbuffer, const unsigned char *input, int width, int height) +{ + const unsigned char *pY, *pCb, *pCr; + int togo = width * height / 4; + pY = input+1; + pCb = input; + pCr = input+4; + while (--togo) { + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + destbuffer += 3; pY++; + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + pY += 2; destbuffer += 3; + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + destbuffer += 3; pY++; + YUV2RGB(*pY, *pCb, *pCr, (RGB *)destbuffer); + pY += 2; pCb += 6; pCr += 6; destbuffer += 3; + } +} + +static void Parse_PYUV(unsigned char *destbuffer, const unsigned char *input, int width, int height, int wstep, int hstep) +{ + /* We have 3 pointers, One to Y, one to Cb and 1 to Cr */ + +/* C19 *89* declaration block (Grr julliard for not allowing C99) */ + int uvjump, ysize, uvsize; + const unsigned char *pY, *pCb, *pCr; + int swstep = 0, shstep = 0; + int ypos = 0, xpos = 0; + int indexUV = 0, cUv; +/* End of Grr */ + + uvjump = width / wstep; + ysize = width * height; + uvsize = (width / wstep) * (height / hstep); + pY = input; + pCb = pY + ysize; + pCr = pCb + uvsize; + /* Bottom down DIB */ + do { + swstep = 0; + cUv = indexUV; + for (xpos = 0; xpos < width; xpos++) { + YUV2RGB(*(pY++), pCb[cUv], pCr[cUv], (RGB *)destbuffer); + destbuffer += 3; + if (++swstep == wstep) { + cUv++; + swstep = 0; + } + } + if (++shstep == hstep) { + shstep = 0; + indexUV = cUv; + } + } while (++ypos < height); +} + +void YUV_To_RGB24(enum YUV_Format format, unsigned char *target, const unsigned char *source, int width, int height) { + int wstep, hstep; + if (format < ENDPLANAR) { + switch (format) { + case YUVP_421: wstep = 2; hstep = 1; break; + case YUVP_422: wstep = 2; hstep = 2; break; + case YUVP_441: wstep = 4; hstep = 1; break; + case YUVP_444: wstep = 4; hstep = 4; break; + default: ERR("Unhandled format \"%d\"\n", format); return; + } + Parse_PYUV(target, source, width, height, wstep, hstep); + } else { + switch (format) { + case YUYV: Parse_YUYV(target, source, width, height); return; + case UYVY: Parse_UYVY(target, source, width, height); return; + case UYYVYY: Parse_UYYVYY(target, source, width, height); return; + default: ERR("Unhandled format \"%d\"\n", format); return; + } + } +} -- 2.11.4.GIT