Added YUV routines needed for v4l driver, and in the future possibly
other capture drivers too.

diff --git a/dlls/qcap/Makefile.in b/dlls/qcap/Makefile.in
index be9e057..a225edc 100644
--- a/dlls/qcap/Makefile.in
+++ b/dlls/qcap/Makefile.in
@@ -13,7 +13,8 @@
 	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 2307459..023af47 100644
--- a/dlls/qcap/qcap_main.h
+++ b/dlls/qcap/qcap_main.h
@@ -56,4 +56,23 @@
 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 0000000..c1cee2c
--- /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 <stdarg.h>
+
+#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;
+      }
+   }
+}