2 * Copyright (C) 2013 Wim Taymans <wim.taymans@gmail.com>
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.
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.
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.
27 #include "video-orc.h"
28 #include "video-format.h"
29 #include <gst/video/video-enumtypes.h>
32 * SECTION:gstvideochroma
33 * @title: GstVideoChromaResample
34 * @short_description: Functions and utility object for operating on chroma video planes
36 * The functions gst_video_chroma_from_string() and gst_video_chroma_to_string() convert
37 * between #GstVideoChromaSite and string descriptions.
39 * #GstVideoChromaResample is a utility object for resampling chroma planes
40 * and converting between different chroma sampling sitings.
44 #ifndef GST_DISABLE_GST_DEBUG
45 #define GST_CAT_DEFAULT ensure_debug_category()
46 static GstDebugCategory *
47 ensure_debug_category (void)
49 static gsize cat_gonce = 0;
51 if (g_once_init_enter (&cat_gonce)) {
54 cat_done = (gsize) _gst_debug_category_new ("video-chroma", 0,
55 "video-chroma object");
57 g_once_init_leave (&cat_gonce, cat_done);
60 return (GstDebugCategory *) cat_gonce;
63 #define ensure_debug_category() /* NOOP */
64 #endif /* GST_DISABLE_GST_DEBUG */
69 GstVideoChromaSite site;
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},
81 * gst_video_chroma_from_string:
82 * @s: a chromasite string
84 * Convert @s to a #GstVideoChromaSite
86 * Deprecated: 1.20: Use gst_video_chroma_site_from_string() instead.
88 * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does
89 * not contain a valid chroma description.
92 gst_video_chroma_from_string (const gchar * s)
94 return gst_video_chroma_site_from_string (s);
98 * gst_video_chroma_site_from_string:
99 * @s: a chromasite string
101 * Convert @s to a #GstVideoChromaSite
103 * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does
104 * not contain a valid chroma-site description.
109 gst_video_chroma_site_from_string (const gchar * s)
114 GstVideoChromaSite ret = GST_VIDEO_CHROMA_SITE_UNKNOWN;
117 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
118 if (g_str_equal (chromasite[i].name, s))
119 return chromasite[i].site;
122 klass = (GFlagsClass *) g_type_class_ref (GST_TYPE_VIDEO_CHROMA_SITE);
123 split = g_strsplit (s, "+", 0);
124 for (iter = split; *iter; iter++) {
127 value = g_flags_get_value_by_nick (klass, *iter);
129 ret = GST_VIDEO_CHROMA_SITE_UNKNOWN;
137 g_type_class_unref (klass);
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;
149 * gst_video_chroma_to_string:
150 * @site: a #GstVideoChromaSite
152 * Converts @site to its string representation.
154 * Deprecated: 1.20: Use gst_video_chroma_site_to_string() instead.
156 * Returns: a string describing @site.
159 gst_video_chroma_to_string (GstVideoChromaSite site)
162 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
163 if (chromasite[i].site == site)
164 return chromasite[i].name;
170 * gst_video_chroma_site_to_string:
171 * @site: a #GstVideoChromaSite
173 * Converts @site to its string representation.
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
182 gst_video_chroma_site_to_string (GstVideoChromaSite site)
189 /* return null string for GST_VIDEO_CHROMA_SITE_UNKNOWN */
193 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
194 if (chromasite[i].site == site)
195 return g_strdup (chromasite[i].name);
198 /* Doesn't make sense */
199 if ((site & GST_VIDEO_CHROMA_SITE_NONE) != 0 &&
200 site != GST_VIDEO_CHROMA_SITE_NONE)
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))) {
209 g_string_append (str, "+");
211 g_string_append (str, value->value_nick);
212 site &= ~value->value;
214 g_type_class_unref (klass);
216 /* This means given chroma-site has unknown value */
218 return g_string_free (str, TRUE);
220 return g_string_free (str, FALSE);
223 struct _GstVideoChromaResample
225 GstVideoChromaMethod method;
226 GstVideoChromaSite site;
227 GstVideoChromaFlags flags;
228 GstVideoFormat format;
229 gint h_factor, v_factor;
232 void (*h_resample) (GstVideoChromaResample * resample, gpointer pixels,
234 void (*v_resample) (GstVideoChromaResample * resample, gpointer lines[],
238 #define PR(i) (p[2 + 4 * (i)])
239 #define PB(i) (p[3 + 4 * (i)])
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)])
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
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
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
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
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
267 /* 2x horizontal upsampling without cositing
270 * | +------ (3*a + b + 2) >> 2
271 * | | +---- ( a + 3*b + 2) >> 2
277 #define MAKE_UPSAMPLE_H2(name,type) \
279 video_chroma_up_h2_##name (GstVideoChromaResample *resample, \
280 gpointer pixels, gint width) \
289 for (i = 1; i < width - 1; i += 2) { \
290 tr0 = tr1, tr1 = PR(i+1); \
291 tb0 = tb1, tb1 = PB(i+1); \
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); \
300 /* 2x vertical upsampling without cositing
304 * O--O--O- <---- (3*a + b + 2) >> 2
305 * O--O--O- <-----( a + 3*b + 2) >> 2
309 #define MAKE_UPSAMPLE_V2(name,type) \
311 video_chroma_up_v2_##name (GstVideoChromaResample *resample, \
312 gpointer lines[], gint width) \
314 type *l0 = lines[0]; \
315 type *l1 = lines[1]; \
317 if (resample->h_resample) { \
318 resample->h_resample (resample, l0, width); \
320 resample->h_resample (resample, l1, width); \
325 video_orc_chroma_up_v2_##name (d0, d1, l0, l1, width); \
328 /* 2x vertical upsampling interlaced without cositing
332 * O--O--O--------------- <--- a
334 * --------------O--O--O- <--- c
335 * O--O--O--------------- <--- (5*a + 3*b + 4) >> 3
337 * --------------O--O--O- <--- (7*c + d + 4) >> 3
338 * O--O--O--------------- <--- ( a + 7*b + 4) >> 3
340 * --------------O--O--O- <--- (3*c + 5*d + 4) >> 3
341 * O--O--O---------------
343 * --------------O--O--O-
345 #define MAKE_UPSAMPLE_VI2(name,type) \
347 video_chroma_up_vi2_##name (GstVideoChromaResample *resample, \
348 gpointer lines[], gint width) \
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; \
358 if (resample->h_resample) { \
360 resample->h_resample (resample, l0, width); \
361 resample->h_resample (resample, l1, width); \
364 resample->h_resample (resample, l2, width); \
365 resample->h_resample (resample, l3, width); \
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); \
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); \
387 /* 2x horizontal downsampling without cositing
389 * +------ (a + b+ 1) >> 1
396 #define MAKE_DOWNSAMPLE_H2_ORC(name,type) \
398 video_chroma_down_h2_##name (GstVideoChromaResample *resample, \
399 gpointer pixels, gint width) \
404 video_orc_chroma_down_h2_##name (d, p, width / 2); \
407 #define MAKE_DOWNSAMPLE_H2(name,type) \
409 video_chroma_down_h2_##name (GstVideoChromaResample *resample, \
410 gpointer pixels, gint width) \
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); \
419 PR(i) = FILT_1_1 (tr0, tr1); \
420 PB(i) = FILT_1_1 (tb0, tb1); \
423 /* 2x vertical downsampling without cositing
426 * O O O <---- (a + b + 1) >> 1
432 #define MAKE_DOWNSAMPLE_V2(name,type) \
434 video_chroma_down_v2_##name (GstVideoChromaResample *resample, \
435 gpointer lines[], gint width) \
437 type *l0 = lines[0]; \
438 type *l1 = lines[1]; \
442 video_orc_chroma_down_v2_##name (d0, l0, l1, width); \
445 if (resample->h_resample) \
446 resample->h_resample (resample, l0, width); \
448 /* 2x vertical downsampling interlaced without cositing
452 * a x--x--x---------------
454 * b --------------x--x--x-
455 * c x--x--x---------------
457 * d --------------x--x--x-
459 #define MAKE_DOWNSAMPLE_VI2(name,type) \
461 video_chroma_down_vi2_##name (GstVideoChromaResample *resample, \
462 gpointer lines[], gint width) \
465 if (resample->h_resample) \
466 resample->h_resample (resample, lines[0], width); \
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);
482 /* 4x horizontal upsampling without cositing
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
493 #define MAKE_UPSAMPLE_H4(name,type) \
495 video_chroma_up_h4_##name (GstVideoChromaResample *resample, \
496 gpointer pixels, gint width) \
505 for (i = 2; i < width - 3; i += 4) { \
506 tr0 = tr1, tr1 = PR(i+2); \
507 tb0 = tb1, tb1 = PB(i+2); \
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); \
520 /* 4x vertical upsampling without cositing
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
533 #define MAKE_UPSAMPLE_V4(name,type) \
535 video_chroma_up_v4_##name (GstVideoChromaResample *resample, \
536 gpointer lines[], gint width) \
539 type *l0 = lines[0]; \
540 type *l1 = lines[1]; \
541 type *l2 = lines[2]; \
542 type *l3 = lines[3]; \
546 if (resample->h_resample) { \
548 resample->h_resample (resample, l0, width); \
549 resample->h_resample (resample, l1, width); \
552 resample->h_resample (resample, l2, width); \
553 resample->h_resample (resample, l3, width); \
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); \
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); \
572 /* 4x vertical upsampling interlaced without cositing
575 #define MAKE_UPSAMPLE_VI4(name,type) \
577 video_chroma_up_vi4_##name (GstVideoChromaResample *resample, \
578 gpointer lines[], gint width) \
581 if (resample->h_resample) { \
582 resample->h_resample (resample, lines[0], width); \
586 /* 4x horizontal downsampling without cositing
588 * +------ (a + 3*b + 3*c + d + 4) >> 3
595 #define MAKE_DOWNSAMPLE_H4(name,type) \
597 video_chroma_down_h4_##name (GstVideoChromaResample *resample, \
598 gpointer pixels, gint width) \
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); \
607 PR(i) = FILT_1_3_3_1 (tr0, tr1, tr2, tr3); \
608 PB(i) = FILT_1_3_3_1 (tb0, tb1, tb2, tb3); \
612 /* 4x vertical downsampling without cositing
616 * O O O <---- (a + 3*b + 3*c + d + 4) >> 4
625 #define MAKE_DOWNSAMPLE_V4(name,type) \
627 video_chroma_down_v4_##name (GstVideoChromaResample *resample, \
628 gpointer lines[], gint width) \
630 type *l0 = lines[0]; \
631 type *l1 = lines[1]; \
632 type *l2 = lines[2]; \
633 type *l3 = lines[3]; \
636 video_orc_chroma_down_v4_##name(d, l0, l1, l2, l3, width); \
638 if (resample->h_resample) \
639 resample->h_resample (resample, l0, width); \
641 /* 4x vertical downsampling interlaced without cositing
644 #define MAKE_DOWNSAMPLE_VI4(name,type) \
646 video_chroma_down_vi4_##name (GstVideoChromaResample *resample, \
647 gpointer lines[], gint width) \
650 if (resample->h_resample) { \
651 resample->h_resample (resample, lines[0], width); \
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);
668 /* 2x horizontal upsampling with cositing
670 * a +------ (a + b + 1) >> 1
677 #define MAKE_UPSAMPLE_H2_CS_ORC(name,type) \
679 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \
680 gpointer pixels, gint width) \
683 /* ORC version is slower */ \
684 video_orc_chroma_up_h2_cs_##name (p, p, p, width-1); \
687 #define MAKE_UPSAMPLE_H2_CS(name,type) \
689 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \
690 gpointer pixels, gint width) \
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)); \
700 /* 2x vertical upsampling with cositing
702 * a x O--O--O- <---- a
703 * O--O--O- <---- (a + b + 1) >> 1
707 #define MAKE_UPSAMPLE_V2_CS(name,type) \
709 video_chroma_up_v2_cs_##name (GstVideoChromaResample *resample, \
710 gpointer lines[], gint width) \
713 if (resample->h_resample) { \
714 resample->h_resample (resample, lines[0], width); \
717 /* 2x vertical upsampling interlaced with cositing
720 #define MAKE_UPSAMPLE_VI2_CS(name,type) \
722 video_chroma_up_vi2_cs_##name (GstVideoChromaResample *resample, \
723 gpointer lines[], gint width) \
726 if (resample->h_resample) { \
727 resample->h_resample (resample, lines[0], width); \
731 /* 2x horizontal downsampling with cositing
734 * | +------ (b + 2*c + d + 2) >> 2
740 #define MAKE_DOWNSAMPLE_H2_CS(name,type) \
742 video_chroma_down_h2_cs_##name (GstVideoChromaResample *resample, \
743 gpointer pixels, gint width) \
751 PR(0) = FILT_3_1 (PR(0), PR(1)); \
752 PB(0) = FILT_3_1 (PB(0), PB(1)); \
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)); \
759 PR(i) = FILT_1_3 (PR(i-1), PR(i)); \
760 PB(i) = FILT_1_3 (PB(i-1), PB(i)); \
763 /* 2x vertical downsampling with cositing
765 * a x O--O--O- <---- a
767 * c x O--O--O- <---- (b + 2*c + d + 2) >> 2
772 #define MAKE_DOWNSAMPLE_V2_CS(name,type) \
774 video_chroma_down_v2_cs_##name (GstVideoChromaResample *resample, \
775 gpointer lines[], gint width) \
778 if (resample->h_resample) { \
779 resample->h_resample (resample, lines[0], width); \
782 /* 2x vertical downsampling interlaced with cositing
785 #define MAKE_DOWNSAMPLE_VI2_CS(name,type) \
787 video_chroma_down_vi2_cs_##name (GstVideoChromaResample *resample, \
788 gpointer lines[], gint width) \
791 if (resample->h_resample) { \
792 resample->h_resample (resample, lines[0], width); \
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);
809 /* 4x horizontal upsampling with cositing
811 * +---------- (3*a + b + 2) >> 2
812 * a | +-------- ( a + b + 1) >> 1
813 * | | | +------ ( a + 3*b + 2) >> 2
819 #define MAKE_UPSAMPLE_H4_CS(name,type) \
821 video_chroma_up_h4_cs_##name (GstVideoChromaResample *resample, \
822 gpointer pixels, gint width) \
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); \
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); \
839 /* 4x vertical upsampling with cositing
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
848 #define MAKE_UPSAMPLE_V4_CS(name,type) \
850 video_chroma_up_v4_cs_##name (GstVideoChromaResample *resample, \
851 gpointer lines[], gint width) \
854 if (resample->h_resample) { \
855 resample->h_resample (resample, lines[0], width); \
858 /* 4x vertical upsampling interlaced with cositing
861 #define MAKE_UPSAMPLE_VI4_CS(name,type) \
863 video_chroma_up_vi4_cs_##name (GstVideoChromaResample *resample, \
864 gpointer lines[], gint width) \
867 if (resample->h_resample) { \
868 resample->h_resample (resample, lines[0], width); \
871 /* 4x horizontal downsampling with cositing
874 * | +------ (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
880 #define MAKE_DOWNSAMPLE_H4_CS(name,type) \
882 video_chroma_down_h4_cs_##name (GstVideoChromaResample *resample, \
883 gpointer pixels, gint width) \
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)); \
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)); \
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)); \
903 /* 4x vertical downsampling with cositing
905 * a x O--O--O- <---- a
909 * e x O--O--O- <---- (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
916 #define MAKE_DOWNSAMPLE_V4_CS(name,type) \
918 video_chroma_down_v4_cs_##name (GstVideoChromaResample *resample, \
919 gpointer lines[], gint width) \
922 if (resample->h_resample) { \
923 resample->h_resample (resample, lines[0], width); \
926 /* 4x vertical downsampling interlaced with cositing
929 #define MAKE_DOWNSAMPLE_VI4_CS(name,type) \
931 video_chroma_down_vi4_cs_##name (GstVideoChromaResample *resample, \
932 gpointer lines[], gint width) \
935 if (resample->h_resample) { \
936 resample->h_resample (resample, lines[0], width); \
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);
955 void (*resample) (GstVideoChromaResample * resample, gpointer pixels,
959 static const HorizResampler h_resamplers[] = {
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}
981 void (*resample) (GstVideoChromaResample * resample, gpointer lines[],
988 video_chroma_none (GstVideoChromaResample * resample,
989 gpointer lines[], gint width)
991 if (resample->h_resample)
992 resample->h_resample (resample, lines[0], width);
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},
1000 {video_chroma_up_v2_u16, 2, -1},
1001 {video_chroma_down_v2_u16, 2, 0},
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 */
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 */
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 */
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
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
1048 * Returns: a new #GstVideoChromaResample that should be freed with
1049 * gst_video_chroma_resample_free() after usage.
1051 GstVideoChromaResample *
1052 gst_video_chroma_resample_new (GstVideoChromaMethod method,
1053 GstVideoChromaSite site, GstVideoChromaFlags flags,
1054 GstVideoFormat format, gint h_factor, gint v_factor)
1056 GstVideoChromaResample *result;
1057 guint cosite, h_index, v_index, bits;
1060 if (h_factor == 0 && v_factor == 0)
1063 if (format == GST_VIDEO_FORMAT_AYUV)
1065 else if (format == GST_VIDEO_FORMAT_AYUV64)
1070 cosite = (site & GST_VIDEO_CHROMA_SITE_H_COSITED ? 1 : 0);
1075 ((ABS (h_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
1076 16 ? 2 : 0) + (h_factor < 0 ? 1 : 0) + 1;
1078 GST_DEBUG ("h_resample %d, factor %d, cosite %d", h_index, h_factor, cosite);
1080 cosite = (site & GST_VIDEO_CHROMA_SITE_V_COSITED ? 1 : 0);
1085 ((ABS (v_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
1086 16 ? 2 : 0) + (v_factor < 0 ? 1 : 0) + 1;
1088 if (flags & GST_VIDEO_CHROMA_FLAG_INTERLACED)
1091 GST_DEBUG ("v_resample %d, factor %d, cosite %d", v_index, v_factor, cosite);
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;
1105 GST_DEBUG ("resample %p, bits %d, n_lines %u, offset %d", result, bits,
1106 result->n_lines, result->offset);
1112 * gst_video_chroma_resample_get_info:
1113 * @resample: a #GstVideoChromaResample
1114 * @n_lines: the number of input lines
1115 * @offset: the first line
1117 * The resampler must be fed @n_lines at a time. The first line should be
1121 gst_video_chroma_resample_get_info (GstVideoChromaResample * resample,
1122 guint * n_lines, gint * offset)
1124 g_return_if_fail (resample != NULL);
1127 *n_lines = resample->n_lines;
1129 *offset = resample->offset;
1133 * gst_video_chroma_resample_free:
1134 * @resample: a #GstVideoChromaResample
1139 gst_video_chroma_resample_free (GstVideoChromaResample * resample)
1141 g_return_if_fail (resample != NULL);
1143 g_slice_free (GstVideoChromaResample, resample);
1147 * gst_video_chroma_resample:
1148 * @resample: a #GstVideoChromaResample
1149 * @lines: pixel lines
1150 * @width: the number of pixels on one line
1152 * Perform resampling of @width chroma pixels in @lines.
1155 gst_video_chroma_resample (GstVideoChromaResample * resample,
1156 gpointer lines[], gint width)
1158 g_return_if_fail (resample != NULL);
1160 resample->v_resample (resample, lines, width);