194 lines
5.8 KiB
C
194 lines
5.8 KiB
C
/* 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 "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 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;
|
|
}
|
|
}
|
|
}
|