1 /* GStreamer
2 * Copyright (C) 2013 Wim Taymans <wim.taymans@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <string.h>
25 #include <stdio.h>
26
27 #include "video-orc.h"
28 #include "video-format.h"
29 #include <gst/video/video-enumtypes.h>
30
31 /**
32 * SECTION:gstvideochroma
33 * @title: GstVideoChromaResample
34 * @short_description: Functions and utility object for operating on chroma video planes
35 *
36 * The functions gst_video_chroma_from_string() and gst_video_chroma_to_string() convert
37 * between #GstVideoChromaSite and string descriptions.
38 *
39 * #GstVideoChromaResample is a utility object for resampling chroma planes
40 * and converting between different chroma sampling sitings.
41 *
42 */
43
44 #ifndef GST_DISABLE_GST_DEBUG
45 #define GST_CAT_DEFAULT ensure_debug_category()
46 static GstDebugCategory *
ensure_debug_category(void)47 ensure_debug_category (void)
48 {
49 static gsize cat_gonce = 0;
50
51 if (g_once_init_enter (&cat_gonce)) {
52 gsize cat_done;
53
54 cat_done = (gsize) _gst_debug_category_new ("video-chroma", 0,
55 "video-chroma object");
56
57 g_once_init_leave (&cat_gonce, cat_done);
58 }
59
60 return (GstDebugCategory *) cat_gonce;
61 }
62 #else
63 #define ensure_debug_category() /* NOOP */
64 #endif /* GST_DISABLE_GST_DEBUG */
65
66 typedef struct
67 {
68 const gchar *name;
69 GstVideoChromaSite site;
70 } ChromaSiteInfo;
71
72 static const ChromaSiteInfo chromasite[] = {
73 {"jpeg", GST_VIDEO_CHROMA_SITE_JPEG},
74 {"mpeg2", GST_VIDEO_CHROMA_SITE_MPEG2},
75 {"dv", GST_VIDEO_CHROMA_SITE_DV},
76 {"alt-line", GST_VIDEO_CHROMA_SITE_ALT_LINE},
77 {"cosited", GST_VIDEO_CHROMA_SITE_COSITED},
78 };
79
80 /**
81 * gst_video_chroma_from_string:
82 * @s: a chromasite string
83 *
84 * Convert @s to a #GstVideoChromaSite
85 *
86 * Deprecated: 1.20: Use gst_video_chroma_site_from_string() instead.
87 *
88 * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does
89 * not contain a valid chroma description.
90 */
91 GstVideoChromaSite
gst_video_chroma_from_string(const gchar * s)92 gst_video_chroma_from_string (const gchar * s)
93 {
94 return gst_video_chroma_site_from_string (s);
95 }
96
97 /**
98 * gst_video_chroma_site_from_string:
99 * @s: a chromasite string
100 *
101 * Convert @s to a #GstVideoChromaSite
102 *
103 * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does
104 * not contain a valid chroma-site description.
105 *
106 * Since: 1.20
107 */
108 GstVideoChromaSite
gst_video_chroma_site_from_string(const gchar * s)109 gst_video_chroma_site_from_string (const gchar * s)
110 {
111 gint i;
112 gchar **split;
113 gchar **iter;
114 GstVideoChromaSite ret = GST_VIDEO_CHROMA_SITE_UNKNOWN;
115 GFlagsClass *klass;
116
117 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
118 if (g_str_equal (chromasite[i].name, s))
119 return chromasite[i].site;
120 }
121
122 klass = (GFlagsClass *) g_type_class_ref (GST_TYPE_VIDEO_CHROMA_SITE);
123 split = g_strsplit (s, "+", 0);
124 for (iter = split; *iter; iter++) {
125 GFlagsValue *value;
126
127 value = g_flags_get_value_by_nick (klass, *iter);
128 if (!value) {
129 ret = GST_VIDEO_CHROMA_SITE_UNKNOWN;
130 goto out;
131 }
132
133 ret |= value->value;
134 }
135
136 out:
137 g_type_class_unref (klass);
138 g_strfreev (split);
139
140 /* Doesn't make sense */
141 if ((ret & GST_VIDEO_CHROMA_SITE_NONE) != 0 &&
142 ret != GST_VIDEO_CHROMA_SITE_NONE)
143 return GST_VIDEO_CHROMA_SITE_UNKNOWN;
144
145 return ret;
146 }
147
148 /**
149 * gst_video_chroma_to_string:
150 * @site: a #GstVideoChromaSite
151 *
152 * Converts @site to its string representation.
153 *
154 * Deprecated: 1.20: Use gst_video_chroma_site_to_string() instead.
155 *
156 * Returns: a string describing @site.
157 */
158 const gchar *
gst_video_chroma_to_string(GstVideoChromaSite site)159 gst_video_chroma_to_string (GstVideoChromaSite site)
160 {
161 gint i;
162 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
163 if (chromasite[i].site == site)
164 return chromasite[i].name;
165 }
166 return NULL;
167 }
168
169 /**
170 * gst_video_chroma_site_to_string:
171 * @site: a #GstVideoChromaSite
172 *
173 * Converts @site to its string representation.
174 *
175 * Returns: (transfer full) (nullable): a string representation of @site
176 * or %NULL if @site contains undefined value or
177 * is equal to %GST_VIDEO_CHROMA_SITE_UNKNOWN
178 *
179 * Since: 1.20
180 */
181 gchar *
gst_video_chroma_site_to_string(GstVideoChromaSite site)182 gst_video_chroma_site_to_string (GstVideoChromaSite site)
183 {
184 gint i;
185 GString *str;
186 GFlagsValue *value;
187 GFlagsClass *klass;
188
189 /* return null string for GST_VIDEO_CHROMA_SITE_UNKNOWN */
190 if (site == 0)
191 return NULL;
192
193 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
194 if (chromasite[i].site == site)
195 return g_strdup (chromasite[i].name);
196 }
197
198 /* Doesn't make sense */
199 if ((site & GST_VIDEO_CHROMA_SITE_NONE) != 0 &&
200 site != GST_VIDEO_CHROMA_SITE_NONE)
201 return NULL;
202
203 /* Construct new string */
204 klass = (GFlagsClass *) g_type_class_ref (GST_TYPE_VIDEO_CHROMA_SITE);
205 str = g_string_new (NULL);
206 while (site != GST_VIDEO_CHROMA_SITE_UNKNOWN &&
207 (value = g_flags_get_first_value (klass, site))) {
208 if (str->len > 0)
209 g_string_append (str, "+");
210
211 g_string_append (str, value->value_nick);
212 site &= ~value->value;
213 }
214 g_type_class_unref (klass);
215
216 /* This means given chroma-site has unknown value */
217 if (site != 0)
218 return g_string_free (str, TRUE);
219
220 return g_string_free (str, FALSE);
221 }
222
223 struct _GstVideoChromaResample
224 {
225 GstVideoChromaMethod method;
226 GstVideoChromaSite site;
227 GstVideoChromaFlags flags;
228 GstVideoFormat format;
229 gint h_factor, v_factor;
230 guint n_lines;
231 gint offset;
232 void (*h_resample) (GstVideoChromaResample * resample, gpointer pixels,
233 gint width);
234 void (*v_resample) (GstVideoChromaResample * resample, gpointer lines[],
235 gint width);
236 };
237
238 #define PR(i) (p[2 + 4 * (i)])
239 #define PB(i) (p[3 + 4 * (i)])
240
241 #define PR0(i) (l0[2 + 4 * (i)])
242 #define PR1(i) (l1[2 + 4 * (i)])
243 #define PR2(i) (l2[2 + 4 * (i)])
244 #define PR3(i) (l3[2 + 4 * (i)])
245 #define PB0(i) (l0[3 + 4 * (i)])
246 #define PB1(i) (l1[3 + 4 * (i)])
247 #define PB2(i) (l2[3 + 4 * (i)])
248 #define PB3(i) (l3[3 + 4 * (i)])
249
250 #define FILT_1_1(a,b) ((a) + (b) + 1) >> 1
251 #define FILT_1_3_3_1(a,b,c,d) ((a) + 3*((b)+(c)) + (d) + 4) >> 3
252
253 #define FILT_3_1(a,b) (3*(a) + (b) + 2) >> 2
254 #define FILT_1_3(a,b) ((a) + 3*(b) + 2) >> 2
255 #define FILT_1_2_1(a,b,c) ((a) + 2*(b) + (c) + 2) >> 2
256
257 #define FILT_7_1(a,b) (7*(a) + 1*(b) + 4) >> 3
258 #define FILT_1_7(a,b) (1*(a) + 7*(b) + 4) >> 3
259
260 #define FILT_5_3(a,b) (5*(a) + 3*(b) + 4) >> 3
261 #define FILT_3_5(a,b) (3*(a) + 5*(b) + 4) >> 3
262
263 #define FILT_10_3_2_1(a,b,c,d) (10*(a) + 3*(b) + 2*(c) + (d) + 8) >> 16
264 #define FILT_1_2_3_10(a,b,c,d) ((a) + 2*(b) + 3*(c) + 10*(d) + 8) >> 16
265 #define FILT_1_2_3_4_3_2_1(a,b,c,d,e,f,g) ((a) + 2*((b)+(f)) + 3*((c)+(e)) + 4*(d) + (g) + 8) >> 16
266
267 /* 2x horizontal upsampling without cositing
268 *
269 * +---------- a
270 * | +------ (3*a + b + 2) >> 2
271 * | | +---- ( a + 3*b + 2) >> 2
272 * v v v
273 * O-O-O-O-
274 * x x
275 * a b
276 */
277 #define MAKE_UPSAMPLE_H2(name,type) \
278 static void \
279 video_chroma_up_h2_##name (GstVideoChromaResample *resample, \
280 gpointer pixels, gint width) \
281 { \
282 type *p = pixels; \
283 gint i; \
284 type tr0, tr1; \
285 type tb0, tb1; \
286 \
287 tr1 = PR(0); \
288 tb1 = PB(0); \
289 for (i = 1; i < width - 1; i += 2) { \
290 tr0 = tr1, tr1 = PR(i+1); \
291 tb0 = tb1, tb1 = PB(i+1); \
292 \
293 PR(i) = FILT_3_1 (tr0, tr1); \
294 PB(i) = FILT_3_1 (tb0, tb1); \
295 PR(i+1) = FILT_1_3 (tr0, tr1); \
296 PB(i+1) = FILT_1_3 (tb0, tb1); \
297 } \
298 }
299
300 /* 2x vertical upsampling without cositing
301 *
302 * O--O--O- <---- a
303 * a x x x
304 * O--O--O- <---- (3*a + b + 2) >> 2
305 * O--O--O- <-----( a + 3*b + 2) >> 2
306 * b x x x
307 * O--O--O- <---- b
308 */
309 #define MAKE_UPSAMPLE_V2(name,type) \
310 static void \
311 video_chroma_up_v2_##name (GstVideoChromaResample *resample, \
312 gpointer lines[], gint width) \
313 { \
314 type *l0 = lines[0]; \
315 type *l1 = lines[1]; \
316 \
317 if (resample->h_resample) { \
318 resample->h_resample (resample, l0, width); \
319 if (l0 != l1) \
320 resample->h_resample (resample, l1, width); \
321 } \
322 if (l0 != l1) { \
323 type *d0 = l0; \
324 type *d1 = l1; \
325 video_orc_chroma_up_v2_##name (d0, d1, l0, l1, width); \
326 } \
327 }
328 /* 2x vertical upsampling interlaced without cositing
329 *
330 * even odd
331 *
332 * O--O--O--------------- <--- a
333 * a x x x
334 * --------------O--O--O- <--- c
335 * O--O--O--------------- <--- (5*a + 3*b + 4) >> 3
336 * c x x x
337 * --------------O--O--O- <--- (7*c + d + 4) >> 3
338 * O--O--O--------------- <--- ( a + 7*b + 4) >> 3
339 * b x x x
340 * --------------O--O--O- <--- (3*c + 5*d + 4) >> 3
341 * O--O--O---------------
342 * d x x x
343 * --------------O--O--O-
344 */
345 #define MAKE_UPSAMPLE_VI2(name,type) \
346 static void \
347 video_chroma_up_vi2_##name (GstVideoChromaResample *resample, \
348 gpointer lines[], gint width) \
349 { \
350 gint i; \
351 type *l0 = lines[0]; \
352 type *l1 = lines[1]; \
353 type *l2 = lines[2]; \
354 type *l3 = lines[3]; \
355 type tr0, tr1, tr2, tr3; \
356 type tb0, tb1, tb2, tb3; \
357 \
358 if (resample->h_resample) { \
359 if (l0 != l1) { \
360 resample->h_resample (resample, l0, width); \
361 resample->h_resample (resample, l1, width); \
362 } \
363 if (l2 != l3) { \
364 resample->h_resample (resample, l2, width); \
365 resample->h_resample (resample, l3, width); \
366 } \
367 } \
368 if (l0 != l1 && l2 != l3) { \
369 for (i = 0; i < width; i++) { \
370 tr0 = PR0(i), tr2 = PR2(i); \
371 tb0 = PB0(i), tb2 = PB2(i); \
372 tr1 = PR1(i), tr3 = PR3(i); \
373 tb1 = PB1(i), tb3 = PB3(i); \
374 \
375 PR0(i) = FILT_5_3 (tr0, tr2); \
376 PB0(i) = FILT_5_3 (tb0, tb2); \
377 PR1(i) = FILT_7_1 (tr1, tr3); \
378 PB1(i) = FILT_7_1 (tb1, tb3); \
379 PR2(i) = FILT_1_7 (tr0, tr2); \
380 PB2(i) = FILT_1_7 (tb0, tb2); \
381 PR3(i) = FILT_3_5 (tr1, tr3); \
382 PB3(i) = FILT_3_5 (tb1, tb3); \
383 } \
384 } \
385 }
386
387 /* 2x horizontal downsampling without cositing
388 *
389 * +------ (a + b+ 1) >> 1
390 * |
391 * v
392 * -O---O--
393 * x x x x
394 * a b c d
395 */
396 #define MAKE_DOWNSAMPLE_H2_ORC(name,type) \
397 static void \
398 video_chroma_down_h2_##name (GstVideoChromaResample *resample, \
399 gpointer pixels, gint width) \
400 { \
401 type *p = pixels; \
402 type *d = p; \
403 \
404 video_orc_chroma_down_h2_##name (d, p, width / 2); \
405 }
406
407 #define MAKE_DOWNSAMPLE_H2(name,type) \
408 static void \
409 video_chroma_down_h2_##name (GstVideoChromaResample *resample, \
410 gpointer pixels, gint width) \
411 { \
412 type *p = pixels; \
413 gint i; \
414 \
415 for (i = 0; i < width - 1; i += 2) { \
416 type tr0 = PR(i), tr1 = PR(i+1); \
417 type tb0 = PB(i), tb1 = PB(i+1); \
418 \
419 PR(i) = FILT_1_1 (tr0, tr1); \
420 PB(i) = FILT_1_1 (tb0, tb1); \
421 } \
422 }
423 /* 2x vertical downsampling without cositing
424 *
425 * a x--x--x-
426 * O O O <---- (a + b + 1) >> 1
427 * b x--x--x-
428 * c x--x--x-
429 * O O O
430 * d x--x--x-
431 */
432 #define MAKE_DOWNSAMPLE_V2(name,type) \
433 static void \
434 video_chroma_down_v2_##name (GstVideoChromaResample *resample, \
435 gpointer lines[], gint width) \
436 { \
437 type *l0 = lines[0]; \
438 type *l1 = lines[1]; \
439 \
440 if (l0 != l1) { \
441 type *d0 = l0; \
442 video_orc_chroma_down_v2_##name (d0, l0, l1, width); \
443 } \
444 \
445 if (resample->h_resample) \
446 resample->h_resample (resample, l0, width); \
447 }
448 /* 2x vertical downsampling interlaced without cositing
449 *
450 * even odd
451 *
452 * a x--x--x---------------
453 * O O O <---
454 * b --------------x--x--x-
455 * c x--x--x---------------
456 * O O O <---
457 * d --------------x--x--x-
458 */
459 #define MAKE_DOWNSAMPLE_VI2(name,type) \
460 static void \
461 video_chroma_down_vi2_##name (GstVideoChromaResample *resample, \
462 gpointer lines[], gint width) \
463 { \
464 /* FIXME */ \
465 if (resample->h_resample) \
466 resample->h_resample (resample, lines[0], width); \
467 }
468
469 MAKE_UPSAMPLE_H2 (u16, guint16);
470 MAKE_UPSAMPLE_H2 (u8, guint8);
471 MAKE_UPSAMPLE_V2 (u16, guint16);
472 MAKE_UPSAMPLE_V2 (u8, guint8);
473 MAKE_UPSAMPLE_VI2 (u16, guint16);
474 MAKE_UPSAMPLE_VI2 (u8, guint8);
475 MAKE_DOWNSAMPLE_H2 (u16, guint16);
476 MAKE_DOWNSAMPLE_H2_ORC (u8, guint8);
477 MAKE_DOWNSAMPLE_V2 (u16, guint16);
478 MAKE_DOWNSAMPLE_V2 (u8, guint8);
479 MAKE_DOWNSAMPLE_VI2 (u16, guint16);
480 MAKE_DOWNSAMPLE_VI2 (u8, guint8);
481
482 /* 4x horizontal upsampling without cositing
483 *
484 * +---------- (7*a + b + 4) >> 3
485 * | +-------- (5*a + 3*b + 4) >> 3
486 * a a | | +------ (3*a + 5*b + 4) >> 3
487 * | | | | | +---- ( a + 7*b + 4) >> 3
488 * v v v v v v
489 * O-O-O-O-O-O-O-O-
490 * x x
491 * a b
492 */
493 #define MAKE_UPSAMPLE_H4(name,type) \
494 static void \
495 video_chroma_up_h4_##name (GstVideoChromaResample *resample, \
496 gpointer pixels, gint width) \
497 { \
498 type *p = pixels; \
499 gint i; \
500 type tr0, tr1; \
501 type tb0, tb1; \
502 \
503 tr1 = PR(0); \
504 tb1 = PB(0); \
505 for (i = 2; i < width - 3; i += 4) { \
506 tr0 = tr1, tr1 = PR(i+2); \
507 tb0 = tb1, tb1 = PB(i+2); \
508 \
509 PR(i) = FILT_7_1 (tr0, tr1); \
510 PB(i) = FILT_7_1 (tb0, tb1); \
511 PR(i+1) = FILT_5_3 (tr0, tr1); \
512 PB(i+1) = FILT_5_3 (tb0, tb1); \
513 PR(i+2) = FILT_3_5 (tr0, tr1); \
514 PB(i+2) = FILT_3_5 (tb0, tb1); \
515 PR(i+3) = FILT_1_7 (tr0, tr1); \
516 PB(i+3) = FILT_1_7 (tb0, tb1); \
517 } \
518 }
519
520 /* 4x vertical upsampling without cositing
521 *
522 * O--O--O- <---- a
523 * O--O--O- <---- a
524 * a x x x
525 * O--O--O- <---- (7*a + b + 4) >> 3
526 * O--O--O- <---- (5*a + 3*b + 4) >> 3
527 * O--O--O- <---- (3*a + 5*b + 4) >> 3
528 * O--O--O- <-----( a + 7*b + 4) >> 3
529 * b x x x
530 * O--O--O-
531 * O--O--O-
532 */
533 #define MAKE_UPSAMPLE_V4(name,type) \
534 static void \
535 video_chroma_up_v4_##name (GstVideoChromaResample *resample, \
536 gpointer lines[], gint width) \
537 { \
538 gint i; \
539 type *l0 = lines[0]; \
540 type *l1 = lines[1]; \
541 type *l2 = lines[2]; \
542 type *l3 = lines[3]; \
543 type tr0, tr1; \
544 type tb0, tb1; \
545 \
546 if (resample->h_resample) { \
547 if (l0 != l1) { \
548 resample->h_resample (resample, l0, width); \
549 resample->h_resample (resample, l1, width); \
550 } \
551 if (l2 != l3) { \
552 resample->h_resample (resample, l2, width); \
553 resample->h_resample (resample, l3, width); \
554 } \
555 } \
556 if (l0 != l1 && l2 != l3) { \
557 for (i = 0; i < width; i++) { \
558 tr0 = PR0(i), tr1 = PR2(i); \
559 tb0 = PB0(i), tb1 = PB2(i); \
560 \
561 PR0(i) = FILT_7_1 (tr0, tr1); \
562 PB0(i) = FILT_7_1 (tb0, tb1); \
563 PR1(i) = FILT_5_3 (tr0, tr1); \
564 PB1(i) = FILT_5_3 (tb0, tb1); \
565 PR2(i) = FILT_3_5 (tr0, tr1); \
566 PB2(i) = FILT_3_5 (tb0, tb1); \
567 PR3(i) = FILT_1_7 (tr0, tr1); \
568 PB3(i) = FILT_1_7 (tb0, tb1); \
569 } \
570 } \
571 }
572 /* 4x vertical upsampling interlaced without cositing
573 *
574 */
575 #define MAKE_UPSAMPLE_VI4(name,type) \
576 static void \
577 video_chroma_up_vi4_##name (GstVideoChromaResample *resample, \
578 gpointer lines[], gint width) \
579 { \
580 /* FIXME */ \
581 if (resample->h_resample) { \
582 resample->h_resample (resample, lines[0], width); \
583 } \
584 }
585
586 /* 4x horizontal downsampling without cositing
587 *
588 * +------ (a + 3*b + 3*c + d + 4) >> 3
589 * |
590 * v
591 * ---O-------O---
592 * x x x x x x x x
593 * a b c d e f g h
594 */
595 #define MAKE_DOWNSAMPLE_H4(name,type) \
596 static void \
597 video_chroma_down_h4_##name (GstVideoChromaResample *resample, \
598 gpointer pixels, gint width) \
599 { \
600 type *p = pixels; \
601 gint i; \
602 \
603 for (i = 0; i < width - 4; i += 4) { \
604 type tr0 = PR(i), tr1 = PR(i+1), tr2 = PR(i+2), tr3 = PR(i+3); \
605 type tb0 = PB(i), tb1 = PB(i+1), tb2 = PB(i+2), tb3 = PB(i+3); \
606 \
607 PR(i) = FILT_1_3_3_1 (tr0, tr1, tr2, tr3); \
608 PB(i) = FILT_1_3_3_1 (tb0, tb1, tb2, tb3); \
609 } \
610 }
611
612 /* 4x vertical downsampling without cositing
613 *
614 * a x--x--x-
615 * b x--x--x-
616 * O O O <---- (a + 3*b + 3*c + d + 4) >> 4
617 * c x--x--x-
618 * d x--x--x-
619 * e x--x--x-
620 * f x--x--x-
621 * O O O
622 * g x--x--x-
623 * h x--x--x-
624 */
625 #define MAKE_DOWNSAMPLE_V4(name,type) \
626 static void \
627 video_chroma_down_v4_##name (GstVideoChromaResample *resample, \
628 gpointer lines[], gint width) \
629 { \
630 type *l0 = lines[0]; \
631 type *l1 = lines[1]; \
632 type *l2 = lines[2]; \
633 type *l3 = lines[3]; \
634 type *d = l0; \
635 \
636 video_orc_chroma_down_v4_##name(d, l0, l1, l2, l3, width); \
637 \
638 if (resample->h_resample) \
639 resample->h_resample (resample, l0, width); \
640 }
641 /* 4x vertical downsampling interlaced without cositing
642 *
643 */
644 #define MAKE_DOWNSAMPLE_VI4(name,type) \
645 static void \
646 video_chroma_down_vi4_##name (GstVideoChromaResample *resample, \
647 gpointer lines[], gint width) \
648 { \
649 /* FIXME */ \
650 if (resample->h_resample) { \
651 resample->h_resample (resample, lines[0], width); \
652 } \
653 }
654
655 MAKE_UPSAMPLE_H4 (u16, guint16);
656 MAKE_UPSAMPLE_H4 (u8, guint8);
657 MAKE_UPSAMPLE_V4 (u16, guint16);
658 MAKE_UPSAMPLE_V4 (u8, guint8);
659 MAKE_UPSAMPLE_VI4 (u16, guint16);
660 MAKE_UPSAMPLE_VI4 (u8, guint8);
661 MAKE_DOWNSAMPLE_H4 (u16, guint16);
662 MAKE_DOWNSAMPLE_H4 (u8, guint8);
663 MAKE_DOWNSAMPLE_V4 (u16, guint16);
664 MAKE_DOWNSAMPLE_V4 (u8, guint8);
665 MAKE_DOWNSAMPLE_VI4 (u16, guint16);
666 MAKE_DOWNSAMPLE_VI4 (u8, guint8);
667
668 /* 2x horizontal upsampling with cositing
669 *
670 * a +------ (a + b + 1) >> 1
671 * | |
672 * v v
673 * O-O-O-O
674 * x x
675 * a b
676 */
677 #define MAKE_UPSAMPLE_H2_CS_ORC(name,type) \
678 static void \
679 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \
680 gpointer pixels, gint width) \
681 { \
682 type *p = pixels; \
683 /* ORC version is slower */ \
684 video_orc_chroma_up_h2_cs_##name (p, p, p, width-1); \
685 }
686
687 #define MAKE_UPSAMPLE_H2_CS(name,type) \
688 static void \
689 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \
690 gpointer pixels, gint width) \
691 { \
692 type *p = pixels; \
693 gint i; \
694 \
695 for (i = 1; i < width - 1; i += 2) { \
696 PR(i) = FILT_1_1 (PR(i-1), PR(i+1)); \
697 PB(i) = FILT_1_1 (PB(i-1), PB(i+1)); \
698 } \
699 }
700 /* 2x vertical upsampling with cositing
701 *
702 * a x O--O--O- <---- a
703 * O--O--O- <---- (a + b + 1) >> 1
704 * b x O--O--O-
705 * O--O--O-
706 */
707 #define MAKE_UPSAMPLE_V2_CS(name,type) \
708 static void \
709 video_chroma_up_v2_cs_##name (GstVideoChromaResample *resample, \
710 gpointer lines[], gint width) \
711 { \
712 /* FIXME */ \
713 if (resample->h_resample) { \
714 resample->h_resample (resample, lines[0], width); \
715 } \
716 }
717 /* 2x vertical upsampling interlaced with cositing
718 *
719 */
720 #define MAKE_UPSAMPLE_VI2_CS(name,type) \
721 static void \
722 video_chroma_up_vi2_cs_##name (GstVideoChromaResample *resample, \
723 gpointer lines[], gint width) \
724 { \
725 /* FIXME */ \
726 if (resample->h_resample) { \
727 resample->h_resample (resample, lines[0], width); \
728 } \
729 }
730
731 /* 2x horizontal downsampling with cositing
732 *
733 * a
734 * | +------ (b + 2*c + d + 2) >> 2
735 * v v
736 * O---O---O---
737 * x x x x x x
738 * a b c d e f
739 */
740 #define MAKE_DOWNSAMPLE_H2_CS(name,type) \
741 static void \
742 video_chroma_down_h2_cs_##name (GstVideoChromaResample *resample, \
743 gpointer pixels, gint width) \
744 { \
745 type *p = pixels; \
746 gint i; \
747 \
748 if (width < 2) \
749 return; \
750 \
751 PR(0) = FILT_3_1 (PR(0), PR(1)); \
752 PB(0) = FILT_3_1 (PB(0), PB(1)); \
753 \
754 for (i = 2; i < width - 2; i += 2) { \
755 PR(i) = FILT_1_2_1 (PR(i-1), PR(i), PR(i+1)); \
756 PB(i) = FILT_1_2_1 (PB(i-1), PB(i), PB(i+1)); \
757 } \
758 if (i < width) { \
759 PR(i) = FILT_1_3 (PR(i-1), PR(i)); \
760 PB(i) = FILT_1_3 (PB(i-1), PB(i)); \
761 } \
762 }
763 /* 2x vertical downsampling with cositing
764 *
765 * a x O--O--O- <---- a
766 * b x --------
767 * c x O--O--O- <---- (b + 2*c + d + 2) >> 2
768 * d x --------
769 * e x O--O--O-
770 * f x --------
771 */
772 #define MAKE_DOWNSAMPLE_V2_CS(name,type) \
773 static void \
774 video_chroma_down_v2_cs_##name (GstVideoChromaResample *resample, \
775 gpointer lines[], gint width) \
776 { \
777 /* FIXME */ \
778 if (resample->h_resample) { \
779 resample->h_resample (resample, lines[0], width); \
780 } \
781 }
782 /* 2x vertical downsampling interlaced with cositing
783 *
784 */
785 #define MAKE_DOWNSAMPLE_VI2_CS(name,type) \
786 static void \
787 video_chroma_down_vi2_cs_##name (GstVideoChromaResample *resample, \
788 gpointer lines[], gint width) \
789 { \
790 /* FIXME */ \
791 if (resample->h_resample) { \
792 resample->h_resample (resample, lines[0], width); \
793 } \
794 }
795
796 MAKE_UPSAMPLE_H2_CS (u16, guint16);
797 MAKE_UPSAMPLE_H2_CS (u8, guint8);
798 MAKE_UPSAMPLE_V2_CS (u16, guint16);
799 MAKE_UPSAMPLE_V2_CS (u8, guint8);
800 MAKE_UPSAMPLE_VI2_CS (u16, guint16);
801 MAKE_UPSAMPLE_VI2_CS (u8, guint8);
802 MAKE_DOWNSAMPLE_H2_CS (u16, guint16);
803 MAKE_DOWNSAMPLE_H2_CS (u8, guint8);
804 MAKE_DOWNSAMPLE_V2_CS (u16, guint16);
805 MAKE_DOWNSAMPLE_V2_CS (u8, guint8);
806 MAKE_DOWNSAMPLE_VI2_CS (u16, guint16);
807 MAKE_DOWNSAMPLE_VI2_CS (u8, guint8);
808
809 /* 4x horizontal upsampling with cositing
810 *
811 * +---------- (3*a + b + 2) >> 2
812 * a | +-------- ( a + b + 1) >> 1
813 * | | | +------ ( a + 3*b + 2) >> 2
814 * v v v v
815 * O-O-O-O-O-O-O-O
816 * x x
817 * a b
818 */
819 #define MAKE_UPSAMPLE_H4_CS(name,type) \
820 static void \
821 video_chroma_up_h4_cs_##name (GstVideoChromaResample *resample, \
822 gpointer pixels, gint width) \
823 { \
824 type *p = pixels; \
825 gint i; \
826 \
827 for (i = 0; i < width - 4; i += 4) { \
828 type tr0 = PR(i), tr1 = PR(i+4); \
829 type tb0 = PB(i), tb1 = PB(i+4); \
830 \
831 PR(i+1) = FILT_3_1 (tr0, tr1); \
832 PB(i+1) = FILT_3_1 (tb0, tb1); \
833 PR(i+2) = FILT_1_1 (tr0, tr1); \
834 PB(i+2) = FILT_1_1 (tb0, tb1); \
835 PR(i+3) = FILT_1_3 (tr0, tr1); \
836 PB(i+3) = FILT_1_3 (tb0, tb1); \
837 } \
838 }
839 /* 4x vertical upsampling with cositing
840 *
841 * a x O--O--O- <---- a
842 * O--O--O- <---- (3*a + b + 2) >> 2
843 * O--O--O- <---- ( a + b + 1) >> 1
844 * O--O--O- <---- ( a + 3*b + 2) >> 2
845 * b x O--O--O-
846 * O--O--O-
847 */
848 #define MAKE_UPSAMPLE_V4_CS(name,type) \
849 static void \
850 video_chroma_up_v4_cs_##name (GstVideoChromaResample *resample, \
851 gpointer lines[], gint width) \
852 { \
853 /* FIXME */ \
854 if (resample->h_resample) { \
855 resample->h_resample (resample, lines[0], width); \
856 } \
857 }
858 /* 4x vertical upsampling interlaced with cositing
859 *
860 */
861 #define MAKE_UPSAMPLE_VI4_CS(name,type) \
862 static void \
863 video_chroma_up_vi4_cs_##name (GstVideoChromaResample *resample, \
864 gpointer lines[], gint width) \
865 { \
866 /* FIXME */ \
867 if (resample->h_resample) { \
868 resample->h_resample (resample, lines[0], width); \
869 } \
870 }
871 /* 4x horizontal downsampling with cositing
872 *
873 * a
874 * | +------ (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
875 * v v
876 * O-------O-------
877 * x x x x x x x x
878 * a b c d e f g h
879 */
880 #define MAKE_DOWNSAMPLE_H4_CS(name,type) \
881 static void \
882 video_chroma_down_h4_cs_##name (GstVideoChromaResample *resample, \
883 gpointer pixels, gint width) \
884 { \
885 type *p = pixels; \
886 gint i; \
887 \
888 if (width < 4) \
889 return; \
890 \
891 PR(0) = FILT_10_3_2_1 (PR(0), PR(1), PR(2), PR(3)); \
892 PB(0) = FILT_10_3_2_1 (PB(0), PB(1), PB(2), PB(3)); \
893 \
894 for (i = 4; i < width - 4; i += 4) { \
895 PR(i) = FILT_1_2_3_4_3_2_1 (PR(i-3), PR(i-2), PR(i-1), PR(i), PR(i+1), PR(i+2), PR(i+3)); \
896 PB(i) = FILT_1_2_3_4_3_2_1 (PB(i-3), PB(i-2), PB(i-1), PB(i), PB(i+1), PB(i+2), PB(i+3)); \
897 } \
898 if (i < width) { \
899 PR(i) = FILT_1_2_3_10 (PR(i-3), PR(i-2), PR(i-1), PR(i)); \
900 PB(i) = FILT_1_2_3_10 (PB(i-3), PB(i-2), PB(i-1), PB(i)); \
901 } \
902 }
903 /* 4x vertical downsampling with cositing
904 *
905 * a x O--O--O- <---- a
906 * b x --------
907 * c x --------
908 * d x --------
909 * e x O--O--O- <---- (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
910 * f x --------
911 * g x --------
912 * h x --------
913 * i x O--O--O-
914 * j x --------
915 */
916 #define MAKE_DOWNSAMPLE_V4_CS(name,type) \
917 static void \
918 video_chroma_down_v4_cs_##name (GstVideoChromaResample *resample, \
919 gpointer lines[], gint width) \
920 { \
921 /* FIXME */ \
922 if (resample->h_resample) { \
923 resample->h_resample (resample, lines[0], width); \
924 } \
925 }
926 /* 4x vertical downsampling interlaced with cositing
927 *
928 */
929 #define MAKE_DOWNSAMPLE_VI4_CS(name,type) \
930 static void \
931 video_chroma_down_vi4_cs_##name (GstVideoChromaResample *resample, \
932 gpointer lines[], gint width) \
933 { \
934 /* FIXME */ \
935 if (resample->h_resample) { \
936 resample->h_resample (resample, lines[0], width); \
937 } \
938 }
939
940 MAKE_UPSAMPLE_H4_CS (u16, guint16);
941 MAKE_UPSAMPLE_H4_CS (u8, guint8);
942 MAKE_UPSAMPLE_V4_CS (u16, guint16);
943 MAKE_UPSAMPLE_V4_CS (u8, guint8);
944 MAKE_UPSAMPLE_VI4_CS (u16, guint16);
945 MAKE_UPSAMPLE_VI4_CS (u8, guint8);
946 MAKE_DOWNSAMPLE_H4_CS (u16, guint16);
947 MAKE_DOWNSAMPLE_H4_CS (u8, guint8);
948 MAKE_DOWNSAMPLE_V4_CS (u16, guint16);
949 MAKE_DOWNSAMPLE_V4_CS (u8, guint8);
950 MAKE_DOWNSAMPLE_VI4_CS (u16, guint16);
951 MAKE_DOWNSAMPLE_VI4_CS (u8, guint8);
952
953 typedef struct
954 {
955 void (*resample) (GstVideoChromaResample * resample, gpointer pixels,
956 gint width);
957 } HorizResampler;
958
959 static const HorizResampler h_resamplers[] = {
960 {NULL},
961 {video_chroma_up_h2_u8},
962 {video_chroma_down_h2_u8},
963 {video_chroma_up_h2_u16},
964 {video_chroma_down_h2_u16},
965 {video_chroma_up_h2_cs_u8},
966 {video_chroma_down_h2_cs_u8},
967 {video_chroma_up_h2_cs_u16},
968 {video_chroma_down_h2_cs_u16},
969 {video_chroma_up_h4_u8},
970 {video_chroma_down_h4_u8},
971 {video_chroma_up_h4_u16},
972 {video_chroma_down_h4_u16},
973 {video_chroma_up_h4_cs_u8},
974 {video_chroma_down_h4_cs_u8},
975 {video_chroma_up_h4_cs_u16},
976 {video_chroma_down_h4_cs_u16}
977 };
978
979 typedef struct
980 {
981 void (*resample) (GstVideoChromaResample * resample, gpointer lines[],
982 gint width);
983 guint n_lines;
984 gint offset;
985 } VertResampler;
986
987 static void
video_chroma_none(GstVideoChromaResample * resample,gpointer lines[],gint width)988 video_chroma_none (GstVideoChromaResample * resample,
989 gpointer lines[], gint width)
990 {
991 if (resample->h_resample)
992 resample->h_resample (resample, lines[0], width);
993 }
994
995 static const VertResampler v_resamplers[] = {
996 {video_chroma_none, 1, 0},
997 {video_chroma_up_v2_u8, 2, -1},
998 {video_chroma_down_v2_u8, 2, 0},
999 /* 16 bits */
1000 {video_chroma_up_v2_u16, 2, -1},
1001 {video_chroma_down_v2_u16, 2, 0},
1002 /* cosited */
1003 {video_chroma_up_v2_cs_u8, 1, 0}, /* IMPLEMENT ME */
1004 {video_chroma_down_v2_cs_u8, 1, 0}, /* IMPLEMENT ME */
1005 {video_chroma_up_v2_cs_u16, 1, 0}, /* IMPLEMENT ME */
1006 {video_chroma_down_v2_cs_u16, 1, 0}, /* IMPLEMENT ME */
1007 /* 4x */
1008 {video_chroma_up_v4_u8, 4, -2},
1009 {video_chroma_down_v4_u8, 4, 0},
1010 {video_chroma_up_v4_u16, 4, -2},
1011 {video_chroma_down_v4_u16, 4, 0},
1012 {video_chroma_up_v4_cs_u8, 1, 0}, /* IMPLEMENT ME */
1013 {video_chroma_down_v4_cs_u8, 1, 0}, /* IMPLEMENT ME */
1014 {video_chroma_up_v4_cs_u16, 1, 0}, /* IMPLEMENT ME */
1015 {video_chroma_down_v4_cs_u16, 1, 0}, /* IMPLEMENT ME */
1016 /* interlaced */
1017 {video_chroma_up_vi2_u8, 4, -2},
1018 {video_chroma_down_vi2_u8, 1, 0}, /* IMPLEMENT ME */
1019 {video_chroma_up_vi2_u16, 4, -2},
1020 {video_chroma_down_vi2_u16, 1, 0}, /* IMPLEMENT ME */
1021 {video_chroma_up_vi2_cs_u8, 1, 0}, /* IMPLEMENT ME */
1022 {video_chroma_down_vi2_cs_u8, 1, 0}, /* IMPLEMENT ME */
1023 {video_chroma_up_vi2_cs_u16, 1, 0}, /* IMPLEMENT ME */
1024 {video_chroma_down_vi2_cs_u16, 1, 0}, /* IMPLEMENT ME */
1025 {video_chroma_up_vi4_u8, 1, 0}, /* IMPLEMENT ME */
1026 {video_chroma_down_vi4_u8, 1, 0}, /* IMPLEMENT ME */
1027 {video_chroma_up_vi4_u16, 1, 0}, /* IMPLEMENT ME */
1028 {video_chroma_down_vi4_u16, 1, 0}, /* IMPLEMENT ME */
1029 {video_chroma_up_vi4_cs_u8, 1, 0}, /* IMPLEMENT ME */
1030 {video_chroma_down_vi4_cs_u8, 1, 0}, /* IMPLEMENT ME */
1031 {video_chroma_up_vi4_cs_u16, 1, 0}, /* IMPLEMENT ME */
1032 {video_chroma_down_vi4_cs_u16, 1, 0}, /* IMPLEMENT ME */
1033 };
1034
1035 /**
1036 * gst_video_chroma_resample_new: (skip)
1037 * @method: a #GstVideoChromaMethod
1038 * @site: a #GstVideoChromaSite
1039 * @flags: #GstVideoChromaFlags
1040 * @format: the #GstVideoFormat
1041 * @h_factor: horizontal resampling factor
1042 * @v_factor: vertical resampling factor
1043 *
1044 * Create a new resampler object for the given parameters. When @h_factor or
1045 * @v_factor is > 0, upsampling will be used, otherwise subsampling is
1046 * performed.
1047 *
1048 * Returns: a new #GstVideoChromaResample that should be freed with
1049 * gst_video_chroma_resample_free() after usage.
1050 */
1051 GstVideoChromaResample *
gst_video_chroma_resample_new(GstVideoChromaMethod method,GstVideoChromaSite site,GstVideoChromaFlags flags,GstVideoFormat format,gint h_factor,gint v_factor)1052 gst_video_chroma_resample_new (GstVideoChromaMethod method,
1053 GstVideoChromaSite site, GstVideoChromaFlags flags,
1054 GstVideoFormat format, gint h_factor, gint v_factor)
1055 {
1056 GstVideoChromaResample *result;
1057 guint cosite, h_index, v_index, bits;
1058
1059 /* no resampling */
1060 if (h_factor == 0 && v_factor == 0)
1061 return NULL;
1062
1063 if (format == GST_VIDEO_FORMAT_AYUV)
1064 bits = 8;
1065 else if (format == GST_VIDEO_FORMAT_AYUV64)
1066 bits = 16;
1067 else
1068 return NULL;
1069
1070 cosite = (site & GST_VIDEO_CHROMA_SITE_H_COSITED ? 1 : 0);
1071 if (h_factor == 0)
1072 h_index = 0;
1073 else
1074 h_index =
1075 ((ABS (h_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
1076 16 ? 2 : 0) + (h_factor < 0 ? 1 : 0) + 1;
1077
1078 GST_DEBUG ("h_resample %d, factor %d, cosite %d", h_index, h_factor, cosite);
1079
1080 cosite = (site & GST_VIDEO_CHROMA_SITE_V_COSITED ? 1 : 0);
1081 if (v_factor == 0)
1082 v_index = 0;
1083 else
1084 v_index =
1085 ((ABS (v_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
1086 16 ? 2 : 0) + (v_factor < 0 ? 1 : 0) + 1;
1087
1088 if (flags & GST_VIDEO_CHROMA_FLAG_INTERLACED)
1089 v_index += 16;
1090
1091 GST_DEBUG ("v_resample %d, factor %d, cosite %d", v_index, v_factor, cosite);
1092
1093 result = g_slice_new (GstVideoChromaResample);
1094 result->method = method;
1095 result->site = site;
1096 result->flags = flags;
1097 result->format = format;
1098 result->h_factor = h_factor;
1099 result->v_factor = v_factor;
1100 result->h_resample = h_resamplers[h_index].resample;
1101 result->v_resample = v_resamplers[v_index].resample;
1102 result->n_lines = v_resamplers[v_index].n_lines;
1103 result->offset = v_resamplers[v_index].offset;
1104
1105 GST_DEBUG ("resample %p, bits %d, n_lines %u, offset %d", result, bits,
1106 result->n_lines, result->offset);
1107
1108 return result;
1109 }
1110
1111 /**
1112 * gst_video_chroma_resample_get_info:
1113 * @resample: a #GstVideoChromaResample
1114 * @n_lines: the number of input lines
1115 * @offset: the first line
1116 *
1117 * The resampler must be fed @n_lines at a time. The first line should be
1118 * at @offset.
1119 */
1120 void
gst_video_chroma_resample_get_info(GstVideoChromaResample * resample,guint * n_lines,gint * offset)1121 gst_video_chroma_resample_get_info (GstVideoChromaResample * resample,
1122 guint * n_lines, gint * offset)
1123 {
1124 g_return_if_fail (resample != NULL);
1125
1126 if (n_lines)
1127 *n_lines = resample->n_lines;
1128 if (offset)
1129 *offset = resample->offset;
1130 }
1131
1132 /**
1133 * gst_video_chroma_resample_free:
1134 * @resample: a #GstVideoChromaResample
1135 *
1136 * Free @resample
1137 */
1138 void
gst_video_chroma_resample_free(GstVideoChromaResample * resample)1139 gst_video_chroma_resample_free (GstVideoChromaResample * resample)
1140 {
1141 g_return_if_fail (resample != NULL);
1142
1143 g_slice_free (GstVideoChromaResample, resample);
1144 }
1145
1146 /**
1147 * gst_video_chroma_resample:
1148 * @resample: a #GstVideoChromaResample
1149 * @lines: pixel lines
1150 * @width: the number of pixels on one line
1151 *
1152 * Perform resampling of @width chroma pixels in @lines.
1153 */
1154 void
gst_video_chroma_resample(GstVideoChromaResample * resample,gpointer lines[],gint width)1155 gst_video_chroma_resample (GstVideoChromaResample * resample,
1156 gpointer lines[], gint width)
1157 {
1158 g_return_if_fail (resample != NULL);
1159
1160 resample->v_resample (resample, lines, width);
1161 }
1162