|  | /* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "wingdi.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_] = y; | 
|  | } | 
|  |  | 
|  | for (cb = 0; cb <= 255; cb++) | 
|  | { | 
|  | u = ((float) 255 / 224) * (cb - 128); | 
|  | yuv_gu[cb] = -0.344 * u; | 
|  | yuv_bu[cb] =  1.772 * u; | 
|  | } | 
|  |  | 
|  | for (cr = 0; cr <= 255; cr++) | 
|  | { | 
|  | v = ((float) 255 / 224) * (cr - 128); | 
|  | yuv_rv[cr] =  1.402 * v; | 
|  | yuv_gv[cr] = -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 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 */ | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  | } |