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:
parent
e7cc03e0bd
commit
145d2469ae
60 changed files with 8368 additions and 4310 deletions
|
@ -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: */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue