Use YUV colorspaces instead of a global YUV conversion mode

Fixes https://github.com/libsdl-org/SDL/issues/8669
main
Sam Lantinga 2024-02-03 07:05:32 -08:00
parent 9e76f23561
commit 50a805cdd1
22 changed files with 361 additions and 327 deletions

View File

@ -1382,6 +1382,9 @@ The following functions have been renamed:
* SDL_UpperBlitScaled() => SDL_BlitSurfaceScaled()
The following functions have been removed:
* SDL_GetYUVConversionMode()
* SDL_GetYUVConversionModeForResolution()
* SDL_SetYUVConversionMode() - use SDL_SetSurfaceColorspace() to set the surface colorspace and SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER with SDL_CreateTextureWithProperties() to set the texture colorspace. The default colorspace for YUV pixel formats is SDL_COLORSPACE_BT601_LIMITED.
* SDL_SoftStretchLinear() - use SDL_SoftStretch() with SDL_SCALEMODE_LINEAR
## SDL_system.h

View File

@ -555,6 +555,11 @@ typedef enum
#define SDL_COLORSPACETRANSFER(X) (SDL_TransferCharacteristics)(((X) >> 5) & 0x1F)
#define SDL_COLORSPACEMATRIX(X) (SDL_MatrixCoefficients)((X) & 0x1F)
#define SDL_ISCOLORSPACE_YUV_BT601(X) (SDL_COLORSPACEMATRIX(X) == SDL_MATRIX_COEFFICIENTS_BT601 || SDL_COLORSPACEMATRIX(X) == SDL_MATRIX_COEFFICIENTS_BT470BG)
#define SDL_ISCOLORSPACE_YUV_BT709(X) (SDL_COLORSPACEMATRIX(X) == SDL_MATRIX_COEFFICIENTS_BT709)
#define SDL_ISCOLORSPACE_LIMITED_RANGE(X) (SDL_COLORSPACERANGE(X) == SDL_COLOR_RANGE_LIMITED)
#define SDL_ISCOLORSPACE_FULL_RANGE(X) (SDL_COLORSPACERANGE(X) == SDL_COLOR_RANGE_LIMITED)
typedef enum
{
SDL_COLORSPACE_UNKNOWN,
@ -620,6 +625,10 @@ typedef enum
/* The default colorspace for RGB surfaces if no colorspace is specified */
SDL_COLORSPACE_RGB_DEFAULT = SDL_COLORSPACE_SRGB,
/* The default colorspace for YUV surfaces if no colorspace is specified */
SDL_COLORSPACE_YUV_DEFAULT = SDL_COLORSPACE_BT601_LIMITED,
} SDL_Colorspace;
/**

View File

@ -458,7 +458,7 @@ extern DECLSPEC SDL_Texture *SDLCALL SDL_CreateTextureFromSurface(SDL_Renderer *
* - `SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER`: an SDL_ColorSpace value
* describing the texture colorspace, defaults to SDL_COLORSPACE_SCRGB for
* floating point textures, SDL_COLORSPACE_HDR10 for 10-bit textures,
* SDL_COLORSPACE_SRGB for other RGB textures and SDL_COLORSPACE_BT709_FULL
* SDL_COLORSPACE_SRGB for other RGB textures and SDL_COLORSPACE_BT601_LIMITED
* for YUV textures.
* - `SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER`: one of the enumerated values in
* SDL_PixelFormatEnum, defaults to the best RGBA format for the renderer

View File

@ -138,17 +138,6 @@ typedef int (SDLCALL *SDL_blit) (struct SDL_Surface *src, const SDL_Rect *srcrec
struct SDL_Surface *dst, const SDL_Rect *dstrect);
/**
* The formula used for converting between YUV and RGB
*/
typedef enum
{
SDL_YUV_CONVERSION_JPEG, /**< Full range JPEG */
SDL_YUV_CONVERSION_BT601, /**< BT.601 (the default) */
SDL_YUV_CONVERSION_BT709, /**< BT.709 */
SDL_YUV_CONVERSION_AUTOMATIC /**< BT.601 for SD content, BT.709 for HD content */
} SDL_YUV_CONVERSION_MODE;
/**
* Allocate a new RGB surface with a specific pixel format.
*
@ -1031,36 +1020,6 @@ extern DECLSPEC int SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, con
*/
extern DECLSPEC int SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);
/**
* Set the YUV conversion mode
*
* \param mode YUV conversion mode
*
* \since This function is available since SDL 3.0.0.
*/
extern DECLSPEC void SDLCALL SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode);
/**
* Get the YUV conversion mode
*
* \returns YUV conversion mode
*
* \since This function is available since SDL 3.0.0.
*/
extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionMode(void);
/**
* Get the YUV conversion mode, returning the correct mode for the resolution
* when the current conversion mode is SDL_YUV_CONVERSION_AUTOMATIC
*
* \param width width
* \param height height
* \returns YUV conversion mode
*
* \since This function is available since SDL 3.0.0.
*/
extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionModeForResolution(int width, int height);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}

View File

@ -347,8 +347,6 @@ SDL3_0.0.0 {
SDL_GetWindowSizeInPixels;
SDL_GetWindowSurface;
SDL_GetWindowTitle;
SDL_GetYUVConversionMode;
SDL_GetYUVConversionModeForResolution;
SDL_CloseHaptic;
SDL_DestroyHapticEffect;
SDL_HapticEffectSupported;
@ -594,7 +592,6 @@ SDL3_0.0.0 {
SDL_SetWindowSize;
SDL_SetWindowTitle;
SDL_SetWindowsMessageHook;
SDL_SetYUVConversionMode;
SDL_ShowCursor;
SDL_ShowMessageBox;
SDL_ShowSimpleMessageBox;

View File

@ -371,8 +371,6 @@
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
#define SDL_GetWindowSurface SDL_GetWindowSurface_REAL
#define SDL_GetWindowTitle SDL_GetWindowTitle_REAL
#define SDL_GetYUVConversionMode SDL_GetYUVConversionMode_REAL
#define SDL_GetYUVConversionModeForResolution SDL_GetYUVConversionModeForResolution_REAL
#define SDL_CloseHaptic SDL_CloseHaptic_REAL
#define SDL_DestroyHapticEffect SDL_DestroyHapticEffect_REAL
#define SDL_HapticEffectSupported SDL_HapticEffectSupported_REAL
@ -617,7 +615,6 @@
#define SDL_SetWindowSize SDL_SetWindowSize_REAL
#define SDL_SetWindowTitle SDL_SetWindowTitle_REAL
#define SDL_SetWindowsMessageHook SDL_SetWindowsMessageHook_REAL
#define SDL_SetYUVConversionMode SDL_SetYUVConversionMode_REAL
#define SDL_ShowCursor SDL_ShowCursor_REAL
#define SDL_ShowMessageBox SDL_ShowMessageBox_REAL
#define SDL_ShowSimpleMessageBox SDL_ShowSimpleMessageBox_REAL

View File

@ -430,8 +430,6 @@ SDL_DYNAPI_PROC(int,SDL_GetWindowSize,(SDL_Window *a, int *b, int *c),(a,b,c),re
SDL_DYNAPI_PROC(int,SDL_GetWindowSizeInPixels,(SDL_Window *a, int *b, int *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_GetWindowSurface,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetWindowTitle,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(SDL_YUV_CONVERSION_MODE,SDL_GetYUVConversionMode,(void),(),return)
SDL_DYNAPI_PROC(SDL_YUV_CONVERSION_MODE,SDL_GetYUVConversionModeForResolution,(int a, int b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_CloseHaptic,(SDL_Haptic *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyHapticEffect,(SDL_Haptic *a, int b),(a,b),)
SDL_DYNAPI_PROC(SDL_bool,SDL_HapticEffectSupported,(SDL_Haptic *a, const SDL_HapticEffect *b),(a,b),return)
@ -659,7 +657,6 @@ SDL_DYNAPI_PROC(int,SDL_SetWindowPosition,(SDL_Window *a, int b, int c),(a,b,c),
SDL_DYNAPI_PROC(int,SDL_SetWindowResizable,(SDL_Window *a, SDL_bool b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowSize,(SDL_Window *a, int b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowTitle,(SDL_Window *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_SetYUVConversionMode,(SDL_YUV_CONVERSION_MODE a),(a),)
SDL_DYNAPI_PROC(int,SDL_ShowCursor,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)

View File

@ -944,17 +944,19 @@ static int SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, LPDIREC
}
#if SDL_HAVE_YUV
if (texturedata->yuv) {
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_JPEG:
*shader = data->shaders[SHADER_YUV_JPEG];
break;
case SDL_YUV_CONVERSION_BT601:
*shader = data->shaders[SHADER_YUV_BT601];
break;
case SDL_YUV_CONVERSION_BT709:
*shader = data->shaders[SHADER_YUV_BT709];
break;
default:
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
*shader = data->shaders[SHADER_YUV_BT601];
} else {
*shader = data->shaders[SHADER_YUV_JPEG];
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
*shader = data->shaders[SHADER_YUV_BT709];
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}

View File

@ -2151,17 +2151,19 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D11_Shader shader;
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_JPEG:
shader = SHADER_YUV_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
shader = SHADER_YUV_BT601;
break;
case SDL_YUV_CONVERSION_BT709:
shader = SHADER_YUV_BT709;
break;
default:
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = SHADER_YUV_BT601;
} else {
shader = SHADER_YUV_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = SHADER_YUV_BT709;
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
@ -2175,17 +2177,19 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D11_Shader shader;
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_JPEG:
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
break;
case SDL_YUV_CONVERSION_BT709:
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
break;
default:
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
} else {
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}

View File

@ -2589,17 +2589,19 @@ static int D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D12_Shader shader;
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_JPEG:
shader = SHADER_YUV_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
shader = SHADER_YUV_BT601;
break;
case SDL_YUV_CONVERSION_BT709:
shader = SHADER_YUV_BT709;
break;
default:
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = SHADER_YUV_BT601;
} else {
shader = SHADER_YUV_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = SHADER_YUV_BT709;
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
@ -2620,17 +2622,19 @@ static int D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D12_Shader shader;
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_JPEG:
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
break;
case SDL_YUV_CONVERSION_BT709:
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
break;
default:
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
} else {
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}

View File

@ -638,20 +638,20 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
#if SDL_HAVE_YUV
if (yuv || nv12) {
size_t offset = 0;
SDL_YUV_CONVERSION_MODE mode = SDL_GetYUVConversionModeForResolution(texture->w, texture->h);
switch (mode) {
case SDL_YUV_CONVERSION_JPEG:
offset = CONSTANTS_OFFSET_DECODE_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
offset = CONSTANTS_OFFSET_DECODE_BT601;
break;
case SDL_YUV_CONVERSION_BT709:
offset = CONSTANTS_OFFSET_DECODE_BT709;
break;
default:
offset = 0;
break;
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
offset = CONSTANTS_OFFSET_DECODE_BT601;
} else {
offset = CONSTANTS_OFFSET_DECODE_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
offset = CONSTANTS_OFFSET_DECODE_BT709;
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
texturedata.conversionBufferOffset = offset;
}
@ -1723,10 +1723,10 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
};
float decodetransformBT709[4 * 4] = {
0.0, -0.501960814, -0.501960814, 0.0, /* offset */
1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
-0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
1.1644, 0.0000, 1.7927, 0.0, /* Rcoeff */
1.1644, -0.2132, -0.5329, 0.0, /* Gcoeff */
1.1644, 2.1124, 0.0000, 0.0, /* Bcoeff */
};
if (!IsMetalAvailable()) {

View File

@ -662,45 +662,46 @@ static int GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr
#if SDL_HAVE_YUV
if (data->yuv || data->nv12) {
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_JPEG:
if (data->yuv) {
data->shader = SHADER_YUV_JPEG;
} else if (texture->format == SDL_PIXELFORMAT_NV12) {
data->shader = SHADER_NV12_JPEG;
} else {
data->shader = SHADER_NV21_JPEG;
}
break;
case SDL_YUV_CONVERSION_BT601:
if (data->yuv) {
data->shader = SHADER_YUV_BT601;
} else if (texture->format == SDL_PIXELFORMAT_NV12) {
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
data->shader = SHADER_NV12_RG_BT601;
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
if (data->yuv) {
data->shader = SHADER_YUV_BT601;
} else if (texture->format == SDL_PIXELFORMAT_NV12) {
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
data->shader = SHADER_NV12_RG_BT601;
} else {
data->shader = SHADER_NV12_RA_BT601;
}
} else {
data->shader = SHADER_NV12_RA_BT601;
data->shader = SHADER_NV21_BT601;
}
} else {
data->shader = SHADER_NV21_BT601;
}
break;
case SDL_YUV_CONVERSION_BT709:
if (data->yuv) {
data->shader = SHADER_YUV_BT709;
} else if (texture->format == SDL_PIXELFORMAT_NV12) {
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
data->shader = SHADER_NV12_RG_BT709;
if (data->yuv) {
data->shader = SHADER_YUV_JPEG;
} else if (texture->format == SDL_PIXELFORMAT_NV12) {
data->shader = SHADER_NV12_JPEG;
} else {
data->shader = SHADER_NV12_RA_BT709;
data->shader = SHADER_NV21_JPEG;
}
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
if (data->yuv) {
data->shader = SHADER_YUV_BT709;
} else if (texture->format == SDL_PIXELFORMAT_NV12) {
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
data->shader = SHADER_NV12_RG_BT709;
} else {
data->shader = SHADER_NV12_RA_BT709;
}
} else {
data->shader = SHADER_NV21_BT709;
}
} else {
data->shader = SHADER_NV21_BT709;
return SDL_SetError("Unsupported YUV conversion mode");
}
break;
default:
SDL_assert(!"unsupported YUV conversion mode");
break;
} else {
return SDL_SetError("Unsupported YUV conversion mode");
}
}
#endif /* SDL_HAVE_YUV */

View File

@ -588,7 +588,7 @@ static int GLES2_CacheShaders(GLES2_RenderData *data)
return 0;
}
static int GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, int w, int h)
static int GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, SDL_Colorspace colorspace)
{
GLuint vertex;
GLuint fragment;
@ -615,58 +615,67 @@ static int GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source,
break;
#if SDL_HAVE_YUV
case GLES2_IMAGESOURCE_TEXTURE_YUV:
switch (SDL_GetYUVConversionModeForResolution(w, h)) {
case SDL_YUV_CONVERSION_JPEG:
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601;
break;
case SDL_YUV_CONVERSION_BT709:
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709;
break;
default:
SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
if (SDL_ISCOLORSPACE_YUV_BT601(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601;
} else {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709;
} else {
SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
} else {
SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
break;
case GLES2_IMAGESOURCE_TEXTURE_NV12:
switch (SDL_GetYUVConversionModeForResolution(w, h)) {
case SDL_YUV_CONVERSION_JPEG:
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT601;
if (SDL_ISCOLORSPACE_YUV_BT601(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT601;
} else {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT601;
}
} else {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT601;
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_JPEG;
}
break;
case SDL_YUV_CONVERSION_BT709:
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT709;
} else if (SDL_ISCOLORSPACE_YUV_BT709(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT709;
} else {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT709;
}
} else {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT709;
SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
break;
default:
SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
} else {
SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
break;
case GLES2_IMAGESOURCE_TEXTURE_NV21:
switch (SDL_GetYUVConversionModeForResolution(w, h)) {
case SDL_YUV_CONVERSION_JPEG:
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601;
break;
case SDL_YUV_CONVERSION_BT709:
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709;
break;
default:
SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
if (SDL_ISCOLORSPACE_YUV_BT601(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601;
} else {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709;
} else {
SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
} else {
SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
break;
@ -961,7 +970,7 @@ static int SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, co
data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)&verts->tex_coord);
}
if (GLES2_SelectProgram(data, imgsrc, texture ? texture->w : 0, texture ? texture->h : 0) < 0) {
if (GLES2_SelectProgram(data, imgsrc, texture ? texture->colorspace : SDL_COLORSPACE_SRGB) < 0) {
return -1;
}

View File

@ -341,17 +341,20 @@ static void VITA_GXM_SetYUVProfile(SDL_Renderer *renderer, SDL_Texture *texture)
{
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->driverdata;
int ret = 0;
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_BT601:
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_STANDARD);
break;
case SDL_YUV_CONVERSION_BT709:
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_STANDARD);
break;
case SDL_YUV_CONVERSION_JPEG:
default:
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV profile: %d\n", SDL_GetYUVConversionModeForResolution(texture->w, texture->h));
break;
if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_STANDARD);
} else {
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_FULL_RANGE);
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_STANDARD);
} else {
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_FULL_RANGE);
}
} else {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV conversion mode\n");
}
if (ret < 0) {

View File

@ -695,7 +695,7 @@ void SDL_DestroyPixelFormat(SDL_PixelFormat *format)
SDL_Colorspace SDL_GetDefaultColorspaceForFormat(Uint32 format)
{
if (SDL_ISPIXELFORMAT_FOURCC(format)) {
return SDL_COLORSPACE_BT709_FULL;
return SDL_COLORSPACE_YUV_DEFAULT;
} else if (SDL_ISPIXELFORMAT_FLOAT(format)) {
return SDL_COLORSPACE_SCRGB;
} else if (SDL_ISPIXELFORMAT_10BIT(format)) {

View File

@ -1567,13 +1567,20 @@ int SDL_ConvertPixelsAndColorspace(int width, int height,
return SDL_InvalidParamError("dst_pitch");
}
if (src_colorspace == SDL_COLORSPACE_UNKNOWN) {
src_colorspace = SDL_GetDefaultColorspaceForFormat(src_format);
}
if (dst_colorspace == SDL_COLORSPACE_UNKNOWN) {
dst_colorspace = SDL_GetDefaultColorspaceForFormat(dst_format);
}
#if SDL_HAVE_YUV
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);
return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src_colorspace, src, src_pitch, dst_format, dst_colorspace, 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);
return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src_colorspace, src, src_pitch, dst_format, dst_colorspace, 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);
return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src_colorspace, src, src_pitch, dst_format, dst_colorspace, dst, dst_pitch);
}
#else
if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
@ -1599,17 +1606,13 @@ int SDL_ConvertPixelsAndColorspace(int width, int height,
&src_surface, &src_fmt, &src_blitmap)) {
return -1;
}
if (src_colorspace != SDL_COLORSPACE_UNKNOWN) {
SDL_SetNumberProperty(SDL_GetSurfaceProperties(&src_surface), SDL_PROP_SURFACE_COLORSPACE_NUMBER, src_colorspace);
}
SDL_SetNumberProperty(SDL_GetSurfaceProperties(&src_surface), SDL_PROP_SURFACE_COLORSPACE_NUMBER, src_colorspace);
if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
&dst_surface, &dst_fmt, &dst_blitmap)) {
return -1;
}
if (dst_colorspace != SDL_COLORSPACE_UNKNOWN) {
SDL_SetNumberProperty(SDL_GetSurfaceProperties(&dst_surface), SDL_PROP_SURFACE_COLORSPACE_NUMBER, dst_colorspace);
}
SDL_SetNumberProperty(SDL_GetSurfaceProperties(&dst_surface), SDL_PROP_SURFACE_COLORSPACE_NUMBER, dst_colorspace);
/* Set up the rect and go! */
rect.x = 0;

