Updated SDL's YUV support, many thanks to Adrien Descamps

New functions get and set the YUV colorspace conversion mode:
	SDL_SetYUVConversionMode()
	SDL_GetYUVConversionMode()
	SDL_GetYUVConversionModeForResolution()

SDL_ConvertPixels() converts between all supported RGB and YUV formats, with SSE acceleration for converting from planar YUV formats (YV12, NV12, etc) to common RGB/RGBA formats.

Added a new test program, testyuv, to verify correctness and speed of YUV conversion functionality.
This commit is contained in:
Sam Lantinga 2017-11-12 22:51:12 -08:00
parent e7cc03e0bd
commit 145d2469ae
60 changed files with 8368 additions and 4310 deletions

View file

@ -25,17 +25,8 @@
#include "SDL_blit.h"
#include "SDL_RLEaccel_c.h"
#include "SDL_pixels_c.h"
#include "SDL_yuv_c.h"
/* Private routines */
static int
SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height,
Uint32 src_format, const void *src,
void *dst, int dst_pitch);
static int
SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height,
const void *src, int src_pitch,
Uint32 dst_format, void *dst);
/* Check to make sure we can safely check multiplication of surface w and pitch and it won't overflow size_t */
SDL_COMPILE_TIME_ASSERT(surface_size_assumptions,
@ -43,6 +34,30 @@ SDL_COMPILE_TIME_ASSERT(surface_size_assumptions,
/* Public routines */
/*
* Calculate the pad-aligned scanline width of a surface
*/
int
SDL_CalculatePitch(Uint32 format, int width)
{
int pitch;
/* Surface should be 4-byte aligned for speed */
pitch = width * SDL_BYTESPERPIXEL(format);
switch (SDL_BITSPERPIXEL(format)) {
case 1:
pitch = (pitch + 7) / 8;
break;
case 4:
pitch = (pitch + 1) / 2;
break;
default:
break;
}
pitch = (pitch + 3) & ~3; /* 4-byte aligning */
return pitch;
}
/*
* Create an empty RGB surface of the appropriate depth using the given
* enum SDL_PIXELFORMAT_* format
@ -70,7 +85,7 @@ SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
}
surface->w = width;
surface->h = height;
surface->pitch = SDL_CalculatePitch(surface);
surface->pitch = SDL_CalculatePitch(format, width);
SDL_SetClipRect(surface, NULL);
if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
@ -1138,135 +1153,27 @@ int SDL_ConvertPixels(int width, int height,
return SDL_InvalidParamError("dst_pitch");
}
if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
} else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
} else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
}
/* Fast path for same format copy */
if (src_format == dst_format) {
int i;
if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
switch (src_format) {
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
/* Packed planes */
width = 4 * ((width + 1) / 2);
for (i = height; i--;) {
SDL_memcpy(dst, src, width);
src = (const Uint8*)src + src_pitch;
dst = (Uint8*)dst + dst_pitch;
}
break;
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
{
/* Y plane */
for (i = height; i--;) {
SDL_memcpy(dst, src, width);
src = (const Uint8*)src + src_pitch;
dst = (Uint8*)dst + dst_pitch;
}
/* not sure the pitch is relevant here.
this also works to add the size of two chroma planes */
#if 0
SDL_memcpy(dst, src, 2 * ((width + 1)/2) * ((height+1)/2));
#else
if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) {
/* U and V planes are a quarter the size of the Y plane */
width = (width + 1) / 2;
height = (height + 1) / 2;
src_pitch = (src_pitch + 1) / 2;
dst_pitch = (dst_pitch + 1) / 2;
for (i = height * 2; i--;) {
SDL_memcpy(dst, src, width);
src = (const Uint8*)src + src_pitch;
dst = (Uint8*)dst + dst_pitch;
}
} else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
/* U/V plane is half the height of the Y plane */
height = (height + 1) / 2;
width = (width + 1) / 2;
src_pitch = (src_pitch + 1) / 2;
dst_pitch = (dst_pitch + 1) / 2;
for (i = height; i--;) {
SDL_memcpy(dst, src, 2 * width);
src = (const Uint8*)src + 2 * src_pitch;
dst = (Uint8*)dst + 2 * dst_pitch;
}
}
#endif
}
break;
default:
return SDL_SetError("Unknown FOURCC pixel format");
}
} else {
const int bpp = SDL_BYTESPERPIXEL(src_format);
width *= bpp;
for (i = height; i--;) {
SDL_memcpy(dst, src, width);
src = (const Uint8*)src + src_pitch;
dst = (Uint8*)dst + dst_pitch;
}
const int bpp = SDL_BYTESPERPIXEL(src_format);
width *= bpp;
for (i = height; i--;) {
SDL_memcpy(dst, src, width);
src = (const Uint8*)src + src_pitch;
dst = (Uint8*)dst + dst_pitch;
}
return 0;
}
/* FOURCC to Any */
if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
/* FOURCC to ARGB8888 */
if (dst_format == SDL_PIXELFORMAT_ARGB8888) {
SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, dst, dst_pitch);
return 0;
}
else /* FOURCC to not(ARGB8888) : need an intermediate conversion */
{
int ret;
void *tmp = SDL_malloc(width * height * 4);
if (tmp == NULL) {
return -1;
}
/* convert src/FOURCC to tmp/ARGB8888 */
SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, tmp, width * 4);
/* convert tmp/ARGB8888 to dst/dst_format */
ret = SDL_ConvertPixels(width, height, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4, dst_format, dst, dst_pitch);
SDL_free(tmp);
return ret;
}
}
/* Any to FOURCC */
if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
/* ARGB8888 to FOURCC */
if (src_format == SDL_PIXELFORMAT_ARGB8888) {
SDL_ConvertPixels_ARGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst);
return 0;
}
else /* not(ARGB8888) to FOURCC : need an intermediate conversion */
{
int ret;
void *tmp = SDL_malloc(width * height * 4);
if (tmp == NULL) {
return -1;
}
/* convert src/src_format to tmp/ARGB8888 */
ret = SDL_ConvertPixels(width, height, src_format, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4);
if (ret == -1) {
SDL_free(tmp);
return ret;
}
/* convert tmp/ARGB8888 to dst/FOURCC */
SDL_ConvertPixels_ARGB8888_to_YUV(width, height, tmp, width * 4, dst_format, dst);
SDL_free(tmp);
return 0;
}
}
if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
src_pitch,
&src_surface, &src_fmt, &src_blitmap)) {
@ -1322,491 +1229,4 @@ SDL_FreeSurface(SDL_Surface * surface)
SDL_free(surface);
}
/* YUV-RGB conversion */
#define CLAMP(val) ((val) > 0 ? ((val) < 255 ? (val) : 255) : 0)
#if 1
/* Coefficients from CCIR 601 */
#define MAKE_Y(r, g, b) (int)( 0.29900f * (r) + 0.58700f * (g) + 0.11400f * (b))
#define MAKE_U(r, g, b) (int)(-0.16874f * (r) - 0.33126f * (g) + 0.50000f * (b) + 128)
#define MAKE_V(r, g, b) (int)( 0.50000f * (r) - 0.41869f * (g) - 0.08131f * (b) + 128)
#define MAKE_R(y, u, v) CLAMP((int)((y) + 1.40200f * ((v) - 128)))
#define MAKE_G(y, u, v) CLAMP((int)((y) - 0.34414f * ((u) - 128) - 0.71414f * ((v) - 128)))
#define MAKE_B(y, u, v) CLAMP((int)((y) + 1.77200f * ((u) - 128) ))
#else
/* Coefficients from Video Demystified */
#define MAKE_Y(r, g, b) ((( 66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16)
#define MAKE_U(r, g, b) ((( -38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128)
#define MAKE_V(r, g, b) ((( 112 * (r) - 94 * (g) - 18 * (b) + 128) >> 8) + 128)
#define MAKE_R(y, u, v) CLAMP(( 298 * ((y) - 16) + 409 * ((v) - 128) + 128) >> 8)
#define MAKE_G(y, u, v) CLAMP(( 298 * ((y) - 16) - 100 * ((u) - 128) - 208 * ((v) - 128) + 128) >> 8)
#define MAKE_B(y, u, v) CLAMP(( 298 * ((y) - 16) + 516 * ((u) - 128) + 128) >> 8)
#endif
static int
SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height,
Uint32 src_format, const void *src,
void *dst, int dst_pitch)
{
const int sz_plane = width * height;
const int sz_plane_chroma = ((width + 1) / 2) * ((height + 1) / 2);
const int width_remainder = (width & 0x1);
const int width_half = width / 2;
const int curr_row_padding = dst_pitch - 4 * width;
int i, j;
Uint8 *curr_row = (Uint8*)dst;
// SDL_Log("SDL_ConvertPixels_YUV_to_ARGB8888 (from %s)", SDL_GetPixelFormatName(src_format));
#define WRITE_RGB_PIXEL(y, u, v) \
*((Uint32*)curr_row) = \
(MAKE_B((y), (u), (v)) \
| (MAKE_G((y), (u), (v)) << 8) \
| (MAKE_R((y), (u), (v)) << 16) \
| 0xff000000); \
curr_row += 4; \
switch (src_format)
{
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
{
const Uint8 *plane_y = (const Uint8*)src;
if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV)
{
const Uint8 *plane_u = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane);
const Uint8 *plane_v = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma);
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
const Uint8 u = *plane_u++;
const Uint8 v = *plane_v++;
const Uint8 y = *plane_y++;
const Uint8 y1 = *plane_y++;
WRITE_RGB_PIXEL(y, u, v);
WRITE_RGB_PIXEL(y1, u, v);
}
if (width_remainder) {
const Uint8 u = *plane_u++;
const Uint8 v = *plane_v++;
const Uint8 y = *plane_y++;
WRITE_RGB_PIXEL(y, u, v);
}
/* Re-use the same line of chroma planes */
if ((j & 0x1) == 0x0) {
plane_u -= width_half + width_remainder;
plane_v -= width_half + width_remainder;
}
curr_row += curr_row_padding;
}
}
else if (src_format == SDL_PIXELFORMAT_NV12)
{
const Uint8 *plane_interleaved_uv = plane_y + sz_plane;
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
const Uint8 y = *plane_y++;
const Uint8 y1 = *plane_y++;
const Uint8 u = *plane_interleaved_uv++;
const Uint8 v = *plane_interleaved_uv++;
WRITE_RGB_PIXEL(y, u, v);
WRITE_RGB_PIXEL(y1, u, v);
}
if (width_remainder) {
const Uint8 y = *plane_y++;
const Uint8 u = *plane_interleaved_uv++;
const Uint8 v = *plane_interleaved_uv++;
WRITE_RGB_PIXEL(y, u, v);
}
/* Re-use the same line of chroma planes */
if ((j & 0x1) == 0x0) {
plane_interleaved_uv -= 2 * (width_half + width_remainder);
}
curr_row += curr_row_padding;
}
}
else /* src_format == SDL_PIXELFORMAT_NV21 */
{
const Uint8 *plane_interleaved_uv = plane_y + sz_plane;
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
const Uint8 y = *plane_y++;
const Uint8 y1 = *plane_y++;
const Uint8 v = *plane_interleaved_uv++;
const Uint8 u = *plane_interleaved_uv++;
WRITE_RGB_PIXEL(y, u, v);
WRITE_RGB_PIXEL(y1, u, v);
}
if (width_remainder) {
const Uint8 y = *plane_y++;
const Uint8 v = *plane_interleaved_uv++;
const Uint8 u = *plane_interleaved_uv++;
WRITE_RGB_PIXEL(y, u, v);
}
/* Re-use the same line of chroma planes */
if ((j & 0x1) == 0x0) {
plane_interleaved_uv -= 2 * (width_half + width_remainder);
}
curr_row += curr_row_padding;
}
}
}
break;
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
{
const Uint8 *plane = (const Uint8 *)src;
#define READ_PACKED_YUV(var1, var2, var3, var4) \
const Uint8 var1 = plane[0]; \
const Uint8 var2 = plane[1]; \
const Uint8 var3 = plane[2]; \
const Uint8 var4 = plane[3]; \
plane += 4; \
if (src_format == SDL_PIXELFORMAT_YUY2) /* Y U Y1 V */
{
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
READ_PACKED_YUV(y, u, y1, v);
WRITE_RGB_PIXEL(y, u, v);
WRITE_RGB_PIXEL(y1, u, v);
}
if (width_remainder) {
READ_PACKED_YUV(y, u, y1, v);
(void)y1; /* y1 unused */
WRITE_RGB_PIXEL(y, u, v);
}
curr_row += curr_row_padding;
}
}
else if (src_format == SDL_PIXELFORMAT_UYVY) /* U Y V Y1 */
{
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
READ_PACKED_YUV(u, y, v, y1);
WRITE_RGB_PIXEL(y, u, v);
WRITE_RGB_PIXEL(y1, u, v);
}
if (width_remainder) {
READ_PACKED_YUV(u, y, v, y1);
(void) y1; /* y1 unused */
WRITE_RGB_PIXEL(y, u, v);
}
curr_row += curr_row_padding;
}
}
else if (src_format == SDL_PIXELFORMAT_YVYU) /* Y V Y1 U */
{
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
READ_PACKED_YUV(y, v, y1, u);
WRITE_RGB_PIXEL(y, u, v);
WRITE_RGB_PIXEL(y1, u, v);
}
if (width_remainder) {
READ_PACKED_YUV(y, v, y1, u);
(void) y1; /* y1 unused */
WRITE_RGB_PIXEL(y, u, v);
}
curr_row += curr_row_padding;
}
}
#undef READ_PACKED_YUV
}
break;
}
#undef WRITE_RGB_PIXEL
return 0;
}
static int
SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *src, int src_pitch, Uint32 dst_format, void *dst)
{
const int src_pitch_x_2 = src_pitch * 2;
const int sz_plane = width * height;
const int sz_plane_chroma = ((width + 1) / 2) * ((height + 1) / 2);
const int height_half = height / 2;
const int height_remainder = (height & 0x1);
const int width_half = width / 2;
const int width_remainder = (width & 0x1);
int i, j;
// SDL_Log("SDL_ConvertPixels_ARGB8888_to_YUV (to %s)", SDL_GetPixelFormatName(dst_format));
switch (dst_format)
{
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
{
const Uint8 *curr_row, *next_row;
Uint8 *plane_y = (Uint8*) dst;
Uint8 *plane_u = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane);
Uint8 *plane_v = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma);
Uint8 *plane_interleaved_uv = plane_y + sz_plane;
curr_row = (const Uint8*)src;
/* Write Y plane */
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
const Uint8 b = curr_row[4 * i + 0];
const Uint8 g = curr_row[4 * i + 1];
const Uint8 r = curr_row[4 * i + 2];
*plane_y++ = MAKE_Y(r, g, b);
}
curr_row += src_pitch;
}
curr_row = (const Uint8*)src;
next_row = (const Uint8*)src;
next_row += src_pitch;
#if 1
/* slightly faster */
#define READ_2x2_PIXELS \
const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \
const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1]; \
const Uint32 p3 = ((const Uint32 *)next_row)[2 * i]; \
const Uint32 p4 = ((const Uint32 *)next_row)[2 * i + 1]; \
const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff) + (p3 & 0x000000ff) + (p4 & 0x000000ff)) >> 2; \
const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00) + (p3 & 0x0000ff00) + (p4 & 0x0000ff00)) >> 10; \
const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000) + (p3 & 0x00ff0000) + (p4 & 0x00ff0000)) >> 18; \
#else
#define READ_2x2_PIXELS \
const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4] \
+ next_row[8 * i + 0] + next_row[8 * i + 4] ) >> 2; \
const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5] \
+ next_row[8 * i + 1] + next_row[8 * i + 5] ) >> 2; \
const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6] \
+ next_row[8 * i + 2] + next_row[8 * i + 6] ) >> 2; \
#endif
#define READ_2x1_PIXELS \
const Uint8 b = (curr_row[8 * i + 0] + next_row[8 * i + 0]) >> 1; \
const Uint8 g = (curr_row[8 * i + 1] + next_row[8 * i + 1]) >> 1; \
const Uint8 r = (curr_row[8 * i + 2] + next_row[8 * i + 2]) >> 1; \
#define READ_1x2_PIXELS \
const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4]) >> 1; \
const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5]) >> 1; \
const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6]) >> 1; \
#define READ_1x1_PIXEL \
const Uint8 b = curr_row[8 * i + 0]; \
const Uint8 g = curr_row[8 * i + 1]; \
const Uint8 r = curr_row[8 * i + 2]; \
if (dst_format == SDL_PIXELFORMAT_YV12 || dst_format == SDL_PIXELFORMAT_IYUV)
{
/* Write UV planes, not interleaved */
for (j = 0; j < height_half; j++) {
for (i = 0; i < width_half; i++) {
READ_2x2_PIXELS;
*plane_u++ = MAKE_U(r, g, b);
*plane_v++ = MAKE_V(r, g, b);
}
if (width_remainder) {
READ_2x1_PIXELS;
*plane_u++ = MAKE_U(r, g, b);
*plane_v++ = MAKE_V(r, g, b);
}
curr_row += src_pitch_x_2;
next_row += src_pitch_x_2;
}
if (height_remainder) {
for (i = 0; i < width_half; i++) {
READ_1x2_PIXELS;
*plane_u++ = MAKE_U(r, g, b);
*plane_v++ = MAKE_V(r, g, b);
}
if (width_remainder) {
READ_1x1_PIXEL;
*plane_u++ = MAKE_U(r, g, b);
*plane_v++ = MAKE_V(r, g, b);
}
}
}
else if (dst_format == SDL_PIXELFORMAT_NV12)
{
for (j = 0; j < height_half; j++) {
for (i = 0; i < width_half; i++) {
READ_2x2_PIXELS;
*plane_interleaved_uv++ = MAKE_U(r, g, b);
*plane_interleaved_uv++ = MAKE_V(r, g, b);
}
if (width_remainder) {
READ_2x1_PIXELS;
*plane_interleaved_uv++ = MAKE_U(r, g, b);
*plane_interleaved_uv++ = MAKE_V(r, g, b);
}
curr_row += src_pitch_x_2;
next_row += src_pitch_x_2;
}
if (height_remainder) {
for (i = 0; i < width_half; i++) {
READ_1x2_PIXELS;
*plane_interleaved_uv++ = MAKE_U(r, g, b);
*plane_interleaved_uv++ = MAKE_V(r, g, b);
}
if (width_remainder) {
READ_1x1_PIXEL;
*plane_interleaved_uv++ = MAKE_U(r, g, b);
*plane_interleaved_uv++ = MAKE_V(r, g, b);
}
}
}
else /* dst_format == SDL_PIXELFORMAT_NV21 */
{
for (j = 0; j < height_half; j++) {
for (i = 0; i < width_half; i++) {
READ_2x2_PIXELS;
*plane_interleaved_uv++ = MAKE_V(r, g, b);
*plane_interleaved_uv++ = MAKE_U(r, g, b);
}
if (width_remainder) {
READ_2x1_PIXELS;
*plane_interleaved_uv++ = MAKE_V(r, g, b);
*plane_interleaved_uv++ = MAKE_U(r, g, b);
}
curr_row += src_pitch_x_2;
next_row += src_pitch_x_2;
}
if (height_remainder) {
for (i = 0; i < width_half; i++) {
READ_1x2_PIXELS;
*plane_interleaved_uv++ = MAKE_V(r, g, b);
*plane_interleaved_uv++ = MAKE_U(r, g, b);
}
if (width_remainder) {
READ_1x1_PIXEL;
*plane_interleaved_uv++ = MAKE_V(r, g, b);
*plane_interleaved_uv++ = MAKE_U(r, g, b);
}
}
}
#undef READ_2x2_PIXELS
#undef READ_2x1_PIXELS
#undef READ_1x2_PIXELS
#undef READ_1x1_PIXEL
}
break;
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
{
const Uint8 *curr_row = (const Uint8*) src;
Uint8 *plane = (Uint8*) dst;
#define READ_TWO_RGB_PIXELS \
const Uint8 b = curr_row[8 * i + 0]; \
const Uint8 g = curr_row[8 * i + 1]; \
const Uint8 r = curr_row[8 * i + 2]; \
const Uint8 b1 = curr_row[8 * i + 4]; \
const Uint8 g1 = curr_row[8 * i + 5]; \
const Uint8 r1 = curr_row[8 * i + 6]; \
const Uint8 B = (b + b1) >> 1; \
const Uint8 G = (g + g1) >> 1; \
const Uint8 R = (r + r1) >> 1; \
#define READ_ONE_RGB_PIXEL \
const Uint8 b = curr_row[8 * i + 0]; \
const Uint8 g = curr_row[8 * i + 1]; \
const Uint8 r = curr_row[8 * i + 2]; \
/* Write YUV plane, packed */
if (dst_format == SDL_PIXELFORMAT_YUY2)
{
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
READ_TWO_RGB_PIXELS;
/* Y U Y1 V */
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_U(R, G, B);
*plane++ = MAKE_Y(r1, g1, b1);
*plane++ = MAKE_V(R, G, B);
}
if (width_remainder) {
READ_ONE_RGB_PIXEL;
/* Y U Y V */
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_U(r, g, b);
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_V(r, g, b);
}
curr_row += src_pitch;
}
}
else if (dst_format == SDL_PIXELFORMAT_UYVY)
{
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
READ_TWO_RGB_PIXELS;
/* U Y V Y1 */
*plane++ = MAKE_U(R, G, B);
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_V(R, G, B);
*plane++ = MAKE_Y(r1, g1, b1);
}
if (width_remainder) {
READ_ONE_RGB_PIXEL;
/* U Y V Y */
*plane++ = MAKE_U(r, g, b);
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_V(r, g, b);
*plane++ = MAKE_Y(r, g, b);
}
curr_row += src_pitch;
}
}
else if (dst_format == SDL_PIXELFORMAT_YVYU)
{
for (j = 0; j < height; j++) {
for (i = 0; i < width_half; i++) {
READ_TWO_RGB_PIXELS;
/* Y V Y1 U */
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_V(R, G, B);
*plane++ = MAKE_Y(r1, g1, b1);
*plane++ = MAKE_U(R, G, B);
}
if (width_remainder) {
READ_ONE_RGB_PIXEL;
/* Y V Y U */
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_V(r, g, b);
*plane++ = MAKE_Y(r, g, b);
*plane++ = MAKE_U(r, g, b);
}
curr_row += src_pitch;
}
}
#undef READ_TWO_RGB_PIXELS
#undef READ_ONE_RGB_PIXEL
}
break;
}
return 0;
}
/* vi: set ts=4 sw=4 expandtab: */