Browse Source

Use YUV colorspaces instead of a global YUV conversion mode

Fixes https://github.com/libsdl-org/SDL/issues/8669
Sam Lantinga 1 year ago
parent
commit
50a805cdd1

+ 3 - 0
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

+ 9 - 0
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;
 
 /**

+ 1 - 1
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

+ 0 - 41
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
 }

+ 0 - 3
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;

+ 0 - 3
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

+ 0 - 3
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)

+ 13 - 11
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");
         }
 

+ 26 - 22
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");
         }
 

+ 26 - 22
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");
         }
 

+ 18 - 18
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()) {

+ 32 - 31
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;
+                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_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;
+        } 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_NV12_RA_BT709;
+                    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 */

+ 51 - 42
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;
     }
 

+ 14 - 11
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) {

+ 1 - 1
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)) {

+ 12 - 9
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;

+ 40 - 58
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 */

+ 3 - 3
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);

+ 36 - 20
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;
-    }
-    SDL_SetYUVConversionMode(mode); /* FIXME: no support for linear transfer */
+        colorspace = SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR,
+                                           frame->color_range,
+                                           frame->color_primaries,
+                                           frame->color_trc,
+                                           frame->colorspace,
+                                           frame->chroma_location);
+    }
+    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;
         }

+ 32 - 21
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:

+ 33 - 6
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:

+ 11 - 1
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);