View File

@ -25,37 +25,11 @@
#include "yuv2rgb/yuv_rgb.h"
#define SDL_YUV_SD_THRESHOLD 576
static SDL_YUV_CONVERSION_MODE SDL_YUV_ConversionMode = SDL_YUV_CONVERSION_BT601;
#if SDL_HAVE_YUV
static SDL_bool IsPlanar2x2Format(Uint32 format);
#endif
void SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode)
{
SDL_YUV_ConversionMode = mode;
}
SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionMode(void)
{
return SDL_YUV_ConversionMode;
}
SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionModeForResolution(int width, int height)
{
SDL_YUV_CONVERSION_MODE mode = SDL_GetYUVConversionMode();
if (mode == SDL_YUV_CONVERSION_AUTOMATIC) {
if (height <= SDL_YUV_SD_THRESHOLD) {
mode = SDL_YUV_CONVERSION_BT601;
} else {
mode = SDL_YUV_CONVERSION_BT709;
}
}
return mode;
}
/*
* Calculate YUV size and pitch. Check for overflow.
* Output 'pitch' that can be used with SDL_ConvertPixels()
@ -185,20 +159,23 @@ int SDL_CalculateYUVSize(Uint32 format, int w, int h, size_t *size, size_t *pitc
#if SDL_HAVE_YUV
static int GetYUVConversionType(int width, int height, YCbCrType *yuv_type)
static int GetYUVConversionType(SDL_Colorspace colorspace, YCbCrType *yuv_type)
{
switch (SDL_GetYUVConversionModeForResolution(width, height)) {
case SDL_YUV_CONVERSION_JPEG:
*yuv_type = YCBCR_JPEG;
break;
case SDL_YUV_CONVERSION_BT601:
*yuv_type = YCBCR_601;
break;
case SDL_YUV_CONVERSION_BT709:
*yuv_type = YCBCR_709;
break;
default:
return SDL_SetError("Unexpected YUV conversion mode");
if (SDL_ISCOLORSPACE_YUV_BT601(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
*yuv_type = YCBCR_601;
} else {
*yuv_type = YCBCR_JPEG;
}
} else if (SDL_ISCOLORSPACE_YUV_BT709(colorspace)) {
if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
*yuv_type = YCBCR_709;
} else {
/* BT709 full range isn't supported yet */
return SDL_SetError("Unsupported YUV colorspace");
}
} else {
return SDL_SetError("Unsupported YUV colorspace");
}
return 0;
}
@ -578,8 +555,8 @@ static SDL_bool yuv_rgb_std(
}
int SDL_ConvertPixels_YUV_to_RGB(int width, int height,
Uint32 src_format, const void *src, int src_pitch,
Uint32 dst_format, void *dst, int dst_pitch)
Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch,
Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch)
{
const Uint8 *y = NULL;
const Uint8 *u = NULL;
@ -592,7 +569,7 @@ int SDL_ConvertPixels_YUV_to_RGB(int width, int height,
return -1;
}
if (GetYUVConversionType(width, height, &yuv_type) < 0) {
if (GetYUVConversionType(src_colorspace, &yuv_type) < 0) {
return -1;
}
@ -620,14 +597,14 @@ int SDL_ConvertPixels_YUV_to_RGB(int width, int height,
}
/* convert src/src_format to tmp/ARGB8888 */
ret = SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, tmp, tmp_pitch);
ret = SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src_colorspace, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, SDL_COLORSPACE_SRGB, tmp, tmp_pitch);
if (ret < 0) {
SDL_free(tmp);
return ret;
}
/* convert tmp/ARGB8888 to dst/RGB */
ret = SDL_ConvertPixels(width, height, SDL_PIXELFORMAT_ARGB8888, tmp, tmp_pitch, dst_format, dst, dst_pitch);
ret = SDL_ConvertPixelsAndColorspace(width, height, SDL_PIXELFORMAT_ARGB8888, SDL_COLORSPACE_SRGB, tmp, tmp_pitch, dst_format, dst_colorspace, dst, dst_pitch);
SDL_free(tmp);
return ret;
}
@ -643,7 +620,7 @@ struct RGB2YUVFactors
float v[3]; /* Rfactor, Gfactor, Bfactor */
};
static int SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *src, int src_pitch, Uint32 dst_format, 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, int dst_pitch, YCbCrType yuv_type)
{
const int src_pitch_x_2 = src_pitch * 2;
const int height_half = height / 2;
@ -652,7 +629,7 @@ static int SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *
const int width_remainder = (width & 0x1);
int i, j;
static struct RGB2YUVFactors RGB2YUVFactorTables[SDL_YUV_CONVERSION_BT709 + 1] = {
static struct RGB2YUVFactors RGB2YUVFactorTables[] = {
/* ITU-T T.871 (JPEG) */
{
0,
@ -675,7 +652,7 @@ static int SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *
{ 0.4392f, -0.3989f, -0.0403f },
},
};
const struct RGB2YUVFactors *cvt = &RGB2YUVFactorTables[SDL_GetYUVConversionModeForResolution(width, height)];
const struct RGB2YUVFactors *cvt = &RGB2YUVFactorTables[yuv_type];
#define MAKE_Y(r, g, b) (Uint8)((int)(cvt->y[0] * (r) + cvt->y[1] * (g) + cvt->y[2] * (b) + 0.5f) + cvt->y_offset)
#define MAKE_U(r, g, b) (Uint8)((int)(cvt->u[0] * (r) + cvt->u[1] * (g) + cvt->u[2] * (b) + 0.5f) + 128)
@ -958,9 +935,15 @@ static int SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *
}
int SDL_ConvertPixels_RGB_to_YUV(int width, int height,
Uint32 src_format, const void *src, int src_pitch,
Uint32 dst_format, void *dst, int dst_pitch)
Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch,
Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch)
{
YCbCrType yuv_type = YCBCR_601;
if (GetYUVConversionType(dst_colorspace, &yuv_type) < 0) {
return -1;
}
#if 0 /* Doesn't handle odd widths */
/* RGB24 to FOURCC */
if (src_format == SDL_PIXELFORMAT_RGB24) {
@ -969,16 +952,11 @@ int SDL_ConvertPixels_RGB_to_YUV(int width, int height,
Uint8 *v;
Uint32 y_stride;
Uint32 uv_stride;
YCbCrType yuv_type;
if (GetYUVPlanes(width, height, dst_format, dst, dst_pitch, (const Uint8 **)&y, (const Uint8 **)&u, (const Uint8 **)&v, &y_stride, &uv_stride) < 0) {
return -1;
}
if (GetYUVConversionType(width, height, &yuv_type) < 0) {
return -1;
}
rgb24_yuv420_std(width, height, src, src_pitch, y, u, v, y_stride, uv_stride, yuv_type);
return 0;
}
@ -986,7 +964,7 @@ int SDL_ConvertPixels_RGB_to_YUV(int width, int height,
/* ARGB8888 to FOURCC */
if (src_format == SDL_PIXELFORMAT_ARGB8888) {
return SDL_ConvertPixels_ARGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst, dst_pitch);
return SDL_ConvertPixels_ARGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst, dst_pitch, yuv_type);
}
/* not ARGB8888 to FOURCC : need an intermediate conversion */
@ -1008,7 +986,7 @@ int SDL_ConvertPixels_RGB_to_YUV(int width, int height,
}
/* convert tmp/ARGB8888 to dst/FOURCC */
ret = SDL_ConvertPixels_ARGB8888_to_YUV(width, height, tmp, tmp_pitch, dst_format, dst, dst_pitch);
ret = SDL_ConvertPixels_ARGB8888_to_YUV(width, height, tmp, tmp_pitch, dst_format, dst, dst_pitch, yuv_type);
SDL_free(tmp);
return ret;
}
@ -2345,10 +2323,14 @@ static int SDL_ConvertPixels_Packed4_to_Planar2x2(int width, int height,
#endif /* SDL_HAVE_YUV */
int SDL_ConvertPixels_YUV_to_YUV(int width, int height,
Uint32 src_format, const void *src, int src_pitch,
Uint32 dst_format, void *dst, int dst_pitch)
Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch,
Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch)
{
#if SDL_HAVE_YUV
if (src_colorspace != dst_colorspace) {
return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV: colorspace conversion not supported");
}
if (src_format == dst_format) {
if (src == dst) {
/* Nothing to do */

View File

@ -26,9 +26,9 @@
/* YUV conversion functions */
extern int SDL_ConvertPixels_YUV_to_RGB(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
extern int SDL_ConvertPixels_RGB_to_YUV(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
extern int SDL_ConvertPixels_YUV_to_YUV(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
extern int SDL_ConvertPixels_YUV_to_RGB(int width, int height, Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch, Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch);
extern int SDL_ConvertPixels_RGB_to_YUV(int width, int height, Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch, Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch);
extern int SDL_ConvertPixels_YUV_to_YUV(int width, int height, Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch, Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch);
extern int SDL_CalculateYUVSize(Uint32 format, int w, int h, size_t *size, size_t *pitch);

View File

@ -397,18 +397,19 @@ static AVCodecContext *OpenVideoStream(AVFormatContext *ic, int stream, const AV
return context;
}
static void SetYUVConversionMode(AVFrame *frame)
static SDL_Colorspace GetFrameColorspace(AVFrame *frame)
{
SDL_YUV_CONVERSION_MODE mode = SDL_YUV_CONVERSION_AUTOMATIC;
SDL_Colorspace colorspace = SDL_COLORSPACE_SRGB;
if (frame && (frame->format == AV_PIX_FMT_YUV420P || frame->format == AV_PIX_FMT_YUYV422 || frame->format == AV_PIX_FMT_UYVY422)) {
if (frame->color_range == AVCOL_RANGE_JPEG)
mode = SDL_YUV_CONVERSION_JPEG;
else if (frame->colorspace == AVCOL_SPC_BT709)
mode = SDL_YUV_CONVERSION_BT709;
else if (frame->colorspace == AVCOL_SPC_BT470BG || frame->colorspace == AVCOL_SPC_SMPTE170M)
mode = SDL_YUV_CONVERSION_BT601;
colorspace = SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR,
frame->color_range,
frame->color_primaries,
frame->color_trc,
frame->colorspace,
frame->chroma_location);
}
SDL_SetYUVConversionMode(mode); /* FIXME: no support for linear transfer */
return colorspace;
}
static void SDLCALL FreeSwsContextContainer(void *userdata, void *value)
@ -436,11 +437,18 @@ static SDL_bool GetTextureForMemoryFrame(AVFrame *frame, SDL_Texture **texture)
SDL_DestroyTexture(*texture);
}
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, GetFrameColorspace(frame));
if (frame_format == SDL_PIXELFORMAT_UNKNOWN) {
*texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, frame->width, frame->height);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, SDL_PIXELFORMAT_ARGB8888);
} else {
*texture = SDL_CreateTexture(renderer, frame_format, SDL_TEXTUREACCESS_STREAMING, frame->width, frame->height);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, frame_format);
}
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STREAMING);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, frame->width);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, frame->height);
*texture = SDL_CreateTextureWithProperties(renderer, props);
SDL_DestroyProperties(props);
if (!*texture) {
return SDL_FALSE;
}
@ -489,7 +497,6 @@ static SDL_bool GetTextureForMemoryFrame(AVFrame *frame, SDL_Texture **texture)
frame->data[1] + frame->linesize[1] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[1],
frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);
}
SetYUVConversionMode(frame);
break;
default:
if (frame->linesize[0] < 0) {
@ -527,11 +534,16 @@ static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
} else {
/* First time set up for NV12 textures */
SDL_SetHint("SDL_RENDER_OPENGL_NV12_RG_SHADER", "1");
SetYUVConversionMode(frame);
}
*texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STATIC, frame->width, frame->height);
props = SDL_CreateProperties();
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, GetFrameColorspace(frame));
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, SDL_PIXELFORMAT_NV12);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STATIC);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, frame->width);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, frame->height);
*texture = SDL_CreateTextureWithProperties(renderer, props);
SDL_DestroyProperties(props);
if (!*texture) {
return SDL_FALSE;
}
@ -617,12 +629,16 @@ static SDL_bool GetTextureForD3D11Frame(AVFrame *frame, SDL_Texture **texture)
if (!*texture || (UINT)texture_width != desc.Width || (UINT)texture_height != desc.Height) {
if (*texture) {
SDL_DestroyTexture(*texture);
} else {
/* First time set up for NV12 textures */
SetYUVConversionMode(frame);
}
*texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STATIC, desc.Width, desc.Height);
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, GetFrameColorspace(frame));
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, SDL_PIXELFORMAT_NV12);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STATIC);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, desc.Width);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, desc.Height);
*texture = SDL_CreateTextureWithProperties(renderer, props);
SDL_DestroyProperties(props);
if (!*texture) {
return SDL_FALSE;
}

