/***************************************************************************
                           kdetvformatconversion.cpp
                           -------------------------
    begin                : Sun Aug 1 2004
    copyright            : (C) 2004 by Dirk Ziegelmeier
    email                : dziegel@gmx.de
 ***************************************************************************/

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "qglobal.h"
#include "kdetvformatconversion.h"

#include <kdebug.h>


/*
 * RGB to YUV2 algorithm inspired by
 * libdc1394/examples/dc1394_multiview.c
 * Copyright 2004 ddennedy (LGPL)
 */

static inline void bgr2yuv(unsigned char r, unsigned char g, unsigned char b, int* y, int* u, int* v)
{
    *y = ( 9798*r + 19235*g +  3736*b) / 32768;
    *u = (-4784*r -  9437*g + 14221*b) / 32768 + 128;
    *v = (20218*r - 16941*g -  3277*b) / 32768 + 128;

    if(*y < 0)
        *y = 0;
    if(*u < 0)
        *u = 0;
    if(*v < 0)
        *v = 0;

    if(*y > 255)
        *y = 255;
    if(*u > 255)
        *u = 255;
    if(*v > 255)
        *v = 255;
}

void KdetvFormatConversion::bgr24_to_yuyv(unsigned char* rgb, unsigned char* yuv, unsigned int lineLength,
                                          unsigned int numLines, unsigned int rgbStride, unsigned int yuvStride)
{
    unsigned int i, j;
    int y0, y1, u0, u1, v0, v1;

    unsigned int rgb_bpl = lineLength*3;
    unsigned int yuv_bpl = lineLength<<1;

    for (unsigned int l=0; l<numLines; l++) {
        for (i=0, j=0; i<rgb_bpl; i+=6, j+=4) {
            bgr2yuv(rgb[i+0], rgb[i+1], rgb[i+2], &y0, &u0, &v0);
            bgr2yuv(rgb[i+3], rgb[i+4], rgb[i+5], &y1, &u1, &v1);
            yuv[j + 0] = y0;
            yuv[j + 1] = (v0+v1)/2;
            yuv[j + 2] = y1;
            yuv[j + 3] = (u0+u1)/2;
        }

        rgb += rgb_bpl + rgbStride;
        yuv += yuv_bpl + yuvStride;
    }
}

void KdetvFormatConversion::bgr32_to_yuyv(unsigned char* rgb, unsigned char* yuv, unsigned int lineLength,
                                          unsigned int numLines, unsigned int rgbStride, unsigned int yuvStride)
{
    unsigned int i, j;
    int y0, y1, u0, u1, v0, v1;

    unsigned int rgb_bpl = lineLength<<2;
    unsigned int yuv_bpl = lineLength<<1;

    for (unsigned int l=0; l<numLines; l++) {
        for (i=0, j=0; i<rgb_bpl; i+=8, j+=4) {
            bgr2yuv(rgb[i+0], rgb[i+1], rgb[i+2], &y0, &u0, &v0);
            bgr2yuv(rgb[i+4], rgb[i+5], rgb[i+6], &y1, &u1, &v1);
            yuv[j + 0] = y0;
            yuv[j + 1] = (v0+v1)/2;
            yuv[j + 2] = y1;
            yuv[j + 3] = (u0+u1)/2;
        }

        rgb += rgb_bpl + rgbStride;
        yuv += yuv_bpl + yuvStride;
    }
}

/*
 * This converter was contributed by Herbert Graeber (17.08.2004)
 */
void KdetvFormatConversion::yuv420p_to_yuyv(unsigned char* yuv420p, unsigned char* yuv, unsigned int lineLength,
                                            unsigned int numLines, unsigned int yuv420pStride, unsigned int yuvStride)
{
    Q_ASSERT((lineLength & 0x0001) == 0);
    Q_ASSERT((numLines   & 0x0001) == 0);

    unsigned char* u0 = yuv420p + numLines * lineLength;
    unsigned char* v0 = u0      + (numLines >> 1) * (lineLength >> 1);
    register unsigned char* d = yuv;
    register unsigned char* y = yuv420p;

    for (unsigned int l=0; l<numLines; l+=2) {
        register unsigned char* u = u0;
        register unsigned char* v = v0;

		// even lines
        for (unsigned int i=0; i<lineLength; i+=2) {
            *d++ = *y++;
            *d++ = *u++;
            *d++ = *y++;
            *d++ = *v++;
        }
        d += yuvStride;
        y += yuv420pStride;

        // next y line, same u and v lines again
        // odd lines
        u = u0;
        v = v0;
        for (unsigned int i=0; i<lineLength; i+=2) {
            *d++ = *y++;
            *d++ = *u++;
            *d++ = *y++;
            *d++ = *v++;
        }
        d += yuvStride;
        y += yuv420pStride;
        u += yuv420pStride >> 1;
        v += yuv420pStride >> 1;

        u0 = u; // next u line
        v0 = v; // next v line
    }
}
