diff --git a/docs/README-migration.md b/docs/README-migration.md index 5f135c38d..4d3768bfa 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -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 diff --git a/include/SDL3/SDL_pixels.h b/include/SDL3/SDL_pixels.h index f53cd7f64..112c6534f 100644 --- a/include/SDL3/SDL_pixels.h +++ b/include/SDL3/SDL_pixels.h @@ -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; /** diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index b1aba7adc..1764e02a6 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -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 diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h index f4c647395..8e064109a 100644 --- a/include/SDL3/SDL_surface.h +++ b/include/SDL3/SDL_surface.h @@ -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 } diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 631fe95d6..07f36e853 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -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; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 4f479e8c1..208eb1238 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -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 diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 2fac10f7f..62b4e6c4f 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -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) diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index 4ba113a93..c8d2e7b46 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/src/render/direct3d/SDL_render_d3d.c @@ -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"); } diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 3c61a192e..f1bbcea57 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -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"); } diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c index 0d6c40590..484d0e272 100644 --- a/src/render/direct3d12/SDL_render_d3d12.c +++ b/src/render/direct3d12/SDL_render_d3d12.c @@ -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"); } diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index 09f39fbf2..fb5453365 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -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()) { diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index e758e0de0..5749e496a 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -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 */ diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index a3ea1eee0..2ac819599 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -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; } diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c index 5bd09e4a1..c82219c42 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm.c +++ b/src/render/vitagxm/SDL_render_vita_gxm.c @@ -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) { diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c index 2b6ece7fa..c76805151 100644 --- a/src/video/SDL_pixels.c +++ b/src/video/SDL_pixels.c @@ -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)) { diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index 8b1f21fcd..d2f5059e6 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -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; diff --git a/src/video/SDL_yuv.c b/src/video/SDL_yuv.c index cd9fa8b92..91e2aa8b6 100644 --- a/src/video/SDL_yuv.c +++ b/src/video/SDL_yuv.c @@ -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 */ diff --git a/src/video/SDL_yuv_c.h b/src/video/SDL_yuv_c.h index 033a013b9..4c2cf5d0f 100644 --- a/src/video/SDL_yuv_c.h +++ b/src/video/SDL_yuv_c.h @@ -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); diff --git a/test/testffmpeg.c b/test/testffmpeg.c index 5495fd9f4..b0771ac4b 100644 --- a/test/testffmpeg.c +++ b/test/testffmpeg.c @@ -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; } diff --git a/test/testyuv.c b/test/testyuv.c index 960d23219..83b6369e7 100644 --- a/test/testyuv.c +++ b/test/testyuv.c @@ -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: diff --git a/test/testyuv_cvt.c b/test/testyuv_cvt.c index 80e873e27..230a0b375 100644 --- a/test/testyuv_cvt.c +++ b/test/testyuv_cvt.c @@ -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: diff --git a/test/testyuv_cvt.h b/test/testyuv_cvt.h index fa736be3c..62e6ab2ab 100644 --- a/test/testyuv_cvt.h +++ b/test/testyuv_cvt.h @@ -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);