diff options
author | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
commit | 6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch) | |
tree | 34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/test/testyuv_cvt.c | |
parent | 8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff) |
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testyuv_cvt.c')
-rw-r--r-- | src/contrib/SDL-3.2.20/test/testyuv_cvt.c | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testyuv_cvt.c b/src/contrib/SDL-3.2.20/test/testyuv_cvt.c new file mode 100644 index 0000000..ef44932 --- /dev/null +++ b/src/contrib/SDL-3.2.20/test/testyuv_cvt.c | |||
@@ -0,0 +1,556 @@ | |||
1 | /* | ||
2 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> | ||
3 | |||
4 | This software is provided 'as-is', without any express or implied | ||
5 | warranty. In no event will the authors be held liable for any damages | ||
6 | arising from the use of this software. | ||
7 | |||
8 | Permission is granted to anyone to use this software for any purpose, | ||
9 | including commercial applications, and to alter it and redistribute it | ||
10 | freely. | ||
11 | */ | ||
12 | |||
13 | #include <SDL3/SDL.h> | ||
14 | |||
15 | #include "testyuv_cvt.h" | ||
16 | |||
17 | #define YUV_SD_THRESHOLD 576 | ||
18 | |||
19 | static YUV_CONVERSION_MODE YUV_ConversionMode = YUV_CONVERSION_BT601; | ||
20 | |||
21 | void SetYUVConversionMode(YUV_CONVERSION_MODE mode) | ||
22 | { | ||
23 | YUV_ConversionMode = mode; | ||
24 | } | ||
25 | |||
26 | YUV_CONVERSION_MODE GetYUVConversionMode(void) | ||
27 | { | ||
28 | return YUV_ConversionMode; | ||
29 | } | ||
30 | |||
31 | YUV_CONVERSION_MODE GetYUVConversionModeForResolution(int width, int height) | ||
32 | { | ||
33 | YUV_CONVERSION_MODE mode = GetYUVConversionMode(); | ||
34 | if (mode == YUV_CONVERSION_AUTOMATIC) { | ||
35 | if (height <= YUV_SD_THRESHOLD) { | ||
36 | mode = YUV_CONVERSION_BT601; | ||
37 | } else { | ||
38 | mode = YUV_CONVERSION_BT709; | ||
39 | } | ||
40 | } | ||
41 | return mode; | ||
42 | } | ||
43 | |||
44 | SDL_Colorspace GetColorspaceForYUVConversionMode(YUV_CONVERSION_MODE mode) | ||
45 | { | ||
46 | SDL_Colorspace colorspace; | ||
47 | |||
48 | switch (mode) { | ||
49 | case YUV_CONVERSION_JPEG: | ||
50 | colorspace = SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, | ||
51 | SDL_COLOR_RANGE_FULL, | ||
52 | SDL_COLOR_PRIMARIES_BT709, | ||
53 | SDL_TRANSFER_CHARACTERISTICS_BT601, | ||
54 | SDL_MATRIX_COEFFICIENTS_BT601, | ||
55 | SDL_CHROMA_LOCATION_CENTER); | ||
56 | break; | ||
57 | case YUV_CONVERSION_BT601: | ||
58 | colorspace = SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, | ||
59 | SDL_COLOR_RANGE_LIMITED, | ||
60 | SDL_COLOR_PRIMARIES_BT709, | ||
61 | SDL_TRANSFER_CHARACTERISTICS_BT601, | ||
62 | SDL_MATRIX_COEFFICIENTS_BT601, | ||
63 | SDL_CHROMA_LOCATION_CENTER); | ||
64 | break; | ||
65 | case YUV_CONVERSION_BT709: | ||
66 | colorspace = SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, | ||
67 | SDL_COLOR_RANGE_LIMITED, | ||
68 | SDL_COLOR_PRIMARIES_BT709, | ||
69 | SDL_TRANSFER_CHARACTERISTICS_BT709, | ||
70 | SDL_MATRIX_COEFFICIENTS_BT709, | ||
71 | SDL_CHROMA_LOCATION_CENTER); | ||
72 | break; | ||
73 | case YUV_CONVERSION_BT2020: | ||
74 | colorspace = SDL_COLORSPACE_BT2020_FULL; | ||
75 | break; | ||
76 | default: | ||
77 | colorspace = SDL_COLORSPACE_UNKNOWN; | ||
78 | break; | ||
79 | } | ||
80 | return colorspace; | ||
81 | } | ||
82 | |||
83 | static float clip3(float x, float y, float z) | ||
84 | { | ||
85 | return (z < x) ? x : ((z > y) ? y : z); | ||
86 | } | ||
87 | |||
88 | static float sRGBtoNits(float v) | ||
89 | { | ||
90 | /* Normalize from 0..255 */ | ||
91 | v /= 255.0f; | ||
92 | |||
93 | /* Convert from sRGB */ | ||
94 | v = v <= 0.04045f ? (v / 12.92f) : SDL_powf(((v + 0.055f) / 1.055f), 2.4f); | ||
95 | |||
96 | /* Convert to nits, using a default SDR whitepoint of 203 */ | ||
97 | v *= 203.0f; | ||
98 | |||
99 | return v; | ||
100 | } | ||
101 | |||
102 | static float PQfromNits(float v) | ||
103 | { | ||
104 | const float c1 = 0.8359375f; | ||
105 | const float c2 = 18.8515625f; | ||
106 | const float c3 = 18.6875f; | ||
107 | const float m1 = 0.1593017578125f; | ||
108 | const float m2 = 78.84375f; | ||
109 | |||
110 | float y = SDL_clamp(v / 10000.0f, 0.0f, 1.0f); | ||
111 | float num = c1 + c2 * SDL_powf(y, m1); | ||
112 | float den = 1.0f + c3 * SDL_powf(y, m1); | ||
113 | return SDL_powf(num / den, m2); | ||
114 | } | ||
115 | |||
116 | void ConvertRec709toRec2020(float *fR, float *fG, float *fB) | ||
117 | { | ||
118 | static const float mat709to2020[] = { | ||
119 | 0.627404f, 0.329283f, 0.043313f, | ||
120 | 0.069097f, 0.919541f, 0.011362f, | ||
121 | 0.016391f, 0.088013f, 0.895595f, | ||
122 | }; | ||
123 | const float *matrix = mat709to2020; | ||
124 | float v[3]; | ||
125 | |||
126 | v[0] = *fR; | ||
127 | v[1] = *fG; | ||
128 | v[2] = *fB; | ||
129 | |||
130 | *fR = matrix[0 * 3 + 0] * v[0] + matrix[0 * 3 + 1] * v[1] + matrix[0 * 3 + 2] * v[2]; | ||
131 | *fG = matrix[1 * 3 + 0] * v[0] + matrix[1 * 3 + 1] * v[1] + matrix[1 * 3 + 2] * v[2]; | ||
132 | *fB = matrix[2 * 3 + 0] * v[0] + matrix[2 * 3 + 1] * v[1] + matrix[2 * 3 + 2] * v[2]; | ||
133 | } | ||
134 | |||
135 | static void RGBtoYUV(const Uint8 *rgb, int rgb_bits, int *yuv, int yuv_bits, YUV_CONVERSION_MODE mode, int monochrome, int luminance) | ||
136 | { | ||
137 | /** | ||
138 | * This formula is from Microsoft's documentation: | ||
139 | * https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx | ||
140 | * L = Kr * R + Kb * B + (1 - Kr - Kb) * G | ||
141 | * Y = floor(2^(M-8) * (219*(L-Z)/S + 16) + 0.5); | ||
142 | * U = clip3(0, (2^M)-1, floor(2^(M-8) * (112*(B-L) / ((1-Kb)*S) + 128) + 0.5)); | ||
143 | * V = clip3(0, (2^M)-1, floor(2^(M-8) * (112*(R-L) / ((1-Kr)*S) + 128) + 0.5)); | ||
144 | */ | ||
145 | bool studio_RGB = false; | ||
146 | bool full_range_YUV = false; | ||
147 | float N, M, S, Z, R, G, B, L, Kr, Kb, Y, U, V; | ||
148 | |||
149 | N = (float)rgb_bits; | ||
150 | M = (float)yuv_bits; | ||
151 | switch (mode) { | ||
152 | case YUV_CONVERSION_JPEG: | ||
153 | case YUV_CONVERSION_BT601: | ||
154 | /* BT.601 */ | ||
155 | Kr = 0.299f; | ||
156 | Kb = 0.114f; | ||
157 | break; | ||
158 | case YUV_CONVERSION_BT709: | ||
159 | /* BT.709 */ | ||
160 | Kr = 0.2126f; | ||
161 | Kb = 0.0722f; | ||
162 | break; | ||
163 | case YUV_CONVERSION_BT2020: | ||
164 | /* BT.2020 */ | ||
165 | Kr = 0.2627f; | ||
166 | Kb = 0.0593f; | ||
167 | break; | ||
168 | default: | ||
169 | /* Invalid */ | ||
170 | Kr = 1.0f; | ||
171 | Kb = 1.0f; | ||
172 | break; | ||
173 | } | ||
174 | |||
175 | R = rgb[0]; | ||
176 | G = rgb[1]; | ||
177 | B = rgb[2]; | ||
178 | |||
179 | if (mode == YUV_CONVERSION_JPEG || mode == YUV_CONVERSION_BT2020) { | ||
180 | full_range_YUV = true; | ||
181 | } | ||
182 | |||
183 | if (mode == YUV_CONVERSION_BT2020) { | ||
184 | /* Input is sRGB, need to convert to BT.2020 PQ YUV */ | ||
185 | R = sRGBtoNits(R); | ||
186 | G = sRGBtoNits(G); | ||
187 | B = sRGBtoNits(B); | ||
188 | ConvertRec709toRec2020(&R, &G, &B); | ||
189 | R = PQfromNits(R); | ||
190 | G = PQfromNits(G); | ||
191 | B = PQfromNits(B); | ||
192 | S = 1.0f; | ||
193 | Z = 0.0f; | ||
194 | } else if (studio_RGB) { | ||
195 | S = 219.0f * SDL_powf(2.0f, N - 8); | ||
196 | Z = 16.0f * SDL_powf(2.0f, N - 8); | ||
197 | } else { | ||
198 | S = 255.0f; | ||
199 | Z = 0.0f; | ||
200 | } | ||
201 | L = Kr * R + Kb * B + (1 - Kr - Kb) * G; | ||
202 | if (monochrome) { | ||
203 | R = L; | ||
204 | B = L; | ||
205 | } | ||
206 | if (full_range_YUV) { | ||
207 | Y = SDL_floorf((SDL_powf(2.0f, M) - 1) * ((L - Z) / S) + 0.5f); | ||
208 | U = clip3(0, SDL_powf(2.0f, M) - 1, SDL_floorf((SDL_powf(2.0f, M) / 2 - 1) * ((B - L) / ((1.0f - Kb) * S)) + SDL_powf(2.0f, M) / 2 + 0.5f)); | ||
209 | V = clip3(0, SDL_powf(2.0f, M) - 1, SDL_floorf((SDL_powf(2.0f, M) / 2 - 1) * ((R - L) / ((1.0f - Kr) * S)) + SDL_powf(2.0f, M) / 2 + 0.5f)); | ||
210 | } else { | ||
211 | Y = SDL_floorf(SDL_powf(2.0f, (M - 8)) * (219.0f * (L - Z) / S + 16) + 0.5f); | ||
212 | U = clip3(0, SDL_powf(2.0f, M) - 1, SDL_floorf(SDL_powf(2.0f, (M - 8)) * (112.0f * (B - L) / ((1.0f - Kb) * S) + 128) + 0.5f)); | ||
213 | V = clip3(0, SDL_powf(2.0f, M) - 1, SDL_floorf(SDL_powf(2.0f, (M - 8)) * (112.0f * (R - L) / ((1.0f - Kr) * S) + 128) + 0.5f)); | ||
214 | } | ||
215 | |||
216 | yuv[0] = (int)Y; | ||
217 | yuv[1] = (int)U; | ||
218 | yuv[2] = (int)V; | ||
219 | |||
220 | if (luminance != 100) { | ||
221 | yuv[0] = (int)clip3(0, SDL_powf(2.0f, M) - 1, SDL_roundf(yuv[0] * (luminance / 100.0f))); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static void ConvertRGBtoPlanar2x2(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance) | ||
226 | { | ||
227 | int x, y; | ||
228 | int yuv[4][3]; | ||
229 | Uint8 *Y1, *Y2, *U, *V; | ||
230 | Uint8 *rgb1, *rgb2; | ||
231 | int rgb_row_advance = (pitch - w * 3) + pitch; | ||
232 | int UV_advance; | ||
233 | |||
234 | rgb1 = src; | ||
235 | rgb2 = src + pitch; | ||
236 | |||
237 | Y1 = out; | ||
238 | Y2 = Y1 + w; | ||
239 | switch (format) { | ||
240 | case SDL_PIXELFORMAT_YV12: | ||
241 | V = (Y1 + h * w); | ||
242 | U = V + ((h + 1) / 2) * ((w + 1) / 2); | ||
243 | UV_advance = 1; | ||
244 | break; | ||
245 | case SDL_PIXELFORMAT_IYUV: | ||
246 | U = (Y1 + h * w); | ||
247 | V = U + ((h + 1) / 2) * ((w + 1) / 2); | ||
248 | UV_advance = 1; | ||
249 | break; | ||
250 | case SDL_PIXELFORMAT_NV12: | ||
251 | U = (Y1 + h * w); | ||
252 | V = U + 1; | ||
253 | UV_advance = 2; | ||
254 | break; | ||
255 | case SDL_PIXELFORMAT_NV21: | ||
256 | V = (Y1 + h * w); | ||
257 | U = V + 1; | ||
258 | UV_advance = 2; | ||
259 | break; | ||
260 | default: | ||
261 | SDL_assert(!"Unsupported planar YUV format"); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | for (y = 0; y < (h - 1); y += 2) { | ||
266 | for (x = 0; x < (w - 1); x += 2) { | ||
267 | RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); | ||
268 | rgb1 += 3; | ||
269 | *Y1++ = (Uint8)yuv[0][0]; | ||
270 | |||
271 | RGBtoYUV(rgb1, 8, yuv[1], 8, mode, monochrome, luminance); | ||
272 | rgb1 += 3; | ||
273 | *Y1++ = (Uint8)yuv[1][0]; | ||
274 | |||
275 | RGBtoYUV(rgb2, 8, yuv[2], 8, mode, monochrome, luminance); | ||
276 | rgb2 += 3; | ||
277 | *Y2++ = (Uint8)yuv[2][0]; | ||
278 | |||
279 | RGBtoYUV(rgb2, 8, yuv[3], 8, mode, monochrome, luminance); | ||
280 | rgb2 += 3; | ||
281 | *Y2++ = (Uint8)yuv[3][0]; | ||
282 | |||
283 | *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1]) / 4.0f + 0.5f); | ||
284 | U += UV_advance; | ||
285 | |||
286 | *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2]) / 4.0f + 0.5f); | ||
287 | V += UV_advance; | ||
288 | } | ||
289 | /* Last column */ | ||
290 | if (x == (w - 1)) { | ||
291 | RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); | ||
292 | rgb1 += 3; | ||
293 | *Y1++ = (Uint8)yuv[0][0]; | ||
294 | |||
295 | RGBtoYUV(rgb2, 8, yuv[2], 8, mode, monochrome, luminance); | ||
296 | rgb2 += 3; | ||
297 | *Y2++ = (Uint8)yuv[2][0]; | ||
298 | |||
299 | *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[2][1]) / 2.0f + 0.5f); | ||
300 | U += UV_advance; | ||
301 | |||
302 | *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[2][2]) / 2.0f + 0.5f); | ||
303 | V += UV_advance; | ||
304 | } | ||
305 | Y1 += w; | ||
306 | Y2 += w; | ||
307 | rgb1 += rgb_row_advance; | ||
308 | rgb2 += rgb_row_advance; | ||
309 | } | ||
310 | /* Last row */ | ||
311 | if (y == (h - 1)) { | ||
312 | for (x = 0; x < (w - 1); x += 2) { | ||
313 | RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); | ||
314 | rgb1 += 3; | ||
315 | *Y1++ = (Uint8)yuv[0][0]; | ||
316 | |||
317 | RGBtoYUV(rgb1, 8, yuv[1], 8, mode, monochrome, luminance); | ||
318 | rgb1 += 3; | ||
319 | *Y1++ = (Uint8)yuv[1][0]; | ||
320 | |||
321 | *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1]) / 2.0f + 0.5f); | ||
322 | U += UV_advance; | ||
323 | |||
324 | *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2]) / 2.0f + 0.5f); | ||
325 | V += UV_advance; | ||
326 | } | ||
327 | /* Last column */ | ||
328 | if (x == (w - 1)) { | ||
329 | RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); | ||
330 | *Y1++ = (Uint8)yuv[0][0]; | ||
331 | |||
332 | *U = (Uint8)yuv[0][1]; | ||
333 | U += UV_advance; | ||
334 | |||
335 | *V = (Uint8)yuv[0][2]; | ||
336 | V += UV_advance; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
341 | static Uint16 Pack10to16(int v) | ||
342 | { | ||
343 | return (Uint16)(v << 6); | ||
344 | } | ||
345 | |||
346 | static void ConvertRGBtoPlanar2x2_P010(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance) | ||
347 | { | ||
348 | int x, y; | ||
349 | int yuv[4][3]; | ||
350 | Uint16 *Y1, *Y2, *U, *V; | ||
351 | Uint8 *rgb1, *rgb2; | ||
352 | int rgb_row_advance = (pitch - w * 3) + pitch; | ||
353 | int UV_advance; | ||
354 | |||
355 | rgb1 = src; | ||
356 | rgb2 = src + pitch; | ||
357 | |||
358 | Y1 = (Uint16 *)out; | ||
359 | Y2 = Y1 + w; | ||
360 | switch (format) { | ||
361 | case SDL_PIXELFORMAT_P010: | ||
362 | U = (Y1 + h * w); | ||
363 | V = U + 1; | ||
364 | UV_advance = 2; | ||
365 | break; | ||
366 | default: | ||
367 | SDL_assert(!"Unsupported planar YUV format"); | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | for (y = 0; y < (h - 1); y += 2) { | ||
372 | for (x = 0; x < (w - 1); x += 2) { | ||
373 | RGBtoYUV(rgb1, 8, yuv[0], 10, mode, monochrome, luminance); | ||
374 | rgb1 += 3; | ||
375 | *Y1++ = Pack10to16(yuv[0][0]); | ||
376 | |||
377 | RGBtoYUV(rgb1, 8, yuv[1], 10, mode, monochrome, luminance); | ||
378 | rgb1 += 3; | ||
379 | *Y1++ = Pack10to16(yuv[1][0]); | ||
380 | |||
381 | RGBtoYUV(rgb2, 8, yuv[2], 10, mode, monochrome, luminance); | ||
382 | rgb2 += 3; | ||
383 | *Y2++ = Pack10to16(yuv[2][0]); | ||
384 | |||
385 | RGBtoYUV(rgb2, 8, yuv[3], 10, mode, monochrome, luminance); | ||
386 | rgb2 += 3; | ||
387 | *Y2++ = Pack10to16(yuv[3][0]); | ||
388 | |||
389 | *U = Pack10to16((int)SDL_floorf((yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1]) / 4.0f + 0.5f)); | ||
390 | U += UV_advance; | ||
391 | |||
392 | *V = Pack10to16((int)SDL_floorf((yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2]) / 4.0f + 0.5f)); | ||
393 | V += UV_advance; | ||
394 | } | ||
395 | /* Last column */ | ||
396 | if (x == (w - 1)) { | ||
397 | RGBtoYUV(rgb1, 8, yuv[0], 10, mode, monochrome, luminance); | ||
398 | rgb1 += 3; | ||
399 | *Y1++ = Pack10to16(yuv[0][0]); | ||
400 | |||
401 | RGBtoYUV(rgb2, 8, yuv[2], 10, mode, monochrome, luminance); | ||
402 | rgb2 += 3; | ||
403 | *Y2++ = Pack10to16(yuv[2][0]); | ||
404 | |||
405 | *U = Pack10to16((int)SDL_floorf((yuv[0][1] + yuv[2][1]) / 2.0f + 0.5f)); | ||
406 | U += UV_advance; | ||
407 | |||
408 | *V = Pack10to16((int)SDL_floorf((yuv[0][2] + yuv[2][2]) / 2.0f + 0.5f)); | ||
409 | V += UV_advance; | ||
410 | } | ||
411 | Y1 += w; | ||
412 | Y2 += w; | ||
413 | rgb1 += rgb_row_advance; | ||
414 | rgb2 += rgb_row_advance; | ||
415 | } | ||
416 | /* Last row */ | ||
417 | if (y == (h - 1)) { | ||
418 | for (x = 0; x < (w - 1); x += 2) { | ||
419 | RGBtoYUV(rgb1, 8, yuv[0], 10, mode, monochrome, luminance); | ||
420 | rgb1 += 3; | ||
421 | *Y1++ = Pack10to16(yuv[0][0]); | ||
422 | |||
423 | RGBtoYUV(rgb1, 8, yuv[1], 10, mode, monochrome, luminance); | ||
424 | rgb1 += 3; | ||
425 | *Y1++ = Pack10to16(yuv[1][0]); | ||
426 | |||
427 | *U = Pack10to16((int)SDL_floorf((yuv[0][1] + yuv[1][1]) / 2.0f + 0.5f)); | ||
428 | U += UV_advance; | ||
429 | |||
430 | *V = Pack10to16((int)SDL_floorf((yuv[0][2] + yuv[1][2]) / 2.0f + 0.5f)); | ||
431 | V += UV_advance; | ||
432 | } | ||
433 | /* Last column */ | ||
434 | if (x == (w - 1)) { | ||
435 | RGBtoYUV(rgb1, 8, yuv[0], 10, mode, monochrome, luminance); | ||
436 | *Y1++ = Pack10to16(yuv[0][0]); | ||
437 | |||
438 | *U = Pack10to16(yuv[0][1]); | ||
439 | U += UV_advance; | ||
440 | |||
441 | *V = Pack10to16(yuv[0][2]); | ||
442 | V += UV_advance; | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
447 | static void ConvertRGBtoPacked4(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance) | ||
448 | { | ||
449 | int x, y; | ||
450 | int yuv[2][3]; | ||
451 | Uint8 *Y1, *Y2, *U, *V; | ||
452 | Uint8 *rgb; | ||
453 | int rgb_row_advance = (pitch - w * 3); | ||
454 | |||
455 | rgb = src; | ||
456 | |||
457 | switch (format) { | ||
458 | case SDL_PIXELFORMAT_YUY2: | ||
459 | Y1 = out; | ||
460 | U = out + 1; | ||
461 | Y2 = out + 2; | ||
462 | V = out + 3; | ||
463 | break; | ||
464 | case SDL_PIXELFORMAT_UYVY: | ||
465 | U = out; | ||
466 | Y1 = out + 1; | ||
467 | V = out + 2; | ||
468 | Y2 = out + 3; | ||
469 | break; | ||
470 | case SDL_PIXELFORMAT_YVYU: | ||
471 | Y1 = out; | ||
472 | V = out + 1; | ||
473 | Y2 = out + 2; | ||
474 | U = out + 3; | ||
475 | break; | ||
476 | default: | ||
477 | SDL_assert(!"Unsupported packed YUV format"); | ||
478 | return; | ||
479 | } | ||
480 | |||
481 | for (y = 0; y < h; ++y) { | ||
482 | for (x = 0; x < (w - 1); x += 2) { | ||
483 | RGBtoYUV(rgb, 8, yuv[0], 8, mode, monochrome, luminance); | ||
484 | rgb += 3; | ||
485 | *Y1 = (Uint8)yuv[0][0]; | ||
486 | Y1 += 4; | ||
487 | |||
488 | RGBtoYUV(rgb, 8, yuv[1], 8, mode, monochrome, luminance); | ||
489 | rgb += 3; | ||
490 | *Y2 = (Uint8)yuv[1][0]; | ||
491 | Y2 += 4; | ||
492 | |||
493 | *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1]) / 2.0f + 0.5f); | ||
494 | U += 4; | ||
495 | |||
496 | *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2]) / 2.0f + 0.5f); | ||
497 | V += 4; | ||
498 | } | ||
499 | /* Last column */ | ||
500 | if (x == (w - 1)) { | ||
501 | RGBtoYUV(rgb, 8, yuv[0], 8, mode, monochrome, luminance); | ||
502 | rgb += 3; | ||
503 | *Y2 = *Y1 = (Uint8)yuv[0][0]; | ||
504 | Y1 += 4; | ||
505 | Y2 += 4; | ||
506 | |||
507 | *U = (Uint8)yuv[0][1]; | ||
508 | U += 4; | ||
509 | |||
510 | *V = (Uint8)yuv[0][2]; | ||
511 | V += 4; | ||
512 | } | ||
513 | rgb += rgb_row_advance; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, YUV_CONVERSION_MODE mode, int monochrome, int luminance) | ||
518 | { | ||
519 | switch (format) { | ||
520 | case SDL_PIXELFORMAT_P010: | ||
521 | ConvertRGBtoPlanar2x2_P010(format, src, pitch, out, w, h, mode, monochrome, luminance); | ||
522 | return true; | ||
523 | case SDL_PIXELFORMAT_YV12: | ||
524 | case SDL_PIXELFORMAT_IYUV: | ||
525 | case SDL_PIXELFORMAT_NV12: | ||
526 | case SDL_PIXELFORMAT_NV21: | ||
527 | ConvertRGBtoPlanar2x2(format, src, pitch, out, w, h, mode, monochrome, luminance); | ||
528 | return true; | ||
529 | case SDL_PIXELFORMAT_YUY2: | ||
530 | case SDL_PIXELFORMAT_UYVY: | ||
531 | case SDL_PIXELFORMAT_YVYU: | ||
532 | ConvertRGBtoPacked4(format, src, pitch, out, w, h, mode, monochrome, luminance); | ||
533 | return true; | ||
534 | default: | ||
535 | return false; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | int CalculateYUVPitch(Uint32 format, int width) | ||
540 | { | ||
541 | switch (format) { | ||
542 | case SDL_PIXELFORMAT_P010: | ||
543 | return width * 2; | ||
544 | case SDL_PIXELFORMAT_YV12: | ||
545 | case SDL_PIXELFORMAT_IYUV: | ||
546 | case SDL_PIXELFORMAT_NV12: | ||
547 | case SDL_PIXELFORMAT_NV21: | ||
548 | return width; | ||
549 | case SDL_PIXELFORMAT_YUY2: | ||
550 | case SDL_PIXELFORMAT_UYVY: | ||
551 | case SDL_PIXELFORMAT_YVYU: | ||
552 | return 4 * ((width + 1) / 2); | ||
553 | default: | ||
554 | return 0; | ||
555 | } | ||
556 | } | ||