SDL_yuv_sw.c
Go to the documentation of this file.
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 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 */
#include "SDL_assert.h"
#include "SDL_yuv_sw_c.h"
SDL_SW_YUVTexture *
SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
{
SDL_SW_YUVTexture *swdata;
switch (format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
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;
{
const int sz_plane = w * h;
const int sz_plane_chroma = ((w + 1) / 2) * ((h + 1) / 2);
const int sz_plane_packed = ((w + 1) / 2) * h;
int dst_size = 0;
switch(format)
{
case SDL_PIXELFORMAT_YV12: /**< Planar mode: Y + V + U (3 planes) */
case SDL_PIXELFORMAT_IYUV: /**< Planar mode: Y + U + V (3 planes) */
dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma;
break;
case SDL_PIXELFORMAT_YUY2: /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */
case SDL_PIXELFORMAT_UYVY: /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
case SDL_PIXELFORMAT_YVYU: /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
dst_size = 4 * sz_plane_packed;
break;
case SDL_PIXELFORMAT_NV12: /**< Planar mode: Y + U/V interleaved (2 planes) */
case SDL_PIXELFORMAT_NV21: /**< Planar mode: Y + V/U interleaved (2 planes) */
dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma;
break;
default:
SDL_assert(0 && "We should never get here (caught above)");
break;
}
swdata->pixels = (Uint8 *) SDL_malloc(dst_size);
if (!swdata->pixels) {
SDL_SW_DestroyYUVTexture(swdata);
SDL_OutOfMemory();
return NULL;
}
}
/* Find the pitch and offset values for the texture */
switch (format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
swdata->pitches[0] = w;
swdata->pitches[1] = (swdata->pitches[0] + 1) / 2;
swdata->pitches[2] = (swdata->pitches[0] + 1) / 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 + 1) / 2);
break;
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
swdata->pitches[0] = ((w + 1) / 2) * 4;
swdata->planes[0] = swdata->pixels;
break;
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
swdata->pitches[0] = w;
swdata->pitches[1] = 2 * ((swdata->pitches[0] + 1) / 2);
swdata->planes[0] = swdata->pixels;
swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
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) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 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 + 1) / 2) + rect->x/2;
length = (rect->w + 1) / 2;
for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
src += (pitch + 1)/2;
dst += (swdata->w + 1)/2;
}
/* Copy the next plane */
src = (Uint8 *) pixels + rect->h * pitch + ((rect->h + 1) / 2) * ((pitch + 1) / 2);
dst = swdata->pixels + swdata->h * swdata->w +
((swdata->h + 1)/2) * ((swdata->w+1) / 2);
dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
length = (rect->w + 1) / 2;
for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
src += (pitch + 1)/2;
dst += (swdata->w + 1)/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 = 4 * ((rect->w + 1) / 2);
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, src, length);
src += pitch;
dst += swdata->pitches[0];
}
}
break;
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
{
if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h) {
SDL_memcpy(swdata->pixels, pixels,
(swdata->h * swdata->w) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 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 += 2 * ((rect->y + 1)/2) * ((swdata->w + 1) / 2) + 2 * (rect->x/2);
length = 2 * ((rect->w + 1) / 2);
for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
src += 2 * ((pitch + 1)/2);
dst += 2 * ((swdata->w + 1)/2);
}
}
}
}
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 + 1) / 2) * ((swdata->w + 1) / 2);
}
dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
length = (rect->w + 1) / 2;
for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
src += Upitch;
dst += (swdata->w + 1)/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 + 1) / 2) * ((swdata->w + 1) / 2);
}
dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
length = (rect->w + 1) / 2;
for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
src += Vpitch;
dst += (swdata->w + 1)/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:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
if (rect
&& (rect->x != 0 || rect->y != 0 || rect->w != swdata->w
|| rect->h != swdata->h)) {
return SDL_SetError
("YV12, IYUV, NV12, NV21 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)
{
int stretch;
/* Make sure we're set up to display in the desired format */
if (target_format != swdata->target_format && swdata->display) {
SDL_FreeSurface(swdata->display);
swdata->display = NULL;
}
stretch = 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)) {
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;
}
if (SDL_ConvertPixels(swdata->w, swdata->h, swdata->format,
swdata->planes[0], swdata->pitches[0],
target_format, pixels, pitch) < 0) {
return -1;
}
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_FreeSurface(swdata->stretch);
SDL_FreeSurface(swdata->display);
SDL_free(swdata);
}
}
/* vi: set ts=4 sw=4 expandtab: */
SDL_SW_UnlockYUVTexture
void SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture *swdata)
Definition: SDL_yuv_sw.c:329
SDL_SW_CreateYUVTexture
SDL_SW_YUVTexture * SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
Definition: SDL_yuv_sw.c:31
dst
GLenum GLenum dst
Definition: SDL_opengl_glext.h:1737
SDL_Surface::h
int h
Definition: SDL_surface.h:73
SDL_SoftStretch
#define SDL_SoftStretch
Definition: SDL_dynapi_overrides.h:470
SDL_SW_YUVTexture::target_format
Uint32 target_format
Definition: SDL_yuv_sw_c.h:30
rect
SDL_Rect rect
Definition: testrelative.c:27
SDL_SW_YUVTexture::pixels
Uint8 * pixels
Definition: SDL_yuv_sw_c.h:32
h
GLfloat GLfloat GLfloat GLfloat h
Definition: SDL_opengl_glext.h:1946
SDL_SW_LockYUVTexture
int SDL_SW_LockYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, void **pixels, int *pitch)
Definition: SDL_yuv_sw.c:302
SDL_PIXELFORMAT_NV21
Definition: SDL_pixels.h:289
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:181
SDL_Surface::w
int w
Definition: SDL_surface.h:73
src
GLenum src
Definition: SDL_opengl_glext.h:1737
SDL_CreateRGBSurfaceFrom
#define SDL_CreateRGBSurfaceFrom
Definition: SDL_dynapi_overrides.h:445
SDL_SW_YUVTexture
Definition: SDL_yuv_sw_c.h:27
SDL_PIXELFORMAT_YVYU
Definition: SDL_pixels.h:285
format
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
SDL_SW_UpdateYUVTexture
int SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, const void *pixels, int pitch)
Definition: SDL_yuv_sw.c:139
SDL_SW_YUVTexture::w
int w
Definition: SDL_yuv_sw_c.h:31
SDL_PIXELFORMAT_NV12
Definition: SDL_pixels.h:287
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
SDL_Surface::pixels
void * pixels
Definition: SDL_surface.h:75
SDL_FreeSurface
#define SDL_FreeSurface
Definition: SDL_dynapi_overrides.h:446
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:157
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_PIXELFORMAT_UNKNOWN
Definition: SDL_pixels.h:173
SDL_SW_YUVTexture::h
int h
Definition: SDL_yuv_sw_c.h:31
w
GLubyte GLubyte GLubyte GLubyte w
Definition: SDL_opengl_glext.h:731
SDL_PixelFormatEnumToMasks
#define SDL_PixelFormatEnumToMasks
Definition: SDL_dynapi_overrides.h:278
SDL_SW_DestroyYUVTexture
void SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture *swdata)
Definition: SDL_yuv_sw.c:404
SDL_Rect::x
int x
Definition: SDL_rect.h:66
pixels
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: SDL_opengl.h:1572
SDL_SW_YUVTexture::stretch
SDL_Surface * stretch
Definition: SDL_yuv_sw_c.h:39
SDL_Rect::w
int w
Definition: SDL_rect.h:67
SDL_SW_YUVTexture::planes
Uint8 * planes[3]
Definition: SDL_yuv_sw_c.h:36
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
NULL
#define NULL
Definition: begin_code.h:164
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_SW_QueryYUVTexturePixels
int SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture *swdata, void **pixels, int *pitch)
Definition: SDL_yuv_sw.c:130
SDL_SW_YUVTexture::pitches
Uint16 pitches[3]
Definition: SDL_yuv_sw_c.h:35
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_CreateRGBSurface
#define SDL_CreateRGBSurface
Definition: SDL_dynapi_overrides.h:444
SDL_yuv_sw_c.h
SDL_PIXELFORMAT_YV12
Definition: SDL_pixels.h:277
SDL_SW_UpdateYUVTexturePlanar
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)
Definition: SDL_yuv_sw.c:247
SDL_Rect::h
int h
Definition: SDL_rect.h:67
SDL_PIXELFORMAT_IYUV
Definition: SDL_pixels.h:279
SDL_SW_YUVTexture::format
Uint32 format
Definition: SDL_yuv_sw_c.h:29
SDL_SW_CopyYUVToRGB
int SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture *swdata, const SDL_Rect *srcrect, Uint32 target_format, int w, int h, void *pixels, int pitch)
Definition: SDL_yuv_sw.c:334
SDL_Surface::pitch
int pitch
Definition: SDL_surface.h:74
SDL_PIXELFORMAT_UYVY
Definition: SDL_pixels.h:283
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_ConvertPixels
#define SDL_ConvertPixels
Definition: SDL_dynapi_overrides.h:465
SDL_PIXELFORMAT_YUY2
Definition: SDL_pixels.h:281
SDL_SW_YUVTexture::display
SDL_Surface * display
Definition: SDL_yuv_sw_c.h:40
length
GLuint GLsizei GLsizei * length
Definition: SDL_opengl_glext.h:669
row
GLenum GLenum void * row
Definition: SDL_opengl_glext.h:3138
SDL_Rect::y
int y
Definition: SDL_rect.h:66
SDL_Rect
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
SDL_assert.h