View File

@ -65,7 +65,7 @@ static SDL_Surface *generate_test_pattern(int pattern_size)
return pattern;
}
static SDL_bool verify_yuv_data(Uint32 format, const Uint8 *yuv, int yuv_pitch, SDL_Surface *surface)
static SDL_bool verify_yuv_data(Uint32 format, SDL_Colorspace colorspace, const Uint8 *yuv, int yuv_pitch, SDL_Surface *surface)
{
const int tolerance = 20;
const int size = (surface->h * surface->pitch);
@ -78,7 +78,7 @@ static SDL_bool verify_yuv_data(Uint32 format, const Uint8 *yuv, int yuv_pitch,
return SDL_FALSE;
}
if (SDL_ConvertPixels(surface->w, surface->h, format, yuv, yuv_pitch, surface->format->format, rgb, surface->pitch) == 0) {
if (SDL_ConvertPixelsAndColorspace(surface->w, surface->h, format, colorspace, yuv, yuv_pitch, surface->format->format, SDL_COLORSPACE_SRGB, rgb, surface->pitch) == 0) {
int x, y;
result = SDL_TRUE;
for (y = 0; y < surface->h; ++y) {
@ -116,12 +116,19 @@ static int run_automated_tests(int pattern_size, int extra_pitch)
SDL_PIXELFORMAT_UYVY,
SDL_PIXELFORMAT_YVYU
};
const SDL_Colorspace colorspaces[] = {
SDL_COLORSPACE_BT601_FULL,
SDL_COLORSPACE_BT601_LIMITED,
SDL_COLORSPACE_BT709_LIMITED
};
int i, j;
SDL_Surface *pattern = generate_test_pattern(pattern_size);
const int yuv_len = MAX_YUV_SURFACE_SIZE(pattern->w, pattern->h, extra_pitch);
Uint8 *yuv1 = (Uint8 *)SDL_malloc(yuv_len);
Uint8 *yuv2 = (Uint8 *)SDL_malloc(yuv_len);
int yuv1_pitch, yuv2_pitch;
YUV_CONVERSION_MODE mode;
SDL_Colorspace colorspace;
int result = -1;
if (!pattern || !yuv1 || !yuv2) {
@ -129,14 +136,18 @@ static int run_automated_tests(int pattern_size, int extra_pitch)
goto done;
}
mode = GetYUVConversionModeForResolution(pattern->w, pattern->h);
SDL_assert(mode < SDL_arraysize(colorspaces));
colorspace = colorspaces[mode];
/* Verify conversion from YUV formats */
for (i = 0; i < SDL_arraysize(formats); ++i) {
if (!ConvertRGBtoYUV(formats[i], pattern->pixels, pattern->pitch, yuv1, pattern->w, pattern->h, SDL_GetYUVConversionModeForResolution(pattern->w, pattern->h), 0, 100)) {
if (!ConvertRGBtoYUV(formats[i], pattern->pixels, pattern->pitch, yuv1, pattern->w, pattern->h, mode, 0, 100)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s\n", SDL_GetPixelFormatName(formats[i]));
goto done;
}
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w);
if (!verify_yuv_data(formats[i], yuv1, yuv1_pitch, pattern)) {
if (!verify_yuv_data(formats[i], colorspace, yuv1, yuv1_pitch, pattern)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB\n", SDL_GetPixelFormatName(formats[i]));
goto done;
}
@ -145,11 +156,11 @@ static int run_automated_tests(int pattern_size, int extra_pitch)
/* Verify conversion to YUV formats */
for (i = 0; i < SDL_arraysize(formats); ++i) {
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
if (SDL_ConvertPixels(pattern->w, pattern->h, pattern->format->format, pattern->pixels, pattern->pitch, formats[i], yuv1, yuv1_pitch) < 0) {
if (SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format->format, SDL_COLORSPACE_SRGB, pattern->pixels, pattern->pitch, formats[i], colorspace, yuv1, yuv1_pitch) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
goto done;
}
if (!verify_yuv_data(formats[i], yuv1, yuv1_pitch, pattern)) {
if (!verify_yuv_data(formats[i], colorspace, yuv1, yuv1_pitch, pattern)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s\n", SDL_GetPixelFormatName(formats[i]));
goto done;
}
@ -160,15 +171,15 @@ static int run_automated_tests(int pattern_size, int extra_pitch)
for (j = 0; j < SDL_arraysize(formats); ++j) {
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch;
if (SDL_ConvertPixels(pattern->w, pattern->h, pattern->format->format, pattern->pixels, pattern->pitch, formats[i], yuv1, yuv1_pitch) < 0) {
if (SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format->format, SDL_COLORSPACE_SRGB, pattern->pixels, pattern->pitch, formats[i], colorspace, yuv1, yuv1_pitch) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
goto done;
}
if (SDL_ConvertPixels(pattern->w, pattern->h, formats[i], yuv1, yuv1_pitch, formats[j], yuv2, yuv2_pitch) < 0) {
if (SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, formats[i], colorspace, yuv1, yuv1_pitch, formats[j], colorspace, yuv2, yuv2_pitch) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError());
goto done;
}
if (!verify_yuv_data(formats[j], yuv2, yuv2_pitch, pattern)) {
if (!verify_yuv_data(formats[j], colorspace, yuv2, yuv2_pitch, pattern)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]));
goto done;
}
@ -185,15 +196,15 @@ static int run_automated_tests(int pattern_size, int extra_pitch)
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch;
if (SDL_ConvertPixels(pattern->w, pattern->h, pattern->format->format, pattern->pixels, pattern->pitch, formats[i], yuv1, yuv1_pitch) < 0) {
if (SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format->format, SDL_COLORSPACE_SRGB, pattern->pixels, pattern->pitch, formats[i], colorspace, yuv1, yuv1_pitch) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
goto done;
}
if (SDL_ConvertPixels(pattern->w, pattern->h, formats[i], yuv1, yuv1_pitch, formats[j], yuv1, yuv2_pitch) < 0) {
if (SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, formats[i], colorspace, yuv1, yuv1_pitch, formats[j], colorspace, yuv1, yuv2_pitch) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError());
goto done;
}
if (!verify_yuv_data(formats[j], yuv1, yuv2_pitch, pattern)) {
if (!verify_yuv_data(formats[j], colorspace, yuv1, yuv2_pitch, pattern)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]));
goto done;
}
@ -277,16 +288,16 @@ int main(int argc, char **argv)
consumed = SDLTest_CommonArg(state, i);
if (!consumed) {
if (SDL_strcmp(argv[i], "--jpeg") == 0) {
SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_JPEG);
SetYUVConversionMode(YUV_CONVERSION_JPEG);
consumed = 1;
} else if (SDL_strcmp(argv[i], "--bt601") == 0) {
SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_BT601);
SetYUVConversionMode(YUV_CONVERSION_BT601);
consumed = 1;
} else if (SDL_strcmp(argv[i], "--bt709") == 0) {
SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_BT709);
SetYUVConversionMode(YUV_CONVERSION_BT709);
consumed = 1;
} else if (SDL_strcmp(argv[i], "--auto") == 0) {
SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_AUTOMATIC);
SetYUVConversionMode(YUV_CONVERSION_AUTOMATIC);
consumed = 1;
} else if (SDL_strcmp(argv[i], "--yv12") == 0) {
yuv_format = SDL_PIXELFORMAT_YV12;
@ -379,7 +390,7 @@ int main(int argc, char **argv)
raw_yuv = SDL_calloc(1, MAX_YUV_SURFACE_SIZE(original->w, original->h, 0));
ConvertRGBtoYUV(yuv_format, original->pixels, original->pitch, raw_yuv, original->w, original->h,
SDL_GetYUVConversionModeForResolution(original->w, original->h),
GetYUVConversionModeForResolution(original->w, original->h),
0, 100);
pitch = CalculateYUVPitch(yuv_format, original->w);
@ -422,14 +433,14 @@ int main(int argc, char **argv)
yuv_name += 16;
}
switch (SDL_GetYUVConversionModeForResolution(original->w, original->h)) {
case SDL_YUV_CONVERSION_JPEG:
switch (GetYUVConversionModeForResolution(original->w, original->h)) {
case YUV_CONVERSION_JPEG:
yuv_mode = "JPEG";
break;
case SDL_YUV_CONVERSION_BT601:
case YUV_CONVERSION_BT601:
yuv_mode = "BT.601";
break;
case SDL_YUV_CONVERSION_BT709:
case YUV_CONVERSION_BT709:
yuv_mode = "BT.709";
break;
default:

View File

@ -14,14 +14,41 @@
#include "testyuv_cvt.h"
#define YUV_SD_THRESHOLD 576
static YUV_CONVERSION_MODE YUV_ConversionMode = YUV_CONVERSION_BT601;
void SetYUVConversionMode(YUV_CONVERSION_MODE mode)
{
YUV_ConversionMode = mode;
}
YUV_CONVERSION_MODE GetYUVConversionMode(void)
{
return YUV_ConversionMode;
}
YUV_CONVERSION_MODE GetYUVConversionModeForResolution(int width, int height)
{
YUV_CONVERSION_MODE mode = GetYUVConversionMode();
if (mode == YUV_CONVERSION_AUTOMATIC) {
if (height <= YUV_SD_THRESHOLD) {
mode = YUV_CONVERSION_BT601;
} else {
mode = YUV_CONVERSION_BT709;
}
}
return mode;
}
static float clip3(float x, float y, float z)
{
return (z < x) ? x : ((z > y) ? y : z);
}
static void RGBtoYUV(const Uint8 *rgb, int *yuv, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
static void RGBtoYUV(const Uint8 *rgb, int *yuv, YUV_CONVERSION_MODE mode, int monochrome, int luminance)
{
if (mode == SDL_YUV_CONVERSION_JPEG) {
if (mode == YUV_CONVERSION_JPEG) {
/* Full range YUV */
yuv[0] = (int)(0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
yuv[1] = (int)((rgb[2] - yuv[0]) * 0.565 + 128);
@ -37,7 +64,7 @@ static void RGBtoYUV(const Uint8 *rgb, int *yuv, SDL_YUV_CONVERSION_MODE mode, i
*/
float S, Z, R, G, B, L, Kr, Kb, Y, U, V;
if (mode == SDL_YUV_CONVERSION_BT709) {
if (mode == YUV_CONVERSION_BT709) {
/* BT.709 */
Kr = 0.2126f;
Kb = 0.0722f;
@ -75,7 +102,7 @@ static void RGBtoYUV(const Uint8 *rgb, int *yuv, SDL_YUV_CONVERSION_MODE mode, i
}
}
static void ConvertRGBtoPlanar2x2(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
static void ConvertRGBtoPlanar2x2(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance)
{
int x, y;
int yuv[4][3];
@ -191,7 +218,7 @@ static void ConvertRGBtoPlanar2x2(Uint32 format, Uint8 *src, int pitch, Uint8 *o
}
}
static void ConvertRGBtoPacked4(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
static void ConvertRGBtoPacked4(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance)
{
int x, y;
int yuv[2][3];
@ -261,7 +288,7 @@ static void ConvertRGBtoPacked4(Uint32 format, Uint8 *src, int pitch, Uint8 *out
}
}
SDL_bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
SDL_bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance)
{
switch (format) {
case SDL_PIXELFORMAT_YV12:

View File

@ -12,5 +12,15 @@
/* These functions are designed for testing correctness, not for speed */
extern SDL_bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance);
typedef enum
{
YUV_CONVERSION_JPEG, /**< Full range JPEG */
YUV_CONVERSION_BT601, /**< BT.601 (the default) */
YUV_CONVERSION_BT709, /**< BT.709 */
YUV_CONVERSION_AUTOMATIC /**< BT.601 for SD content, BT.709 for HD content */
} YUV_CONVERSION_MODE;
extern void SetYUVConversionMode(YUV_CONVERSION_MODE mode);
extern YUV_CONVERSION_MODE GetYUVConversionModeForResolution(int width, int height);
extern SDL_bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance);
extern int CalculateYUVPitch(Uint32 format, int width);