1406 lines
44 KiB
C
1406 lines
44 KiB
C
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
#include "../SDL_internal.h"
|
|
|
|
/* This is the software implementation of the YUV texture support */
|
|
|
|
/* This code was derived from code carrying the following copyright notices:
|
|
|
|
* Copyright (c) 1995 The Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation for any purpose, without fee, and without written agreement is
|
|
* hereby granted, provided that the above copyright notice and the following
|
|
* two paragraphs appear in all copies of this software.
|
|
*
|
|
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
|
|
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
|
|
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
|
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
|
|
* Copyright (c) 1995 Erik Corry
|
|
* All rights reserved.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation for any purpose, without fee, and without written agreement is
|
|
* hereby granted, provided that the above copyright notice and the following
|
|
* two paragraphs appear in all copies of this software.
|
|
*
|
|
* IN NO EVENT SHALL ERIK CORRY BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
|
* SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
|
|
* THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ERIK CORRY HAS BEEN ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* ERIK CORRY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
|
|
* BASIS, AND ERIK CORRY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
|
|
* UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
|
|
* Portions of this software Copyright (c) 1995 Brown University.
|
|
* All rights reserved.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation for any purpose, without fee, and without written agreement
|
|
* is hereby granted, provided that the above copyright notice and the
|
|
* following two paragraphs appear in all copies of this software.
|
|
*
|
|
* IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
|
|
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
|
|
* UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
|
|
* BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
|
|
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
*/
|
|
|
|
#include "SDL_assert.h"
|
|
#include "SDL_video.h"
|
|
#include "SDL_cpuinfo.h"
|
|
#include "SDL_yuv_sw_c.h"
|
|
|
|
|
|
/* The colorspace conversion functions */
|
|
|
|
#if (__GNUC__ > 2) && defined(__i386__) && __OPTIMIZE__ && SDL_ASSEMBLY_ROUTINES
|
|
extern void Color565DitherYV12MMX1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod);
|
|
extern void ColorRGBDitherYV12MMX1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod);
|
|
#endif
|
|
|
|
static void
|
|
Color16DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned short *row1;
|
|
unsigned short *row2;
|
|
unsigned char *lum2;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
row1 = (unsigned short *) out;
|
|
row2 = row1 + cols + mod;
|
|
lum2 = lum + cols;
|
|
|
|
mod += cols + mod;
|
|
|
|
y = rows / 2;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
++cr;
|
|
++cb;
|
|
|
|
L = *lum++;
|
|
*row1++ = (unsigned short) (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
|
|
L = *lum++;
|
|
*row1++ = (unsigned short) (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
|
|
|
|
/* Now, do second row. */
|
|
|
|
L = *lum2++;
|
|
*row2++ = (unsigned short) (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
|
|
L = *lum2++;
|
|
*row2++ = (unsigned short) (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
}
|
|
|
|
/*
|
|
* These values are at the start of the next line, (due
|
|
* to the ++'s above),but they need to be at the start
|
|
* of the line after that.
|
|
*/
|
|
lum += cols;
|
|
lum2 += cols;
|
|
row1 += mod;
|
|
row2 += mod;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color24DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int value;
|
|
unsigned char *row1;
|
|
unsigned char *row2;
|
|
unsigned char *lum2;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
row1 = out;
|
|
row2 = row1 + cols * 3 + mod * 3;
|
|
lum2 = lum + cols;
|
|
|
|
mod += cols + mod;
|
|
mod *= 3;
|
|
|
|
y = rows / 2;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
++cr;
|
|
++cb;
|
|
|
|
L = *lum++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
*row1++ = (value) & 0xFF;
|
|
*row1++ = (value >> 8) & 0xFF;
|
|
*row1++ = (value >> 16) & 0xFF;
|
|
|
|
L = *lum++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
*row1++ = (value) & 0xFF;
|
|
*row1++ = (value >> 8) & 0xFF;
|
|
*row1++ = (value >> 16) & 0xFF;
|
|
|
|
|
|
/* Now, do second row. */
|
|
|
|
L = *lum2++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
*row2++ = (value) & 0xFF;
|
|
*row2++ = (value >> 8) & 0xFF;
|
|
*row2++ = (value >> 16) & 0xFF;
|
|
|
|
L = *lum2++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
*row2++ = (value) & 0xFF;
|
|
*row2++ = (value >> 8) & 0xFF;
|
|
*row2++ = (value >> 16) & 0xFF;
|
|
}
|
|
|
|
/*
|
|
* These values are at the start of the next line, (due
|
|
* to the ++'s above),but they need to be at the start
|
|
* of the line after that.
|
|
*/
|
|
lum += cols;
|
|
lum2 += cols;
|
|
row1 += mod;
|
|
row2 += mod;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int *row1;
|
|
unsigned int *row2;
|
|
unsigned char *lum2;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
row1 = (unsigned int *) out;
|
|
row2 = row1 + cols + mod;
|
|
lum2 = lum + cols;
|
|
|
|
mod += cols + mod;
|
|
|
|
y = rows / 2;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
++cr;
|
|
++cb;
|
|
|
|
L = *lum++;
|
|
*row1++ = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
|
|
L = *lum++;
|
|
*row1++ = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
|
|
|
|
/* Now, do second row. */
|
|
|
|
L = *lum2++;
|
|
*row2++ = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
|
|
L = *lum2++;
|
|
*row2++ = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
}
|
|
|
|
/*
|
|
* These values are at the start of the next line, (due
|
|
* to the ++'s above),but they need to be at the start
|
|
* of the line after that.
|
|
*/
|
|
lum += cols;
|
|
lum2 += cols;
|
|
row1 += mod;
|
|
row2 += mod;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* In this function I make use of a nasty trick. The tables have the lower
|
|
* 16 bits replicated in the upper 16. This means I can write ints and get
|
|
* the horisontal doubling for free (almost).
|
|
*/
|
|
static void
|
|
Color16DitherYV12Mod2X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int *row1 = (unsigned int *) out;
|
|
const int next_row = cols + (mod / 2);
|
|
unsigned int *row2 = row1 + 2 * next_row;
|
|
unsigned char *lum2;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
lum2 = lum + cols;
|
|
|
|
mod = (next_row * 3) + (mod / 2);
|
|
|
|
y = rows / 2;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
++cr;
|
|
++cb;
|
|
|
|
L = *lum++;
|
|
row1[0] = row1[next_row] = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
row1++;
|
|
|
|
L = *lum++;
|
|
row1[0] = row1[next_row] = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
row1++;
|
|
|
|
|
|
/* Now, do second row. */
|
|
|
|
L = *lum2++;
|
|
row2[0] = row2[next_row] = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
row2++;
|
|
|
|
L = *lum2++;
|
|
row2[0] = row2[next_row] = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
row2++;
|
|
}
|
|
|
|
/*
|
|
* These values are at the start of the next line, (due
|
|
* to the ++'s above),but they need to be at the start
|
|
* of the line after that.
|
|
*/
|
|
lum += cols;
|
|
lum2 += cols;
|
|
row1 += mod;
|
|
row2 += mod;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color24DitherYV12Mod2X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int value;
|
|
unsigned char *row1 = out;
|
|
const int next_row = (cols * 2 + mod) * 3;
|
|
unsigned char *row2 = row1 + 2 * next_row;
|
|
unsigned char *lum2;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
lum2 = lum + cols;
|
|
|
|
mod = next_row * 3 + mod * 3;
|
|
|
|
y = rows / 2;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
++cr;
|
|
++cb;
|
|
|
|
L = *lum++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row1[0 + 0] = row1[3 + 0] = row1[next_row + 0] =
|
|
row1[next_row + 3 + 0] = (value) & 0xFF;
|
|
row1[0 + 1] = row1[3 + 1] = row1[next_row + 1] =
|
|
row1[next_row + 3 + 1] = (value >> 8) & 0xFF;
|
|
row1[0 + 2] = row1[3 + 2] = row1[next_row + 2] =
|
|
row1[next_row + 3 + 2] = (value >> 16) & 0xFF;
|
|
row1 += 2 * 3;
|
|
|
|
L = *lum++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row1[0 + 0] = row1[3 + 0] = row1[next_row + 0] =
|
|
row1[next_row + 3 + 0] = (value) & 0xFF;
|
|
row1[0 + 1] = row1[3 + 1] = row1[next_row + 1] =
|
|
row1[next_row + 3 + 1] = (value >> 8) & 0xFF;
|
|
row1[0 + 2] = row1[3 + 2] = row1[next_row + 2] =
|
|
row1[next_row + 3 + 2] = (value >> 16) & 0xFF;
|
|
row1 += 2 * 3;
|
|
|
|
|
|
/* Now, do second row. */
|
|
|
|
L = *lum2++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row2[0 + 0] = row2[3 + 0] = row2[next_row + 0] =
|
|
row2[next_row + 3 + 0] = (value) & 0xFF;
|
|
row2[0 + 1] = row2[3 + 1] = row2[next_row + 1] =
|
|
row2[next_row + 3 + 1] = (value >> 8) & 0xFF;
|
|
row2[0 + 2] = row2[3 + 2] = row2[next_row + 2] =
|
|
row2[next_row + 3 + 2] = (value >> 16) & 0xFF;
|
|
row2 += 2 * 3;
|
|
|
|
L = *lum2++;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row2[0 + 0] = row2[3 + 0] = row2[next_row + 0] =
|
|
row2[next_row + 3 + 0] = (value) & 0xFF;
|
|
row2[0 + 1] = row2[3 + 1] = row2[next_row + 1] =
|
|
row2[next_row + 3 + 1] = (value >> 8) & 0xFF;
|
|
row2[0 + 2] = row2[3 + 2] = row2[next_row + 2] =
|
|
row2[next_row + 3 + 2] = (value >> 16) & 0xFF;
|
|
row2 += 2 * 3;
|
|
}
|
|
|
|
/*
|
|
* These values are at the start of the next line, (due
|
|
* to the ++'s above),but they need to be at the start
|
|
* of the line after that.
|
|
*/
|
|
lum += cols;
|
|
lum2 += cols;
|
|
row1 += mod;
|
|
row2 += mod;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color32DitherYV12Mod2X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int *row1 = (unsigned int *) out;
|
|
const int next_row = cols * 2 + mod;
|
|
unsigned int *row2 = row1 + 2 * next_row;
|
|
unsigned char *lum2;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
lum2 = lum + cols;
|
|
|
|
mod = (next_row * 3) + mod;
|
|
|
|
y = rows / 2;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
++cr;
|
|
++cb;
|
|
|
|
L = *lum++;
|
|
row1[0] = row1[1] = row1[next_row] = row1[next_row + 1] =
|
|
(rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row1 += 2;
|
|
|
|
L = *lum++;
|
|
row1[0] = row1[1] = row1[next_row] = row1[next_row + 1] =
|
|
(rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row1 += 2;
|
|
|
|
|
|
/* Now, do second row. */
|
|
|
|
L = *lum2++;
|
|
row2[0] = row2[1] = row2[next_row] = row2[next_row + 1] =
|
|
(rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row2 += 2;
|
|
|
|
L = *lum2++;
|
|
row2[0] = row2[1] = row2[next_row] = row2[next_row + 1] =
|
|
(rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row2 += 2;
|
|
}
|
|
|
|
/*
|
|
* These values are at the start of the next line, (due
|
|
* to the ++'s above),but they need to be at the start
|
|
* of the line after that.
|
|
*/
|
|
lum += cols;
|
|
lum2 += cols;
|
|
row1 += mod;
|
|
row2 += mod;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color16DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned short *row;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
row = (unsigned short *) out;
|
|
|
|
y = rows;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
cr += 4;
|
|
cb += 4;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
*row++ = (unsigned short) (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
*row++ = (unsigned short) (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
|
|
}
|
|
|
|
row += mod;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color24DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int value;
|
|
unsigned char *row;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
row = (unsigned char *) out;
|
|
mod *= 3;
|
|
y = rows;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
cr += 4;
|
|
cb += 4;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
*row++ = (value) & 0xFF;
|
|
*row++ = (value >> 8) & 0xFF;
|
|
*row++ = (value >> 16) & 0xFF;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
*row++ = (value) & 0xFF;
|
|
*row++ = (value >> 8) & 0xFF;
|
|
*row++ = (value >> 16) & 0xFF;
|
|
|
|
}
|
|
row += mod;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color32DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int *row;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
row = (unsigned int *) out;
|
|
y = rows;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
cr += 4;
|
|
cb += 4;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
*row++ = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
*row++ = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
|
|
|
|
}
|
|
row += mod;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* In this function I make use of a nasty trick. The tables have the lower
|
|
* 16 bits replicated in the upper 16. This means I can write ints and get
|
|
* the horisontal doubling for free (almost).
|
|
*/
|
|
static void
|
|
Color16DitherYUY2Mod2X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int *row = (unsigned int *) out;
|
|
const int next_row = cols + (mod / 2);
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
|
|
y = rows;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
cr += 4;
|
|
cb += 4;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
row[0] = row[next_row] = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
row++;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
row[0] = row[next_row] = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] |
|
|
rgb_2_pix[L + cb_b]);
|
|
row++;
|
|
|
|
}
|
|
row += next_row;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color24DitherYUY2Mod2X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int value;
|
|
unsigned char *row = out;
|
|
const int next_row = (cols * 2 + mod) * 3;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
y = rows;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
cr += 4;
|
|
cb += 4;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row[0 + 0] = row[3 + 0] = row[next_row + 0] =
|
|
row[next_row + 3 + 0] = (value) & 0xFF;
|
|
row[0 + 1] = row[3 + 1] = row[next_row + 1] =
|
|
row[next_row + 3 + 1] = (value >> 8) & 0xFF;
|
|
row[0 + 2] = row[3 + 2] = row[next_row + 2] =
|
|
row[next_row + 3 + 2] = (value >> 16) & 0xFF;
|
|
row += 2 * 3;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
value = (rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row[0 + 0] = row[3 + 0] = row[next_row + 0] =
|
|
row[next_row + 3 + 0] = (value) & 0xFF;
|
|
row[0 + 1] = row[3 + 1] = row[next_row + 1] =
|
|
row[next_row + 3 + 1] = (value >> 8) & 0xFF;
|
|
row[0 + 2] = row[3 + 2] = row[next_row + 2] =
|
|
row[next_row + 3 + 2] = (value >> 16) & 0xFF;
|
|
row += 2 * 3;
|
|
|
|
}
|
|
row += next_row;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Color32DitherYUY2Mod2X(int *colortab, Uint32 * rgb_2_pix,
|
|
unsigned char *lum, unsigned char *cr,
|
|
unsigned char *cb, unsigned char *out,
|
|
int rows, int cols, int mod)
|
|
{
|
|
unsigned int *row = (unsigned int *) out;
|
|
const int next_row = cols * 2 + mod;
|
|
int x, y;
|
|
int cr_r;
|
|
int crb_g;
|
|
int cb_b;
|
|
int cols_2 = cols / 2;
|
|
mod += mod;
|
|
y = rows;
|
|
while (y--) {
|
|
x = cols_2;
|
|
while (x--) {
|
|
register int L;
|
|
|
|
cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
|
|
crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
|
|
+ colortab[*cb + 2 * 256];
|
|
cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
|
|
cr += 4;
|
|
cb += 4;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
row[0] = row[1] = row[next_row] = row[next_row + 1] =
|
|
(rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row += 2;
|
|
|
|
L = *lum;
|
|
lum += 2;
|
|
row[0] = row[1] = row[next_row] = row[next_row + 1] =
|
|
(rgb_2_pix[L + cr_r] |
|
|
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
|
|
row += 2;
|
|
|
|
|
|
}
|
|
|
|
row += next_row;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* How many 1 bits are there in the Uint32.
|
|
* Low performance, do not call often.
|
|
*/
|
|
static int
|
|
number_of_bits_set(Uint32 a)
|
|
{
|
|
if (!a)
|
|
return 0;
|
|
if (a & 1)
|
|
return 1 + number_of_bits_set(a >> 1);
|
|
return (number_of_bits_set(a >> 1));
|
|
}
|
|
|
|
/*
|
|
* How many 0 bits are there at least significant end of Uint32.
|
|
* Low performance, do not call often.
|
|
*/
|
|
static int
|
|
free_bits_at_bottom(Uint32 a)
|
|
{
|
|
/* assume char is 8 bits */
|
|
if (!a)
|
|
return sizeof(Uint32) * 8;
|
|
if (((Sint32) a) & 1l)
|
|
return 0;
|
|
return 1 + free_bits_at_bottom(a >> 1);
|
|
}
|
|
|
|
static int
|
|
SDL_SW_SetupYUVDisplay(SDL_SW_YUVTexture * swdata, Uint32 target_format)
|
|
{
|
|
Uint32 *r_2_pix_alloc;
|
|
Uint32 *g_2_pix_alloc;
|
|
Uint32 *b_2_pix_alloc;
|
|
int i;
|
|
int bpp;
|
|
Uint32 Rmask, Gmask, Bmask, Amask;
|
|
|
|
if (!SDL_PixelFormatEnumToMasks
|
|
(target_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask) || bpp < 15) {
|
|
return SDL_SetError("Unsupported YUV destination format");
|
|
}
|
|
|
|
swdata->target_format = target_format;
|
|
r_2_pix_alloc = &swdata->rgb_2_pix[0 * 768];
|
|
g_2_pix_alloc = &swdata->rgb_2_pix[1 * 768];
|
|
b_2_pix_alloc = &swdata->rgb_2_pix[2 * 768];
|
|
|
|
/*
|
|
* Set up entries 0-255 in rgb-to-pixel value tables.
|
|
*/
|
|
for (i = 0; i < 256; ++i) {
|
|
r_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Rmask));
|
|
r_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Rmask);
|
|
r_2_pix_alloc[i + 256] |= Amask;
|
|
g_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Gmask));
|
|
g_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Gmask);
|
|
g_2_pix_alloc[i + 256] |= Amask;
|
|
b_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Bmask));
|
|
b_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Bmask);
|
|
b_2_pix_alloc[i + 256] |= Amask;
|
|
}
|
|
|
|
/*
|
|
* If we have 16-bit output depth, then we double the value
|
|
* in the top word. This means that we can write out both
|
|
* pixels in the pixel doubling mode with one op. It is
|
|
* harmless in the normal case as storing a 32-bit value
|
|
* through a short pointer will lose the top bits anyway.
|
|
*/
|
|
if (SDL_BYTESPERPIXEL(target_format) == 2) {
|
|
for (i = 0; i < 256; ++i) {
|
|
r_2_pix_alloc[i + 256] |= (r_2_pix_alloc[i + 256]) << 16;
|
|
g_2_pix_alloc[i + 256] |= (g_2_pix_alloc[i + 256]) << 16;
|
|
b_2_pix_alloc[i + 256] |= (b_2_pix_alloc[i + 256]) << 16;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Spread out the values we have to the rest of the array so that
|
|
* we do not need to check for overflow.
|
|
*/
|
|
for (i = 0; i < 256; ++i) {
|
|
r_2_pix_alloc[i] = r_2_pix_alloc[256];
|
|
r_2_pix_alloc[i + 512] = r_2_pix_alloc[511];
|
|
g_2_pix_alloc[i] = g_2_pix_alloc[256];
|
|
g_2_pix_alloc[i + 512] = g_2_pix_alloc[511];
|
|
b_2_pix_alloc[i] = b_2_pix_alloc[256];
|
|
b_2_pix_alloc[i + 512] = b_2_pix_alloc[511];
|
|
}
|
|
|
|
/* You have chosen wisely... */
|
|
switch (swdata->format) {
|
|
case SDL_PIXELFORMAT_YV12:
|
|
case SDL_PIXELFORMAT_IYUV:
|
|
if (SDL_BYTESPERPIXEL(target_format) == 2) {
|
|
#if (__GNUC__ > 2) && defined(__i386__) && __OPTIMIZE__ && SDL_ASSEMBLY_ROUTINES
|
|
/* inline assembly functions */
|
|
if (SDL_HasMMX() && (Rmask == 0xF800) &&
|
|
(Gmask == 0x07E0) && (Bmask == 0x001F)
|
|
&& (swdata->w & 15) == 0) {
|
|
/* printf("Using MMX 16-bit 565 dither\n"); */
|
|
swdata->Display1X = Color565DitherYV12MMX1X;
|
|
} else {
|
|
/* printf("Using C 16-bit dither\n"); */
|
|
swdata->Display1X = Color16DitherYV12Mod1X;
|
|
}
|
|
#else
|
|
swdata->Display1X = Color16DitherYV12Mod1X;
|
|
#endif
|
|
swdata->Display2X = Color16DitherYV12Mod2X;
|
|
}
|
|
if (SDL_BYTESPERPIXEL(target_format) == 3) {
|
|
swdata->Display1X = Color24DitherYV12Mod1X;
|
|
swdata->Display2X = Color24DitherYV12Mod2X;
|
|
}
|
|
if (SDL_BYTESPERPIXEL(target_format) == 4) {
|
|
#if (__GNUC__ > 2) && defined(__i386__) && __OPTIMIZE__ && SDL_ASSEMBLY_ROUTINES
|
|
/* inline assembly functions */
|
|
if (SDL_HasMMX() && (Rmask == 0x00FF0000) &&
|
|
(Gmask == 0x0000FF00) &&
|
|
(Bmask == 0x000000FF) && (swdata->w & 15) == 0) {
|
|
/* printf("Using MMX 32-bit dither\n"); */
|
|
swdata->Display1X = ColorRGBDitherYV12MMX1X;
|
|
} else {
|
|
/* printf("Using C 32-bit dither\n"); */
|
|
swdata->Display1X = Color32DitherYV12Mod1X;
|
|
}
|
|
#else
|
|
swdata->Display1X = Color32DitherYV12Mod1X;
|
|
#endif
|
|
swdata->Display2X = Color32DitherYV12Mod2X;
|
|
}
|
|
break;
|
|
case SDL_PIXELFORMAT_YUY2:
|
|
case SDL_PIXELFORMAT_UYVY:
|
|
case SDL_PIXELFORMAT_YVYU:
|
|
if (SDL_BYTESPERPIXEL(target_format) == 2) {
|
|
swdata->Display1X = Color16DitherYUY2Mod1X;
|
|
swdata->Display2X = Color16DitherYUY2Mod2X;
|
|
}
|
|
if (SDL_BYTESPERPIXEL(target_format) == 3) {
|
|
swdata->Display1X = Color24DitherYUY2Mod1X;
|
|
swdata->Display2X = Color24DitherYUY2Mod2X;
|
|
}
|
|
if (SDL_BYTESPERPIXEL(target_format) == 4) {
|
|
swdata->Display1X = Color32DitherYUY2Mod1X;
|
|
swdata->Display2X = Color32DitherYUY2Mod2X;
|
|
}
|
|
break;
|
|
default:
|
|
/* We should never get here (caught above) */
|
|
break;
|
|
}
|
|
|
|
SDL_FreeSurface(swdata->display);
|
|
swdata->display = NULL;
|
|
return 0;
|
|
}
|
|
|
|
SDL_SW_YUVTexture *
|
|
SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
|
|
{
|
|
SDL_SW_YUVTexture *swdata;
|
|
int *Cr_r_tab;
|
|
int *Cr_g_tab;
|
|
int *Cb_g_tab;
|
|
int *Cb_b_tab;
|
|
int i;
|
|
int CR, CB;
|
|
|
|
switch (format) {
|
|
case SDL_PIXELFORMAT_YV12:
|
|
case SDL_PIXELFORMAT_IYUV:
|
|
case SDL_PIXELFORMAT_YUY2:
|
|
case SDL_PIXELFORMAT_UYVY:
|
|
case SDL_PIXELFORMAT_YVYU:
|
|
break;
|
|
default:
|
|
SDL_SetError("Unsupported YUV format");
|
|
return NULL;
|
|
}
|
|
|
|
swdata = (SDL_SW_YUVTexture *) SDL_calloc(1, sizeof(*swdata));
|
|
if (!swdata) {
|
|
SDL_OutOfMemory();
|
|
return NULL;
|
|
}
|
|
|
|
swdata->format = format;
|
|
swdata->target_format = SDL_PIXELFORMAT_UNKNOWN;
|
|
swdata->w = w;
|
|
swdata->h = h;
|
|
swdata->pixels = (Uint8 *) SDL_malloc(w * h * 2);
|
|
swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int));
|
|
swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32));
|
|
if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) {
|
|
SDL_SW_DestroyYUVTexture(swdata);
|
|
SDL_OutOfMemory();
|
|
return NULL;
|
|
}
|
|
|
|
/* Generate the tables for the display surface */
|
|
Cr_r_tab = &swdata->colortab[0 * 256];
|
|
Cr_g_tab = &swdata->colortab[1 * 256];
|
|
Cb_g_tab = &swdata->colortab[2 * 256];
|
|
Cb_b_tab = &swdata->colortab[3 * 256];
|
|
for (i = 0; i < 256; i++) {
|
|
/* Gamma correction (luminescence table) and chroma correction
|
|
would be done here. See the Berkeley mpeg_play sources.
|
|
*/
|
|
CB = CR = (i - 128);
|
|
Cr_r_tab[i] = (int) ((0.419 / 0.299) * CR);
|
|
Cr_g_tab[i] = (int) (-(0.299 / 0.419) * CR);
|
|
Cb_g_tab[i] = (int) (-(0.114 / 0.331) * CB);
|
|
Cb_b_tab[i] = (int) ((0.587 / 0.331) * CB);
|
|
}
|
|
|
|
/* Find the pitch and offset values for the overlay */
|
|
switch (format) {
|
|
case SDL_PIXELFORMAT_YV12:
|
|
case SDL_PIXELFORMAT_IYUV:
|
|
swdata->pitches[0] = w;
|
|
swdata->pitches[1] = swdata->pitches[0] / 2;
|
|
swdata->pitches[2] = swdata->pitches[0] / 2;
|
|
swdata->planes[0] = swdata->pixels;
|
|
swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
|
|
swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * h / 2;
|
|
break;
|
|
case SDL_PIXELFORMAT_YUY2:
|
|
case SDL_PIXELFORMAT_UYVY:
|
|
case SDL_PIXELFORMAT_YVYU:
|
|
swdata->pitches[0] = w * 2;
|
|
swdata->planes[0] = swdata->pixels;
|
|
break;
|
|
default:
|
|
SDL_assert(0 && "We should never get here (caught above)");
|
|
break;
|
|
}
|
|
|
|
/* We're all done.. */
|
|
return (swdata);
|
|
}
|
|
|
|
int
|
|
SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels,
|
|
int *pitch)
|
|
{
|
|
*pixels = swdata->planes[0];
|
|
*pitch = swdata->pitches[0];
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
|
const void *pixels, int pitch)
|
|
{
|
|
switch (swdata->format) {
|
|
case SDL_PIXELFORMAT_YV12:
|
|
case SDL_PIXELFORMAT_IYUV:
|
|
if (rect->x == 0 && rect->y == 0 &&
|
|
rect->w == swdata->w && rect->h == swdata->h) {
|
|
SDL_memcpy(swdata->pixels, pixels,
|
|
(swdata->h * swdata->w) + (swdata->h * swdata->w) / 2);
|
|
} else {
|
|
Uint8 *src, *dst;
|
|
int row;
|
|
size_t length;
|
|
|
|
/* Copy the Y plane */
|
|
src = (Uint8 *) pixels;
|
|
dst = swdata->pixels + rect->y * swdata->w + rect->x;
|
|
length = rect->w;
|
|
for (row = 0; row < rect->h; ++row) {
|
|
SDL_memcpy(dst, src, length);
|
|
src += pitch;
|
|
dst += swdata->w;
|
|
}
|
|
|
|
/* Copy the next plane */
|
|
src = (Uint8 *) pixels + rect->h * pitch;
|
|
dst = swdata->pixels + swdata->h * swdata->w;
|
|
dst += rect->y/2 * swdata->w/2 + rect->x/2;
|
|
length = rect->w / 2;
|
|
for (row = 0; row < rect->h/2; ++row) {
|
|
SDL_memcpy(dst, src, length);
|
|
src += pitch/2;
|
|
dst += swdata->w/2;
|
|
}
|
|
|
|
/* Copy the next plane */
|
|
src = (Uint8 *) pixels + rect->h * pitch + (rect->h * pitch) / 4;
|
|
dst = swdata->pixels + swdata->h * swdata->w +
|
|
(swdata->h * swdata->w) / 4;
|
|
dst += rect->y/2 * swdata->w/2 + rect->x/2;
|
|
length = rect->w / 2;
|
|
for (row = 0; row < rect->h/2; ++row) {
|
|
SDL_memcpy(dst, src, length);
|
|
src += pitch/2;
|
|
dst += swdata->w/2;
|
|
}
|
|
}
|
|
break;
|
|
case SDL_PIXELFORMAT_YUY2:
|
|
case SDL_PIXELFORMAT_UYVY:
|
|
case SDL_PIXELFORMAT_YVYU:
|
|
{
|
|
Uint8 *src, *dst;
|
|
int row;
|
|
size_t length;
|
|
|
|
src = (Uint8 *) pixels;
|
|
dst =
|
|
swdata->planes[0] + rect->y * swdata->pitches[0] +
|
|
rect->x * 2;
|
|
length = rect->w * 2;
|
|
for (row = 0; row < rect->h; ++row) {
|
|
SDL_memcpy(dst, src, length);
|
|
src += pitch;
|
|
dst += swdata->pitches[0];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
|
const Uint8 *Yplane, int Ypitch,
|
|
const Uint8 *Uplane, int Upitch,
|
|
const Uint8 *Vplane, int Vpitch)
|
|
{
|
|
const Uint8 *src;
|
|
Uint8 *dst;
|
|
int row;
|
|
size_t length;
|
|
|
|
/* Copy the Y plane */
|
|
src = Yplane;
|
|
dst = swdata->pixels + rect->y * swdata->w + rect->x;
|
|
length = rect->w;
|
|
for (row = 0; row < rect->h; ++row) {
|
|
SDL_memcpy(dst, src, length);
|
|
src += Ypitch;
|
|
dst += swdata->w;
|
|
}
|
|
|
|
/* Copy the U plane */
|
|
src = Uplane;
|
|
if (swdata->format == SDL_PIXELFORMAT_IYUV) {
|
|
dst = swdata->pixels + swdata->h * swdata->w;
|
|
} else {
|
|
dst = swdata->pixels + swdata->h * swdata->w +
|
|
(swdata->h * swdata->w) / 4;
|
|
}
|
|
dst += rect->y/2 * swdata->w/2 + rect->x/2;
|
|
length = rect->w / 2;
|
|
for (row = 0; row < rect->h/2; ++row) {
|
|
SDL_memcpy(dst, src, length);
|
|
src += Upitch;
|
|
dst += swdata->w/2;
|
|
}
|
|
|
|
/* Copy the V plane */
|
|
src = Vplane;
|
|
if (swdata->format == SDL_PIXELFORMAT_YV12) {
|
|
dst = swdata->pixels + swdata->h * swdata->w;
|
|
} else {
|
|
dst = swdata->pixels + swdata->h * swdata->w +
|
|
(swdata->h * swdata->w) / 4;
|
|
}
|
|
dst += rect->y/2 * swdata->w/2 + rect->x/2;
|
|
length = rect->w / 2;
|
|
for (row = 0; row < rect->h/2; ++row) {
|
|
SDL_memcpy(dst, src, length);
|
|
src += Vpitch;
|
|
dst += swdata->w/2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
|
void **pixels, int *pitch)
|
|
{
|
|
switch (swdata->format) {
|
|
case SDL_PIXELFORMAT_YV12:
|
|
case SDL_PIXELFORMAT_IYUV:
|
|
if (rect
|
|
&& (rect->x != 0 || rect->y != 0 || rect->w != swdata->w
|
|
|| rect->h != swdata->h)) {
|
|
return SDL_SetError
|
|
("YV12 and IYUV textures only support full surface locks");
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (rect) {
|
|
*pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2;
|
|
} else {
|
|
*pixels = swdata->planes[0];
|
|
}
|
|
*pitch = swdata->pitches[0];
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata)
|
|
{
|
|
}
|
|
|
|
int
|
|
SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect,
|
|
Uint32 target_format, int w, int h, void *pixels,
|
|
int pitch)
|
|
{
|
|
const int targetbpp = SDL_BYTESPERPIXEL(target_format);
|
|
int stretch;
|
|
int scale_2x;
|
|
Uint8 *lum, *Cr, *Cb;
|
|
int mod;
|
|
|
|
if (targetbpp == 0) {
|
|
return SDL_SetError("Invalid target pixel format");
|
|
}
|
|
|
|
/* Make sure we're set up to display in the desired format */
|
|
if (target_format != swdata->target_format) {
|
|
if (SDL_SW_SetupYUVDisplay(swdata, target_format) < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
stretch = 0;
|
|
scale_2x = 0;
|
|
if (srcrect->x || srcrect->y || srcrect->w < swdata->w
|
|
|| srcrect->h < swdata->h) {
|
|
/* The source rectangle has been clipped.
|
|
Using a scratch surface is easier than adding clipped
|
|
source support to all the blitters, plus that would
|
|
slow them down in the general unclipped case.
|
|
*/
|
|
stretch = 1;
|
|
} else if ((srcrect->w != w) || (srcrect->h != h)) {
|
|
if ((w == 2 * srcrect->w) && (h == 2 * srcrect->h)) {
|
|
scale_2x = 1;
|
|
} else {
|
|
stretch = 1;
|
|
}
|
|
}
|
|
if (stretch) {
|
|
int bpp;
|
|
Uint32 Rmask, Gmask, Bmask, Amask;
|
|
|
|
if (swdata->display) {
|
|
swdata->display->w = w;
|
|
swdata->display->h = h;
|
|
swdata->display->pixels = pixels;
|
|
swdata->display->pitch = pitch;
|
|
} else {
|
|
/* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
|
|
SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
|
|
&Bmask, &Amask);
|
|
swdata->display =
|
|
SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask,
|
|
Gmask, Bmask, Amask);
|
|
if (!swdata->display) {
|
|
return (-1);
|
|
}
|
|
}
|
|
if (!swdata->stretch) {
|
|
/* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
|
|
SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
|
|
&Bmask, &Amask);
|
|
swdata->stretch =
|
|
SDL_CreateRGBSurface(0, swdata->w, swdata->h, bpp, Rmask,
|
|
Gmask, Bmask, Amask);
|
|
if (!swdata->stretch) {
|
|
return (-1);
|
|
}
|
|
}
|
|
pixels = swdata->stretch->pixels;
|
|
pitch = swdata->stretch->pitch;
|
|
}
|
|
switch (swdata->format) {
|
|
case SDL_PIXELFORMAT_YV12:
|
|
lum = swdata->planes[0];
|
|
Cr = swdata->planes[1];
|
|
Cb = swdata->planes[2];
|
|
break;
|
|
case SDL_PIXELFORMAT_IYUV:
|
|
lum = swdata->planes[0];
|
|
Cr = swdata->planes[2];
|
|
Cb = swdata->planes[1];
|
|
break;
|
|
case SDL_PIXELFORMAT_YUY2:
|
|
lum = swdata->planes[0];
|
|
Cr = lum + 3;
|
|
Cb = lum + 1;
|
|
break;
|
|
case SDL_PIXELFORMAT_UYVY:
|
|
lum = swdata->planes[0] + 1;
|
|
Cr = lum + 1;
|
|
Cb = lum - 1;
|
|
break;
|
|
case SDL_PIXELFORMAT_YVYU:
|
|
lum = swdata->planes[0];
|
|
Cr = lum + 1;
|
|
Cb = lum + 3;
|
|
break;
|
|
default:
|
|
return SDL_SetError("Unsupported YUV format in copy");
|
|
}
|
|
mod = (pitch / targetbpp);
|
|
|
|
if (scale_2x) {
|
|
mod -= (swdata->w * 2);
|
|
swdata->Display2X(swdata->colortab, swdata->rgb_2_pix,
|
|
lum, Cr, Cb, pixels, swdata->h, swdata->w, mod);
|
|
} else {
|
|
mod -= swdata->w;
|
|
swdata->Display1X(swdata->colortab, swdata->rgb_2_pix,
|
|
lum, Cr, Cb, pixels, swdata->h, swdata->w, mod);
|
|
}
|
|
if (stretch) {
|
|
SDL_Rect rect = *srcrect;
|
|
SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata)
|
|
{
|
|
if (swdata) {
|
|
SDL_free(swdata->pixels);
|
|
SDL_free(swdata->colortab);
|
|
SDL_free(swdata->rgb_2_pix);
|
|
SDL_FreeSurface(swdata->stretch);
|
|
SDL_FreeSurface(swdata->display);
|
|
SDL_free(swdata);
|
|
}
|
|
}
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|